push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / ntdll / thread.c
blobc3706512f10dce6db3d04cf26b20ee13d126fbc9
1 /*
2 * NT threads support
4 * Copyright 1996, 2003 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_MMAN_H
28 #include <sys/mman.h>
29 #endif
30 #ifdef HAVE_SYS_TIMES_H
31 #include <sys/times.h>
32 #endif
34 #define NONAMELESSUNION
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "winternl.h"
38 #include "wine/library.h"
39 #include "wine/server.h"
40 #include "wine/debug.h"
41 #include "ntdll_misc.h"
42 #include "ddk/wdm.h"
43 #include "wine/exception.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(thread);
46 WINE_DECLARE_DEBUG_CHANNEL(relay);
48 struct _KUSER_SHARED_DATA *user_shared_data = NULL;
50 PUNHANDLED_EXCEPTION_FILTER unhandled_exception_filter = NULL;
52 /* info passed to a starting thread */
53 struct startup_info
55 TEB *teb;
56 PRTL_THREAD_START_ROUTINE entry_point;
57 void *entry_arg;
60 static PEB_LDR_DATA ldr;
61 static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
62 static WCHAR current_dir[MAX_NT_PATH_LENGTH];
63 static RTL_BITMAP tls_bitmap;
64 static RTL_BITMAP tls_expansion_bitmap;
65 static RTL_BITMAP fls_bitmap;
66 static LIST_ENTRY tls_links;
67 static int nb_threads = 1;
69 static RTL_CRITICAL_SECTION ldt_section;
70 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
72 0, 0, &ldt_section,
73 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
74 0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") }
76 static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 };
77 static sigset_t ldt_sigset;
79 /***********************************************************************
80 * locking for LDT routines
82 static void ldt_lock(void)
84 sigset_t sigset;
86 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
87 RtlEnterCriticalSection( &ldt_section );
88 if (ldt_section.RecursionCount == 1) ldt_sigset = sigset;
91 static void ldt_unlock(void)
93 if (ldt_section.RecursionCount == 1)
95 sigset_t sigset = ldt_sigset;
96 RtlLeaveCriticalSection( &ldt_section );
97 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
99 else RtlLeaveCriticalSection( &ldt_section );
103 /***********************************************************************
104 * get_unicode_string
106 * Copy a unicode string from the startup info.
108 static inline void get_unicode_string( UNICODE_STRING *str, WCHAR **src, WCHAR **dst, UINT len )
110 str->Buffer = *dst;
111 str->Length = len;
112 str->MaximumLength = len + sizeof(WCHAR);
113 memcpy( str->Buffer, *src, len );
114 str->Buffer[len / sizeof(WCHAR)] = 0;
115 *src += len / sizeof(WCHAR);
116 *dst += len / sizeof(WCHAR) + 1;
119 /***********************************************************************
120 * init_user_process_params
122 * Fill the RTL_USER_PROCESS_PARAMETERS structure from the server.
124 static NTSTATUS init_user_process_params( SIZE_T data_size, HANDLE *exe_file )
126 void *ptr;
127 WCHAR *src, *dst;
128 SIZE_T info_size, env_size, size, alloc_size;
129 NTSTATUS status;
130 startup_info_t *info;
131 RTL_USER_PROCESS_PARAMETERS *params = NULL;
133 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, data_size )))
134 return STATUS_NO_MEMORY;
136 SERVER_START_REQ( get_startup_info )
138 wine_server_set_reply( req, info, data_size );
139 if (!(status = wine_server_call( req )))
141 data_size = wine_server_reply_size( reply );
142 info_size = reply->info_size;
143 env_size = data_size - info_size;
144 *exe_file = wine_server_ptr_handle( reply->exe_file );
147 SERVER_END_REQ;
148 if (status != STATUS_SUCCESS) goto done;
150 size = sizeof(*params);
151 size += MAX_NT_PATH_LENGTH * sizeof(WCHAR);
152 size += info->dllpath_len + sizeof(WCHAR);
153 size += info->imagepath_len + sizeof(WCHAR);
154 size += info->cmdline_len + sizeof(WCHAR);
155 size += info->title_len + sizeof(WCHAR);
156 size += info->desktop_len + sizeof(WCHAR);
157 size += info->shellinfo_len + sizeof(WCHAR);
158 size += info->runtime_len + sizeof(WCHAR);
160 alloc_size = size;
161 status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &alloc_size,
162 MEM_COMMIT, PAGE_READWRITE );
163 if (status != STATUS_SUCCESS) goto done;
165 NtCurrentTeb()->Peb->ProcessParameters = params;
166 params->AllocationSize = alloc_size;
167 params->Size = size;
168 params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
169 params->DebugFlags = info->debug_flags;
170 params->ConsoleHandle = wine_server_ptr_handle( info->console );
171 params->ConsoleFlags = info->console_flags;
172 params->hStdInput = wine_server_ptr_handle( info->hstdin );
173 params->hStdOutput = wine_server_ptr_handle( info->hstdout );
174 params->hStdError = wine_server_ptr_handle( info->hstderr );
175 params->dwX = info->x;
176 params->dwY = info->y;
177 params->dwXSize = info->xsize;
178 params->dwYSize = info->ysize;
179 params->dwXCountChars = info->xchars;
180 params->dwYCountChars = info->ychars;
181 params->dwFillAttribute = info->attribute;
182 params->dwFlags = info->flags;
183 params->wShowWindow = info->show;
185 src = (WCHAR *)(info + 1);
186 dst = (WCHAR *)(params + 1);
188 /* current directory needs more space */
189 get_unicode_string( &params->CurrentDirectory.DosPath, &src, &dst, info->curdir_len );
190 params->CurrentDirectory.DosPath.MaximumLength = MAX_NT_PATH_LENGTH * sizeof(WCHAR);
191 dst = (WCHAR *)(params + 1) + MAX_NT_PATH_LENGTH;
193 get_unicode_string( &params->DllPath, &src, &dst, info->dllpath_len );
194 get_unicode_string( &params->ImagePathName, &src, &dst, info->imagepath_len );
195 get_unicode_string( &params->CommandLine, &src, &dst, info->cmdline_len );
196 get_unicode_string( &params->WindowTitle, &src, &dst, info->title_len );
197 get_unicode_string( &params->Desktop, &src, &dst, info->desktop_len );
198 get_unicode_string( &params->ShellInfo, &src, &dst, info->shellinfo_len );
200 /* runtime info isn't a real string */
201 params->RuntimeInfo.Buffer = dst;
202 params->RuntimeInfo.Length = params->RuntimeInfo.MaximumLength = info->runtime_len;
203 memcpy( dst, src, info->runtime_len );
205 /* environment needs to be a separate memory block */
206 ptr = NULL;
207 alloc_size = max( 1, env_size );
208 status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &alloc_size,
209 MEM_COMMIT, PAGE_READWRITE );
210 if (status != STATUS_SUCCESS) goto done;
211 memcpy( ptr, (char *)info + info_size, env_size );
212 params->Environment = ptr;
214 done:
215 RtlFreeHeap( GetProcessHeap(), 0, info );
216 return status;
219 /***********************************************************************
220 * get_global_flag
222 * This is called before the process heap is created,
223 * but after the connection to the server is established.
224 * No windows heap allocation is permitted.
226 static DWORD get_global_flag(void)
228 static const WCHAR sessionman_keyW[] = {'M','a','c','h','i','n','e','\\',
229 'S','y','s','t','e','m','\\',
230 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
231 'C','o','n','t','r','o','l','\\',
232 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
233 static const WCHAR global_flagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
234 OBJECT_ATTRIBUTES attr;
235 UNICODE_STRING nameW, valueW;
236 HANDLE hkey;
237 char tmp[32];
238 DWORD count;
239 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
240 NTSTATUS status;
242 attr.Length = sizeof(attr);
243 attr.RootDirectory = 0;
244 attr.ObjectName = &nameW;
245 attr.Attributes = 0;
246 attr.SecurityDescriptor = NULL;
247 attr.SecurityQualityOfService = NULL;
248 RtlInitUnicodeString( &nameW, sessionman_keyW );
250 status = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr );
251 if (status != STATUS_SUCCESS)
252 return 0;
254 RtlInitUnicodeString( &valueW, global_flagW );
255 status = NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count );
256 if (status != STATUS_SUCCESS)
257 return 0;
259 /* Some documents say this can be a string, so handle either type */
260 if (info->Type == REG_DWORD)
261 return *(DWORD *)info->Data;
262 if (info->Type == REG_SZ)
263 return strtol((char *)info->Data, NULL, 16);
264 return 0;
267 /***********************************************************************
268 * thread_init
270 * Setup the initial thread.
272 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
274 HANDLE thread_init(void)
276 PEB *peb;
277 TEB *teb;
278 void *addr;
279 SIZE_T size, info_size;
280 HANDLE exe_file = 0;
281 LARGE_INTEGER now;
282 struct ntdll_thread_data *thread_data;
283 static struct debug_info debug_info; /* debug info for initial thread */
285 virtual_init();
287 /* reserve space for shared user data */
289 addr = (void *)0x7ffe0000;
290 size = 0x10000;
291 NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
292 user_shared_data = addr;
294 /* allocate and initialize the PEB */
296 addr = NULL;
297 size = sizeof(*peb);
298 NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size,
299 MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE );
300 peb = addr;
302 peb->ProcessParameters = &params;
303 peb->TlsBitmap = &tls_bitmap;
304 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
305 peb->FlsBitmap = &fls_bitmap;
306 peb->LdrData = &ldr;
307 params.CurrentDirectory.DosPath.Buffer = current_dir;
308 params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir);
309 params.wShowWindow = 1; /* SW_SHOWNORMAL */
310 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
311 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
312 sizeof(peb->TlsExpansionBitmapBits) * 8 );
313 RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
314 InitializeListHead( &peb->FlsListHead );
315 InitializeListHead( &ldr.InLoadOrderModuleList );
316 InitializeListHead( &ldr.InMemoryOrderModuleList );
317 InitializeListHead( &ldr.InInitializationOrderModuleList );
318 InitializeListHead( &tls_links );
320 /* allocate and initialize the initial TEB */
322 signal_alloc_thread( &teb );
323 teb->Peb = peb;
324 teb->Tib.StackBase = (void *)~0UL;
325 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
326 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
328 thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
329 thread_data->request_fd = -1;
330 thread_data->reply_fd = -1;
331 thread_data->wait_fd[0] = -1;
332 thread_data->wait_fd[1] = -1;
333 thread_data->debug_info = &debug_info;
334 InsertHeadList( &tls_links, &teb->TlsLinks );
336 signal_init_thread( teb );
337 virtual_init_threading();
339 debug_info.str_pos = debug_info.strings;
340 debug_info.out_pos = debug_info.output;
341 debug_init();
343 /* setup the server connection */
344 server_init_process();
345 info_size = server_init_thread( peb );
347 /* retrieve the global flags settings from the registry */
348 peb->NtGlobalFlag = get_global_flag();
350 /* create the process heap */
351 if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
353 MESSAGE( "wine: failed to create the process heap\n" );
354 exit(1);
357 /* allocate user parameters */
358 if (info_size)
360 init_user_process_params( info_size, &exe_file );
362 else
364 /* This is wine specific: we have no parent (we're started from unix)
365 * so, create a simple console with bare handles to unix stdio
367 wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, &params.hStdInput );
368 wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdOutput );
369 wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdError );
372 /* initialize LDT locking */
373 wine_ldt_init_locking( ldt_lock, ldt_unlock );
375 /* initialize time values in user_shared_data */
376 NtQuerySystemTime( &now );
377 user_shared_data->SystemTime.LowPart = now.u.LowPart;
378 user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
379 user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
380 user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
381 user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
382 user_shared_data->TickCountMultiplier = 1 << 24;
384 fill_cpu_info();
386 return exe_file;
390 /***********************************************************************
391 * terminate_thread
393 void terminate_thread( int status )
395 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
396 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
398 close( ntdll_get_thread_data()->wait_fd[0] );
399 close( ntdll_get_thread_data()->wait_fd[1] );
400 close( ntdll_get_thread_data()->reply_fd );
401 close( ntdll_get_thread_data()->request_fd );
402 pthread_exit( UIntToPtr(status) );
406 /***********************************************************************
407 * exit_thread
409 void exit_thread( int status )
411 static void *prev_teb;
412 TEB *teb;
414 if (status) /* send the exit code to the server (0 is already the default) */
416 SERVER_START_REQ( terminate_thread )
418 req->handle = wine_server_obj_handle( GetCurrentThread() );
419 req->exit_code = status;
420 wine_server_call( req );
422 SERVER_END_REQ;
425 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1)
427 LdrShutdownProcess();
428 exit( status );
431 LdrShutdownThread();
432 RtlAcquirePebLock();
433 RemoveEntryList( &NtCurrentTeb()->TlsLinks );
434 RtlReleasePebLock();
435 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots );
436 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
438 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
440 if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() )))
442 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
444 pthread_join( thread_data->pthread_id, NULL );
445 signal_free_thread( teb );
448 close( ntdll_get_thread_data()->wait_fd[0] );
449 close( ntdll_get_thread_data()->wait_fd[1] );
450 close( ntdll_get_thread_data()->reply_fd );
451 close( ntdll_get_thread_data()->request_fd );
452 pthread_exit( UIntToPtr(status) );
456 /***********************************************************************
457 * start_thread
459 * Startup routine for a newly created thread.
461 static void start_thread( struct startup_info *info )
463 TEB *teb = info->teb;
464 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
465 PRTL_THREAD_START_ROUTINE func = info->entry_point;
466 void *arg = info->entry_arg;
467 struct debug_info debug_info;
469 debug_info.str_pos = debug_info.strings;
470 debug_info.out_pos = debug_info.output;
471 thread_data->debug_info = &debug_info;
472 thread_data->pthread_id = pthread_self();
474 signal_init_thread( teb );
475 server_init_thread( func );
476 pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
478 RtlAcquirePebLock();
479 InsertHeadList( &tls_links, &teb->TlsLinks );
480 RtlReleasePebLock();
482 MODULE_DllThreadAttach( NULL );
484 if (TRACE_ON(relay))
485 DPRINTF( "%04x:Starting thread proc %p (arg=%p)\n", GetCurrentThreadId(), func, arg );
487 call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
491 /***********************************************************************
492 * RtlCreateUserThread (NTDLL.@)
494 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
495 BOOLEAN suspended, PVOID stack_addr,
496 SIZE_T stack_reserve, SIZE_T stack_commit,
497 PRTL_THREAD_START_ROUTINE start, void *param,
498 HANDLE *handle_ptr, CLIENT_ID *id )
500 sigset_t sigset;
501 pthread_t pthread_id;
502 pthread_attr_t attr;
503 struct ntdll_thread_data *thread_data;
504 struct startup_info *info = NULL;
505 HANDLE handle = 0;
506 TEB *teb = NULL;
507 DWORD tid = 0;
508 int request_pipe[2];
509 NTSTATUS status;
511 if (process != NtCurrentProcess())
513 apc_call_t call;
514 apc_result_t result;
516 memset( &call, 0, sizeof(call) );
518 call.create_thread.type = APC_CREATE_THREAD;
519 call.create_thread.func = wine_server_client_ptr( start );
520 call.create_thread.arg = wine_server_client_ptr( param );
521 call.create_thread.reserve = stack_reserve;
522 call.create_thread.commit = stack_commit;
523 call.create_thread.suspend = suspended;
524 status = NTDLL_queue_process_apc( process, &call, &result );
525 if (status != STATUS_SUCCESS) return status;
527 if (result.create_thread.status == STATUS_SUCCESS)
529 if (id) id->UniqueThread = ULongToHandle(result.create_thread.tid);
530 if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle );
531 else NtClose( wine_server_ptr_handle( result.create_thread.handle ));
533 return result.create_thread.status;
536 if (server_pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
537 wine_server_send_fd( request_pipe[0] );
539 SERVER_START_REQ( new_thread )
541 req->access = THREAD_ALL_ACCESS;
542 req->attributes = 0; /* FIXME */
543 req->suspend = suspended;
544 req->request_fd = request_pipe[0];
545 if (!(status = wine_server_call( req )))
547 handle = wine_server_ptr_handle( reply->handle );
548 tid = reply->tid;
550 close( request_pipe[0] );
552 SERVER_END_REQ;
554 if (status)
556 close( request_pipe[1] );
557 return status;
560 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
562 if ((status = signal_alloc_thread( &teb ))) goto error;
564 teb->Peb = NtCurrentTeb()->Peb;
565 teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
566 teb->ClientId.UniqueThread = ULongToHandle(tid);
567 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
568 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
570 info = (struct startup_info *)(teb + 1);
571 info->teb = teb;
572 info->entry_point = start;
573 info->entry_arg = param;
575 thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
576 thread_data->request_fd = request_pipe[1];
577 thread_data->reply_fd = -1;
578 thread_data->wait_fd[0] = -1;
579 thread_data->wait_fd[1] = -1;
581 if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit ))) goto error;
583 pthread_attr_init( &attr );
584 pthread_attr_setstack( &attr, teb->DeallocationStack,
585 (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
586 pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
587 interlocked_xchg_add( &nb_threads, 1 );
588 if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, info ))
590 interlocked_xchg_add( &nb_threads, -1 );
591 pthread_attr_destroy( &attr );
592 status = STATUS_NO_MEMORY;
593 goto error;
595 pthread_attr_destroy( &attr );
596 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
598 if (id) id->UniqueThread = ULongToHandle(tid);
599 if (handle_ptr) *handle_ptr = handle;
600 else NtClose( handle );
602 return STATUS_SUCCESS;
604 error:
605 if (teb) signal_free_thread( teb );
606 if (handle) NtClose( handle );
607 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
608 close( request_pipe[1] );
609 return status;
613 /***********************************************************************
614 * NtOpenThread (NTDLL.@)
615 * ZwOpenThread (NTDLL.@)
617 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
618 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
620 NTSTATUS ret;
622 SERVER_START_REQ( open_thread )
624 req->tid = HandleToULong(id->UniqueThread);
625 req->access = access;
626 req->attributes = attr ? attr->Attributes : 0;
627 ret = wine_server_call( req );
628 *handle = wine_server_ptr_handle( reply->handle );
630 SERVER_END_REQ;
631 return ret;
635 /******************************************************************************
636 * NtSuspendThread (NTDLL.@)
637 * ZwSuspendThread (NTDLL.@)
639 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
641 NTSTATUS ret;
643 SERVER_START_REQ( suspend_thread )
645 req->handle = wine_server_obj_handle( handle );
646 if (!(ret = wine_server_call( req ))) *count = reply->count;
648 SERVER_END_REQ;
649 return ret;
653 /******************************************************************************
654 * NtResumeThread (NTDLL.@)
655 * ZwResumeThread (NTDLL.@)
657 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
659 NTSTATUS ret;
661 SERVER_START_REQ( resume_thread )
663 req->handle = wine_server_obj_handle( handle );
664 if (!(ret = wine_server_call( req ))) *count = reply->count;
666 SERVER_END_REQ;
667 return ret;
671 /******************************************************************************
672 * NtAlertResumeThread (NTDLL.@)
673 * ZwAlertResumeThread (NTDLL.@)
675 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
677 FIXME( "stub: should alert thread %p\n", handle );
678 return NtResumeThread( handle, count );
682 /******************************************************************************
683 * NtAlertThread (NTDLL.@)
684 * ZwAlertThread (NTDLL.@)
686 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
688 FIXME( "stub: %p\n", handle );
689 return STATUS_NOT_IMPLEMENTED;
693 /******************************************************************************
694 * NtTerminateThread (NTDLL.@)
695 * ZwTerminateThread (NTDLL.@)
697 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
699 NTSTATUS ret;
700 BOOL self;
702 SERVER_START_REQ( terminate_thread )
704 req->handle = wine_server_obj_handle( handle );
705 req->exit_code = exit_code;
706 ret = wine_server_call( req );
707 self = !ret && reply->self;
709 SERVER_END_REQ;
711 if (self) abort_thread( exit_code );
712 return ret;
716 /******************************************************************************
717 * NtQueueApcThread (NTDLL.@)
719 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
720 ULONG_PTR arg2, ULONG_PTR arg3 )
722 NTSTATUS ret;
723 SERVER_START_REQ( queue_apc )
725 req->handle = wine_server_obj_handle( handle );
726 if (func)
728 req->call.type = APC_USER;
729 req->call.user.func = wine_server_client_ptr( func );
730 req->call.user.args[0] = arg1;
731 req->call.user.args[1] = arg2;
732 req->call.user.args[2] = arg3;
734 else req->call.type = APC_NONE; /* wake up only */
735 ret = wine_server_call( req );
737 SERVER_END_REQ;
738 return ret;
742 /***********************************************************************
743 * NtSetContextThread (NTDLL.@)
744 * ZwSetContextThread (NTDLL.@)
746 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
748 NTSTATUS ret;
749 DWORD dummy, i;
750 BOOL self = FALSE;
752 #ifdef __i386__
753 /* on i386 debug registers always require a server call */
754 self = (handle == GetCurrentThread());
755 if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
757 self = (ntdll_get_thread_data()->dr0 == context->Dr0 &&
758 ntdll_get_thread_data()->dr1 == context->Dr1 &&
759 ntdll_get_thread_data()->dr2 == context->Dr2 &&
760 ntdll_get_thread_data()->dr3 == context->Dr3 &&
761 ntdll_get_thread_data()->dr6 == context->Dr6 &&
762 ntdll_get_thread_data()->dr7 == context->Dr7);
764 #endif
766 if (!self)
768 context_t server_context;
770 context_to_server( &server_context, context );
772 SERVER_START_REQ( set_thread_context )
774 req->handle = wine_server_obj_handle( handle );
775 req->suspend = 0;
776 wine_server_add_data( req, &server_context, sizeof(server_context) );
777 ret = wine_server_call( req );
778 self = reply->self;
780 SERVER_END_REQ;
782 if (ret == STATUS_PENDING)
784 if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
786 for (i = 0; i < 100; i++)
788 SERVER_START_REQ( set_thread_context )
790 req->handle = wine_server_obj_handle( handle );
791 req->suspend = 0;
792 wine_server_add_data( req, &server_context, sizeof(server_context) );
793 ret = wine_server_call( req );
795 SERVER_END_REQ;
796 if (ret == STATUS_PENDING)
798 LARGE_INTEGER timeout;
799 timeout.QuadPart = -10000;
800 NtDelayExecution( FALSE, &timeout );
802 else break;
804 NtResumeThread( handle, &dummy );
806 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
809 if (ret) return ret;
812 if (self) set_cpu_context( context );
813 return STATUS_SUCCESS;
817 /* convert CPU-specific flags to generic server flags */
818 static inline unsigned int get_server_context_flags( DWORD flags )
820 unsigned int ret = 0;
822 flags &= 0x3f; /* mask CPU id flags */
823 if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
824 if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
825 #ifdef CONTEXT_SEGMENTS
826 if (flags & CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
827 #endif
828 #ifdef CONTEXT_FLOATING_POINT
829 if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
830 #endif
831 #ifdef CONTEXT_DEBUG_REGISTERS
832 if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
833 #endif
834 #ifdef CONTEXT_EXTENDED_REGISTERS
835 if (flags & CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
836 #endif
837 return ret;
840 /***********************************************************************
841 * NtGetContextThread (NTDLL.@)
842 * ZwGetContextThread (NTDLL.@)
844 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
846 NTSTATUS ret;
847 DWORD dummy, i;
848 DWORD needed_flags = context->ContextFlags;
849 BOOL self = (handle == GetCurrentThread());
851 #ifdef __i386__
852 /* on i386 debug registers always require a server call */
853 if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) self = FALSE;
854 #endif
856 if (!self)
858 unsigned int server_flags = get_server_context_flags( context->ContextFlags );
859 context_t server_context;
861 SERVER_START_REQ( get_thread_context )
863 req->handle = wine_server_obj_handle( handle );
864 req->flags = server_flags;
865 req->suspend = 0;
866 wine_server_set_reply( req, &server_context, sizeof(server_context) );
867 ret = wine_server_call( req );
868 self = reply->self;
870 SERVER_END_REQ;
872 if (ret == STATUS_PENDING)
874 if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
876 for (i = 0; i < 100; i++)
878 SERVER_START_REQ( get_thread_context )
880 req->handle = wine_server_obj_handle( handle );
881 req->flags = server_flags;
882 req->suspend = 0;
883 wine_server_set_reply( req, &server_context, sizeof(server_context) );
884 ret = wine_server_call( req );
886 SERVER_END_REQ;
887 if (ret == STATUS_PENDING)
889 LARGE_INTEGER timeout;
890 timeout.QuadPart = -10000;
891 NtDelayExecution( FALSE, &timeout );
893 else break;
895 NtResumeThread( handle, &dummy );
897 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
899 if (!ret) ret = context_from_server( context, &server_context );
900 if (ret) return ret;
901 needed_flags &= ~context->ContextFlags;
904 if (self)
906 if (needed_flags)
908 CONTEXT ctx;
909 RtlCaptureContext( &ctx );
910 copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
911 context->ContextFlags |= ctx.ContextFlags & needed_flags;
913 #ifdef __i386__
914 /* update the cached version of the debug registers */
915 if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
917 ntdll_get_thread_data()->dr0 = context->Dr0;
918 ntdll_get_thread_data()->dr1 = context->Dr1;
919 ntdll_get_thread_data()->dr2 = context->Dr2;
920 ntdll_get_thread_data()->dr3 = context->Dr3;
921 ntdll_get_thread_data()->dr6 = context->Dr6;
922 ntdll_get_thread_data()->dr7 = context->Dr7;
924 #endif
926 return STATUS_SUCCESS;
930 /******************************************************************************
931 * NtQueryInformationThread (NTDLL.@)
932 * ZwQueryInformationThread (NTDLL.@)
934 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
935 void *data, ULONG length, ULONG *ret_len )
937 NTSTATUS status;
939 switch(class)
941 case ThreadBasicInformation:
943 THREAD_BASIC_INFORMATION info;
944 const ULONG_PTR affinity_mask = ((ULONG_PTR)1 << NtCurrentTeb()->Peb->NumberOfProcessors) - 1;
946 SERVER_START_REQ( get_thread_info )
948 req->handle = wine_server_obj_handle( handle );
949 req->tid_in = 0;
950 if (!(status = wine_server_call( req )))
952 info.ExitStatus = reply->exit_code;
953 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
954 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
955 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
956 info.AffinityMask = reply->affinity & affinity_mask;
957 info.Priority = reply->priority;
958 info.BasePriority = reply->priority; /* FIXME */
961 SERVER_END_REQ;
962 if (status == STATUS_SUCCESS)
964 if (data) memcpy( data, &info, min( length, sizeof(info) ));
965 if (ret_len) *ret_len = min( length, sizeof(info) );
968 return status;
969 case ThreadAffinityMask:
971 const ULONG_PTR affinity_mask = ((ULONG_PTR)1 << NtCurrentTeb()->Peb->NumberOfProcessors) - 1;
972 ULONG_PTR affinity = 0;
974 SERVER_START_REQ( get_thread_info )
976 req->handle = wine_server_obj_handle( handle );
977 req->tid_in = 0;
978 if (!(status = wine_server_call( req )))
979 affinity = reply->affinity & affinity_mask;
981 SERVER_END_REQ;
982 if (status == STATUS_SUCCESS)
984 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
985 if (ret_len) *ret_len = min( length, sizeof(affinity) );
988 return status;
989 case ThreadTimes:
991 KERNEL_USER_TIMES kusrt;
992 /* We need to do a server call to get the creation time or exit time */
993 /* This works on any thread */
994 SERVER_START_REQ( get_thread_info )
996 req->handle = wine_server_obj_handle( handle );
997 req->tid_in = 0;
998 status = wine_server_call( req );
999 if (status == STATUS_SUCCESS)
1001 kusrt.CreateTime.QuadPart = reply->creation_time;
1002 kusrt.ExitTime.QuadPart = reply->exit_time;
1005 SERVER_END_REQ;
1006 if (status == STATUS_SUCCESS)
1008 /* We call times(2) for kernel time or user time */
1009 /* We can only (portably) do this for the current thread */
1010 if (handle == GetCurrentThread())
1012 struct tms time_buf;
1013 long clocks_per_sec = sysconf(_SC_CLK_TCK);
1015 times(&time_buf);
1016 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
1017 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
1019 else
1021 static BOOL reported = FALSE;
1023 kusrt.KernelTime.QuadPart = 0;
1024 kusrt.UserTime.QuadPart = 0;
1025 if (reported)
1026 TRACE("Cannot get kerneltime or usertime of other threads\n");
1027 else
1029 FIXME("Cannot get kerneltime or usertime of other threads\n");
1030 reported = TRUE;
1033 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1034 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1037 return status;
1038 case ThreadDescriptorTableEntry:
1040 #ifdef __i386__
1041 THREAD_DESCRIPTOR_INFORMATION* tdi = data;
1042 if (length < sizeof(*tdi))
1043 status = STATUS_INFO_LENGTH_MISMATCH;
1044 else if (!(tdi->Selector & 4)) /* GDT selector */
1046 unsigned sel = tdi->Selector & ~3; /* ignore RPL */
1047 status = STATUS_SUCCESS;
1048 if (!sel) /* null selector */
1049 memset( &tdi->Entry, 0, sizeof(tdi->Entry) );
1050 else
1052 tdi->Entry.BaseLow = 0;
1053 tdi->Entry.HighWord.Bits.BaseMid = 0;
1054 tdi->Entry.HighWord.Bits.BaseHi = 0;
1055 tdi->Entry.LimitLow = 0xffff;
1056 tdi->Entry.HighWord.Bits.LimitHi = 0xf;
1057 tdi->Entry.HighWord.Bits.Dpl = 3;
1058 tdi->Entry.HighWord.Bits.Sys = 0;
1059 tdi->Entry.HighWord.Bits.Pres = 1;
1060 tdi->Entry.HighWord.Bits.Granularity = 1;
1061 tdi->Entry.HighWord.Bits.Default_Big = 1;
1062 tdi->Entry.HighWord.Bits.Type = 0x12;
1063 /* it has to be one of the system GDT selectors */
1064 if (sel != (wine_get_ds() & ~3) && sel != (wine_get_ss() & ~3))
1066 if (sel == (wine_get_cs() & ~3))
1067 tdi->Entry.HighWord.Bits.Type |= 8; /* code segment */
1068 else status = STATUS_ACCESS_DENIED;
1072 else
1074 SERVER_START_REQ( get_selector_entry )
1076 req->handle = wine_server_obj_handle( handle );
1077 req->entry = tdi->Selector >> 3;
1078 status = wine_server_call( req );
1079 if (!status)
1081 if (!(reply->flags & WINE_LDT_FLAGS_ALLOCATED))
1082 status = STATUS_ACCESS_VIOLATION;
1083 else
1085 wine_ldt_set_base ( &tdi->Entry, (void *)reply->base );
1086 wine_ldt_set_limit( &tdi->Entry, reply->limit );
1087 wine_ldt_set_flags( &tdi->Entry, reply->flags );
1091 SERVER_END_REQ;
1093 if (status == STATUS_SUCCESS && ret_len)
1094 /* yes, that's a bit strange, but it's the way it is */
1095 *ret_len = sizeof(LDT_ENTRY);
1096 #else
1097 status = STATUS_NOT_IMPLEMENTED;
1098 #endif
1099 return status;
1101 case ThreadAmILastThread:
1103 SERVER_START_REQ(get_thread_info)
1105 req->handle = wine_server_obj_handle( handle );
1106 req->tid_in = 0;
1107 status = wine_server_call( req );
1108 if (status == STATUS_SUCCESS)
1110 BOOLEAN last = reply->last;
1111 if (data) memcpy( data, &last, min( length, sizeof(last) ));
1112 if (ret_len) *ret_len = min( length, sizeof(last) );
1115 SERVER_END_REQ;
1116 return status;
1118 case ThreadPriority:
1119 case ThreadBasePriority:
1120 case ThreadImpersonationToken:
1121 case ThreadEnableAlignmentFaultFixup:
1122 case ThreadEventPair_Reusable:
1123 case ThreadQuerySetWin32StartAddress:
1124 case ThreadZeroTlsCell:
1125 case ThreadPerformanceCount:
1126 case ThreadIdealProcessor:
1127 case ThreadPriorityBoost:
1128 case ThreadSetTlsArrayAddress:
1129 case ThreadIsIoPending:
1130 default:
1131 FIXME( "info class %d not supported yet\n", class );
1132 return STATUS_NOT_IMPLEMENTED;
1137 /******************************************************************************
1138 * NtSetInformationThread (NTDLL.@)
1139 * ZwSetInformationThread (NTDLL.@)
1141 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
1142 LPCVOID data, ULONG length )
1144 NTSTATUS status;
1145 switch(class)
1147 case ThreadZeroTlsCell:
1148 if (handle == GetCurrentThread())
1150 LIST_ENTRY *entry;
1151 DWORD index;
1153 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1154 index = *(const DWORD *)data;
1155 if (index < TLS_MINIMUM_AVAILABLE)
1157 RtlAcquirePebLock();
1158 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1160 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1161 teb->TlsSlots[index] = 0;
1163 RtlReleasePebLock();
1165 else
1167 index -= TLS_MINIMUM_AVAILABLE;
1168 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
1169 return STATUS_INVALID_PARAMETER;
1170 RtlAcquirePebLock();
1171 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1173 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1174 if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
1176 RtlReleasePebLock();
1178 return STATUS_SUCCESS;
1180 FIXME( "ZeroTlsCell not supported on other threads\n" );
1181 return STATUS_NOT_IMPLEMENTED;
1183 case ThreadImpersonationToken:
1185 const HANDLE *phToken = data;
1186 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1187 TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
1188 SERVER_START_REQ( set_thread_info )
1190 req->handle = wine_server_obj_handle( handle );
1191 req->token = wine_server_obj_handle( *phToken );
1192 req->mask = SET_THREAD_INFO_TOKEN;
1193 status = wine_server_call( req );
1195 SERVER_END_REQ;
1197 return status;
1198 case ThreadBasePriority:
1200 const DWORD *pprio = data;
1201 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1202 SERVER_START_REQ( set_thread_info )
1204 req->handle = wine_server_obj_handle( handle );
1205 req->priority = *pprio;
1206 req->mask = SET_THREAD_INFO_PRIORITY;
1207 status = wine_server_call( req );
1209 SERVER_END_REQ;
1211 return status;
1212 case ThreadAffinityMask:
1214 const ULONG_PTR affinity_mask = ((ULONG_PTR)1 << NtCurrentTeb()->Peb->NumberOfProcessors) - 1;
1215 const ULONG_PTR *paff = data;
1216 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
1217 if (*paff & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1218 if (!*paff) return STATUS_INVALID_PARAMETER;
1219 SERVER_START_REQ( set_thread_info )
1221 req->handle = wine_server_obj_handle( handle );
1222 req->affinity = *paff;
1223 req->mask = SET_THREAD_INFO_AFFINITY;
1224 status = wine_server_call( req );
1226 SERVER_END_REQ;
1228 return status;
1229 case ThreadHideFromDebugger:
1230 /* pretend the call succeeded to satisfy some code protectors */
1231 return STATUS_SUCCESS;
1233 case ThreadBasicInformation:
1234 case ThreadTimes:
1235 case ThreadPriority:
1236 case ThreadDescriptorTableEntry:
1237 case ThreadEnableAlignmentFaultFixup:
1238 case ThreadEventPair_Reusable:
1239 case ThreadQuerySetWin32StartAddress:
1240 case ThreadPerformanceCount:
1241 case ThreadAmILastThread:
1242 case ThreadIdealProcessor:
1243 case ThreadPriorityBoost:
1244 case ThreadSetTlsArrayAddress:
1245 case ThreadIsIoPending:
1246 default:
1247 FIXME( "info class %d not supported yet\n", class );
1248 return STATUS_NOT_IMPLEMENTED;