TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / ntdll / thread.c
blob62277a12000abccd5a54ea41c908995e0452f8d6
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
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
35 #endif
36 #include <errno.h>
38 #define NONAMELESSUNION
39 #include "ntstatus.h"
40 #define WIN32_NO_STATUS
41 #include "winternl.h"
42 #include "wine/library.h"
43 #include "wine/server.h"
44 #include "wine/debug.h"
45 #include "ntdll_misc.h"
46 #include "ddk/wdm.h"
47 #include "wine/exception.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(thread);
50 WINE_DECLARE_DEBUG_CHANNEL(relay);
52 struct _KUSER_SHARED_DATA *user_shared_data = NULL;
54 PUNHANDLED_EXCEPTION_FILTER unhandled_exception_filter = NULL;
56 /* info passed to a starting thread */
57 struct startup_info
59 TEB *teb;
60 PRTL_THREAD_START_ROUTINE entry_point;
61 void *entry_arg;
62 BOOL native_thread;
65 static PEB *peb;
66 static PEB_LDR_DATA ldr;
67 static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
68 static WCHAR current_dir[MAX_NT_PATH_LENGTH];
69 static RTL_BITMAP tls_bitmap;
70 static RTL_BITMAP tls_expansion_bitmap;
71 static RTL_BITMAP fls_bitmap;
72 static int nb_threads = 1;
74 /***********************************************************************
75 * get_unicode_string
77 * Copy a unicode string from the startup info.
79 static inline void get_unicode_string( UNICODE_STRING *str, WCHAR **src, WCHAR **dst, UINT len )
81 str->Buffer = *dst;
82 str->Length = len;
83 str->MaximumLength = len + sizeof(WCHAR);
84 memcpy( str->Buffer, *src, len );
85 str->Buffer[len / sizeof(WCHAR)] = 0;
86 *src += len / sizeof(WCHAR);
87 *dst += len / sizeof(WCHAR) + 1;
90 /***********************************************************************
91 * init_user_process_params
93 * Fill the RTL_USER_PROCESS_PARAMETERS structure from the server.
95 static NTSTATUS init_user_process_params( SIZE_T data_size, HANDLE *exe_file )
97 void *ptr;
98 WCHAR *src, *dst;
99 SIZE_T info_size, env_size, size, alloc_size;
100 NTSTATUS status;
101 startup_info_t *info;
102 RTL_USER_PROCESS_PARAMETERS *params = NULL;
104 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, data_size )))
105 return STATUS_NO_MEMORY;
107 SERVER_START_REQ( get_startup_info )
109 wine_server_set_reply( req, info, data_size );
110 if (!(status = wine_server_call( req )))
112 data_size = wine_server_reply_size( reply );
113 info_size = reply->info_size;
114 env_size = data_size - info_size;
115 *exe_file = wine_server_ptr_handle( reply->exe_file );
118 SERVER_END_REQ;
119 if (status != STATUS_SUCCESS) goto done;
121 size = sizeof(*params);
122 size += MAX_NT_PATH_LENGTH * sizeof(WCHAR);
123 size += info->dllpath_len + sizeof(WCHAR);
124 size += info->imagepath_len + sizeof(WCHAR);
125 size += info->cmdline_len + sizeof(WCHAR);
126 size += info->title_len + sizeof(WCHAR);
127 size += info->desktop_len + sizeof(WCHAR);
128 size += info->shellinfo_len + sizeof(WCHAR);
129 size += info->runtime_len + sizeof(WCHAR);
131 alloc_size = size;
132 status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &alloc_size,
133 MEM_COMMIT, PAGE_READWRITE );
134 if (status != STATUS_SUCCESS) goto done;
136 NtCurrentTeb()->Peb->ProcessParameters = params;
137 params->AllocationSize = alloc_size;
138 params->Size = size;
139 params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
140 params->DebugFlags = info->debug_flags;
141 params->ConsoleHandle = wine_server_ptr_handle( info->console );
142 params->ConsoleFlags = info->console_flags;
143 params->hStdInput = wine_server_ptr_handle( info->hstdin );
144 params->hStdOutput = wine_server_ptr_handle( info->hstdout );
145 params->hStdError = wine_server_ptr_handle( info->hstderr );
146 params->dwX = info->x;
147 params->dwY = info->y;
148 params->dwXSize = info->xsize;
149 params->dwYSize = info->ysize;
150 params->dwXCountChars = info->xchars;
151 params->dwYCountChars = info->ychars;
152 params->dwFillAttribute = info->attribute;
153 params->dwFlags = info->flags;
154 params->wShowWindow = info->show;
156 src = (WCHAR *)(info + 1);
157 dst = (WCHAR *)(params + 1);
159 /* current directory needs more space */
160 get_unicode_string( &params->CurrentDirectory.DosPath, &src, &dst, info->curdir_len );
161 params->CurrentDirectory.DosPath.MaximumLength = MAX_NT_PATH_LENGTH * sizeof(WCHAR);
162 dst = (WCHAR *)(params + 1) + MAX_NT_PATH_LENGTH;
164 get_unicode_string( &params->DllPath, &src, &dst, info->dllpath_len );
165 get_unicode_string( &params->ImagePathName, &src, &dst, info->imagepath_len );
166 get_unicode_string( &params->CommandLine, &src, &dst, info->cmdline_len );
167 get_unicode_string( &params->WindowTitle, &src, &dst, info->title_len );
168 get_unicode_string( &params->Desktop, &src, &dst, info->desktop_len );
169 get_unicode_string( &params->ShellInfo, &src, &dst, info->shellinfo_len );
171 /* runtime info isn't a real string */
172 params->RuntimeInfo.Buffer = dst;
173 params->RuntimeInfo.Length = params->RuntimeInfo.MaximumLength = info->runtime_len;
174 memcpy( dst, src, info->runtime_len );
176 /* environment needs to be a separate memory block */
177 ptr = NULL;
178 alloc_size = max( 1, env_size );
179 status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &alloc_size,
180 MEM_COMMIT, PAGE_READWRITE );
181 if (status != STATUS_SUCCESS) goto done;
182 memcpy( ptr, (char *)info + info_size, env_size );
183 params->Environment = ptr;
185 done:
186 RtlFreeHeap( GetProcessHeap(), 0, info );
187 return status;
190 #ifdef __APPLE__
191 #include <mach/mach.h>
192 #include <mach/mach_error.h>
194 static ULONG64 get_dyld_image_info_addr(void)
196 ULONG64 ret = 0;
197 #ifdef TASK_DYLD_INFO
198 struct task_dyld_info dyld_info;
199 mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
200 if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &size) == KERN_SUCCESS)
201 ret = dyld_info.all_image_info_addr;
202 #endif
203 return ret;
205 #endif /* __APPLE__ */
207 #ifdef __linux__
208 #include <sys/resource.h>
210 extern typeof(pthread_create) *__glob_pthread_create, *call_pthread_create;
211 extern typeof(pthread_join) *__glob_pthread_join, *call_pthread_join;
212 extern typeof(pthread_detach) *__glob_pthread_detach, *call_pthread_detach;
214 static typeof(pthread_create) __hook_pthread_create;
215 static typeof(pthread_join) __hook_pthread_join;
216 static typeof(pthread_detach) __hook_pthread_detach;
218 static pthread_mutex_t thread_lock;
220 static void thread_wrap_init(void)
222 pthread_mutexattr_t attr;
223 pthread_mutexattr_init(&attr);
224 pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
225 pthread_mutex_init(&thread_lock, &attr);
226 pthread_mutexattr_destroy(&attr);
228 call_pthread_create = __hook_pthread_create;
229 call_pthread_join = __hook_pthread_join;
230 call_pthread_detach = __hook_pthread_detach;
233 static TEB *dead_teb;
234 static struct list active_list = LIST_INIT(active_list);
236 static void take_thread_lock(void)
238 int ret = pthread_mutex_lock(&thread_lock);
239 if (ret == EOWNERDEAD)
240 pthread_mutex_consistent(&thread_lock);
243 static void detach_thread_unlock(TEB *own_teb)
245 struct ntdll_thread_data *thread_data;
246 TEB *teb = dead_teb;
248 dead_teb = own_teb;
250 pthread_mutex_unlock(&thread_lock);
251 if (!teb)
252 return;
254 thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
255 __glob_pthread_join(thread_data->pthread_id, NULL);
256 signal_free_thread(teb);
259 static void reap_thread(TEB *teb)
261 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
262 take_thread_lock();
263 if (thread_data->detached)
264 detach_thread_unlock(teb);
265 else {
267 * Do not unlock, wait until the thread is thoroughly dead.
268 * This prevents a race condition where detach is called
269 * after the thread has not finished dying yet.
274 #else
275 #define __glob_pthread_create pthread_create
276 #define __glob_pthread_join pthread_join
277 #define __glob_pthread_detach pthread_detach
278 #define thread_wrap_init()
279 #endif
281 /***********************************************************************
282 * thread_init
284 * Setup the initial thread.
286 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
288 HANDLE thread_init(void)
290 TEB *teb;
291 void *addr;
292 SIZE_T size, info_size;
293 HANDLE exe_file = 0;
294 LARGE_INTEGER now;
295 NTSTATUS status;
296 struct ntdll_thread_data *thread_data;
297 static struct debug_info debug_info; /* debug info for initial thread */
298 #ifdef __APPLE__
299 ULONG64 dyld_image_info;
300 #endif
302 thread_wrap_init();
303 virtual_init();
305 /* reserve space for shared user data */
307 addr = (void *)0x7ffe0000;
308 size = 0x10000;
309 status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size,
310 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
311 if (status)
313 MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
314 exit(1);
316 user_shared_data = addr;
318 /* allocate and initialize the PEB */
320 addr = NULL;
321 size = sizeof(*peb);
322 NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size,
323 MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE );
324 peb = addr;
326 peb->ProcessParameters = &params;
327 peb->TlsBitmap = &tls_bitmap;
328 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
329 peb->FlsBitmap = &fls_bitmap;
330 peb->LdrData = &ldr;
331 params.CurrentDirectory.DosPath.Buffer = current_dir;
332 params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir);
333 params.wShowWindow = 1; /* SW_SHOWNORMAL */
334 ldr.Length = sizeof(ldr);
335 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
336 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
337 sizeof(peb->TlsExpansionBitmapBits) * 8 );
338 RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
339 RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
340 RtlSetBits( peb->FlsBitmap, 0, 1 );
341 InitializeListHead( &peb->FlsListHead );
342 InitializeListHead( &ldr.InLoadOrderModuleList );
343 InitializeListHead( &ldr.InMemoryOrderModuleList );
344 InitializeListHead( &ldr.InInitializationOrderModuleList );
345 #ifdef __APPLE__
346 dyld_image_info = get_dyld_image_info_addr();
347 #ifdef __LP64__
348 #ifdef WORDS_BIGENDIAN
349 peb->Reserved[1] = dyld_image_info & 0xFFFFFFFF;
350 peb->Reserved[0] = dyld_image_info >> 32;
351 #else
352 peb->Reserved[0] = dyld_image_info & 0xFFFFFFFF;
353 peb->Reserved[1] = dyld_image_info >> 32;
354 #endif
355 #else
356 peb->Reserved[0] = dyld_image_info & 0xFFFFFFFF;
357 #endif
358 #endif
361 * Starting with Vista, the first user to log on has session id 1.
362 * Session id 0 is for processes that don't interact with the user (like services).
364 peb->SessionId = 1;
366 /* allocate and initialize the initial TEB */
368 signal_alloc_thread( &teb );
369 teb->Peb = peb;
370 teb->Tib.StackBase = (void *)~0UL;
371 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
372 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
374 thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
375 thread_data->request_fd = -1;
376 thread_data->reply_fd = -1;
377 thread_data->wait_fd[0] = -1;
378 thread_data->wait_fd[1] = -1;
379 thread_data->debug_info = &debug_info;
380 InsertHeadList( &tls_links, &teb->TlsLinks );
382 signal_init_thread( teb );
383 virtual_init_threading();
385 debug_info.str_pos = debug_info.strings;
386 debug_info.out_pos = debug_info.output;
387 debug_init();
389 /* setup the server connection */
390 server_init_process();
391 info_size = server_init_thread( peb );
393 /* create the process heap */
394 if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
396 MESSAGE( "wine: failed to create the process heap\n" );
397 exit(1);
400 /* allocate user parameters */
401 if (info_size)
403 init_user_process_params( info_size, &exe_file );
405 else
407 if (isatty(0) || isatty(1) || isatty(2))
408 params.ConsoleHandle = (HANDLE)2; /* see kernel32/kernel_private.h */
409 if (!isatty(0))
410 wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, &params.hStdInput );
411 if (!isatty(1))
412 wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdOutput );
413 if (!isatty(2))
414 wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdError );
417 /* initialize time values in user_shared_data */
418 NtQuerySystemTime( &now );
419 user_shared_data->SystemTime.LowPart = now.u.LowPart;
420 user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
421 user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
422 user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
423 user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
424 user_shared_data->TickCountMultiplier = 1 << 24;
426 fill_cpu_info();
428 NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );
430 return exe_file;
434 /***********************************************************************
435 * terminate_thread
437 void terminate_thread( int status )
439 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
440 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
442 close( ntdll_get_thread_data()->wait_fd[0] );
443 close( ntdll_get_thread_data()->wait_fd[1] );
444 close( ntdll_get_thread_data()->reply_fd );
445 close( ntdll_get_thread_data()->request_fd );
446 pthread_exit( UIntToPtr(status) );
449 static void exit_thread_common( int status )
451 #ifndef __linux__
452 static void *prev_teb;
453 TEB *teb;
454 #endif
456 if (status) /* send the exit code to the server (0 is already the default) */
458 SERVER_START_REQ( terminate_thread )
460 req->handle = wine_server_obj_handle( GetCurrentThread() );
461 req->exit_code = status;
462 wine_server_call( req );
464 SERVER_END_REQ;
467 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1)
469 LdrShutdownProcess();
470 exit( status );
473 LdrShutdownThread();
474 RtlFreeThreadActivationContextStack();
476 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
478 #ifndef __linux__
479 if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() )))
481 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
483 if (thread_data->pthread_id)
485 __glob_pthread_join( thread_data->pthread_id, NULL );
486 signal_free_thread( teb );
489 #else
490 reap_thread(NtCurrentTeb());
491 #endif
493 close( ntdll_get_thread_data()->wait_fd[0] );
494 close( ntdll_get_thread_data()->wait_fd[1] );
495 close( ntdll_get_thread_data()->reply_fd );
496 close( ntdll_get_thread_data()->request_fd );
499 void exit_thread( int status )
501 exit_thread_common(status);
502 pthread_exit( UIntToPtr(status) );
505 #ifdef __linux__
507 struct unix_arg {
508 void *(*start)(void *);
509 void *arg;
512 /* dummy used for comparison */
513 static DWORD native_unix_start;
515 static void call_native_cleanup(void *arg)
517 exit_thread_common(0);
520 static int
521 __hook_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
522 void *(*start_routine) (void *), void *parm)
524 NTSTATUS ret;
525 pthread_t tid;
526 size_t stack = 0, stack_commit;
527 static size_t default_stack;
528 struct unix_arg arg;
529 IMAGE_NT_HEADERS *nt;
531 arg.start = start_routine;
532 arg.arg = parm;
534 if (!default_stack) {
535 struct rlimit limit;
537 if (getrlimit(RLIMIT_STACK, &limit) == 0 &&
538 limit.rlim_cur != RLIM_INFINITY)
539 default_stack = limit.rlim_cur;
540 else
541 default_stack = 2 * 1024 * 1024;
544 if (!thread)
545 thread = &tid;
547 TRACE("Overriding thread creation!\n");
548 if (attr) {
549 static int once;
550 if (!once++)
551 FIXME("most thread attributes ignored!\n");
552 else
553 WARN("most thread attributes ignored!\n");
555 pthread_attr_getstacksize(attr, &stack);
558 if (!stack)
559 stack = default_stack;
561 nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
562 stack_commit = nt->OptionalHeader.SizeOfStackCommit;
564 if (!stack_commit || stack_commit > stack)
565 stack_commit = stack;
567 ret = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, stack, stack_commit, (void*)&native_unix_start, &arg, NULL, (void*)thread );
568 if (ret != STATUS_SUCCESS)
569 FIXME("ret: %08x\n", ret);
570 switch (ret) {
571 case STATUS_SUCCESS:
572 TRACE("created thread %lx for %p/%p\n", *thread, start_routine, parm);
573 return 0;
574 case STATUS_NO_MEMORY:
575 return ENOMEM;
576 case STATUS_TOO_MANY_OPENED_FILES:
577 return EMFILE;
578 default:
579 ERR("Unhandled ntstatus %08x\n", ret);
580 return ENOMEM;
584 static int __hook_pthread_detach(pthread_t thread)
586 struct ntdll_thread_data *thread_data;
587 TEB *teb = NULL;
589 if (pthread_equal(thread, pthread_self())) {
590 TRACE("Detached self: %lx\n", pthread_self());
591 ntdll_get_thread_data()->detached = 1;
592 return 0;
595 take_thread_lock();
596 LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), entry) {
597 if (pthread_equal(thread_data->pthread_id, thread)) {
598 teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
600 list_remove(&thread_data->entry);
601 if (!pthread_tryjoin_np(thread, NULL)) {
602 detach_thread_unlock(NULL);
603 TRACE("Thread %lx was dead, cleaning up\n", thread);
604 signal_free_thread(teb);
605 return 0;
607 thread_data->detached = 1;
608 break;
611 detach_thread_unlock(NULL);
612 if (!teb)
613 TRACE("Could not find thread %lx to detach\n", thread);
614 else
615 TRACE("Changed thread %lx to detached\n", thread);
616 return teb ? 0 : ESRCH;
619 static int __hook_pthread_join(pthread_t thread, void **retval)
621 struct ntdll_thread_data *thread_data, *t2;
622 int ret = ESRCH;
624 if (pthread_equal(thread, pthread_self()))
625 return EDEADLK;
627 take_thread_lock();
628 LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), entry) {
629 TEB *teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
631 if (pthread_equal(thread, thread_data->pthread_id)) {
633 ret = pthread_tryjoin_np(thread, retval);
634 if (!ret) {
635 TRACE("Thread %lx was dead fastpath, cleaning up\n", thread);
636 goto free;
638 detach_thread_unlock(NULL);
640 ret = __glob_pthread_join(thread, retval);
641 if (ret) {
642 TRACE("Thread %lx join failed with %i, ignoring\n", thread, ret);
643 return ret;
646 take_thread_lock();
647 /* Check if someone else freed the thread yet */
648 LIST_FOR_EACH_ENTRY(t2, &active_list, typeof(*thread_data), entry)
649 if (t2 == thread_data) {
650 TRACE("Cleaning up after successful join\n");
651 goto free;
653 TRACE("No clean up after successful join, multiple pthread_join's?\n");
654 break;
656 free:
657 list_remove(&thread_data->entry);
658 detach_thread_unlock(NULL);
659 signal_free_thread(teb);
660 return 0;
664 detach_thread_unlock(NULL);
665 if (ret)
666 TRACE("failed with %i\n", ret);
667 return ret;
670 #endif
672 /***********************************************************************
673 * start_thread
675 * Startup routine for a newly created thread.
677 static void start_thread( struct startup_info *info )
679 TEB *teb = info->teb;
680 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
681 PRTL_THREAD_START_ROUTINE func = info->entry_point;
682 void *arg = info->entry_arg;
683 struct debug_info debug_info;
685 debug_info.str_pos = debug_info.strings;
686 debug_info.out_pos = debug_info.output;
687 thread_data->debug_info = &debug_info;
688 thread_data->pthread_id = pthread_self();
690 signal_init_thread( teb );
691 server_init_thread( func );
692 pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
694 MODULE_DllThreadAttach( NULL );
696 if (TRACE_ON(relay))
697 DPRINTF( "%04x:Starting thread proc %p (arg=%p)\n", GetCurrentThreadId(), func, arg );
699 #ifdef __linux__
700 if (info->native_thread) {
701 void *(*start)(void*) = (void*)func;
703 FIXME("Started native thread %08x\n", GetCurrentThreadId());
704 pthread_cleanup_push(call_native_cleanup, NULL);
705 pthread_exit(start(arg));
706 pthread_cleanup_pop(1);
707 return;
709 #endif
710 call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
713 /***********************************************************************
714 * RtlCreateUserThread (NTDLL.@)
716 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
717 BOOLEAN suspended, PVOID stack_addr,
718 SIZE_T stack_reserve, SIZE_T stack_commit,
719 PRTL_THREAD_START_ROUTINE start, void *param,
720 HANDLE *handle_ptr, CLIENT_ID *id )
722 sigset_t sigset;
723 pthread_attr_t attr;
724 struct ntdll_thread_data *thread_data;
725 struct startup_info *info = NULL;
726 HANDLE handle = 0, actctx = 0;
727 TEB *teb = NULL;
728 DWORD tid = 0;
729 int request_pipe[2], ret;
730 NTSTATUS status;
732 if (process != NtCurrentProcess())
734 apc_call_t call;
735 apc_result_t result;
737 memset( &call, 0, sizeof(call) );
739 call.create_thread.type = APC_CREATE_THREAD;
740 call.create_thread.func = wine_server_client_ptr( start );
741 call.create_thread.arg = wine_server_client_ptr( param );
742 call.create_thread.reserve = stack_reserve;
743 call.create_thread.commit = stack_commit;
744 call.create_thread.suspend = suspended;
745 status = server_queue_process_apc( process, &call, &result );
746 if (status != STATUS_SUCCESS) return status;
748 if (result.create_thread.status == STATUS_SUCCESS)
750 if (id) id->UniqueThread = ULongToHandle(result.create_thread.tid);
751 if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle );
752 else NtClose( wine_server_ptr_handle( result.create_thread.handle ));
754 TRACE("CreateThread for other process returns %08x\n", result.create_thread.status);
755 return result.create_thread.status;
758 if (server_pipe( request_pipe ) == -1) {
759 TRACE("CreateThread cannot create request pipe: %m\n");
760 return STATUS_TOO_MANY_OPENED_FILES;
762 wine_server_send_fd( request_pipe[0] );
764 SERVER_START_REQ( new_thread )
766 req->access = THREAD_ALL_ACCESS;
767 req->attributes = 0; /* FIXME */
768 req->suspend = suspended;
769 req->request_fd = request_pipe[0];
770 if (!(status = wine_server_call( req )))
772 handle = wine_server_ptr_handle( reply->handle );
773 tid = reply->tid;
775 close( request_pipe[0] );
777 SERVER_END_REQ;
779 if (status)
781 close( request_pipe[1] );
782 TRACE("CreateThread server request failed with %08x\n", status);
783 return status;
786 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
788 if ((status = signal_alloc_thread( &teb ))) {
789 TRACE("CreateThread signal thread allocation failed with %08x\n", status);
790 goto error;
793 teb->Peb = NtCurrentTeb()->Peb;
794 teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
795 teb->ClientId.UniqueThread = ULongToHandle(tid);
796 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
797 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
799 /* create default activation context frame for new thread */
800 RtlGetActiveActivationContext(&actctx);
801 if (actctx)
803 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
805 frame = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame));
806 frame->Previous = NULL;
807 frame->ActivationContext = actctx;
808 frame->Flags = 0;
809 teb->ActivationContextStack.ActiveFrame = frame;
812 info = (struct startup_info *)(teb + 1);
813 info->teb = teb;
814 #ifdef __linux__
815 info->native_thread = (void*)start == (void*)&native_unix_start;
816 if (info->native_thread) {
817 struct unix_arg *arg = param;
818 info->entry_point = (void*)arg->start;
819 info->entry_arg = arg->arg;
820 } else
821 #endif
823 info->entry_point = start;
824 info->entry_arg = param;
827 thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
828 #ifdef __linux__
829 thread_data->detached = !info->native_thread;
830 #endif
831 thread_data->request_fd = request_pipe[1];
832 thread_data->reply_fd = -1;
833 thread_data->wait_fd[0] = -1;
834 thread_data->wait_fd[1] = -1;
835 thread_data->entry.next = NULL;
837 if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit ))) {
838 TRACE("Allocating virtual stack for %p (%li/%li) failed with %08x\n", start, stack_reserve, stack_commit, status);
839 goto error;
842 pthread_attr_init( &attr );
843 pthread_attr_setstack( &attr, teb->DeallocationStack,
844 (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
845 pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
846 interlocked_xchg_add( &nb_threads, 1 );
848 take_thread_lock();
849 ret = __glob_pthread_create( &thread_data->pthread_id, &attr, (void * (*)(void *))start_thread, info );
850 if (ret)
852 TRACE("pthread create failed with %i/%m\n", ret);
853 interlocked_xchg_add( &nb_threads, -1 );
854 pthread_attr_destroy( &attr );
855 status = STATUS_NO_MEMORY;
856 goto error;
858 if (!thread_data->detached)
859 list_add_tail(&active_list, &thread_data->entry);
860 detach_thread_unlock(NULL);
862 pthread_attr_destroy( &attr );
863 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
865 TRACE("Created thread succesfully, win handle: %04x, pthread: %lx\n", tid, thread_data->pthread_id);
867 #ifdef __linux__
868 if ((void*)start == (void*)&native_unix_start && id)
869 *(pthread_t*)id = thread_data->pthread_id;
870 else
871 #endif
872 if (id) id->UniqueThread = ULongToHandle(tid);
873 if (handle_ptr) *handle_ptr = handle;
874 else NtClose( handle );
876 return STATUS_SUCCESS;
878 error:
879 if (teb) signal_free_thread( teb );
880 if (handle) NtClose( handle );
881 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
882 close( request_pipe[1] );
883 return status;
887 /******************************************************************************
888 * RtlGetNtGlobalFlags (NTDLL.@)
890 ULONG WINAPI RtlGetNtGlobalFlags(void)
892 if (!peb) return 0; /* init not done yet */
893 return peb->NtGlobalFlag;
897 /***********************************************************************
898 * NtOpenThread (NTDLL.@)
899 * ZwOpenThread (NTDLL.@)
901 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
902 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
904 NTSTATUS ret;
906 SERVER_START_REQ( open_thread )
908 req->tid = HandleToULong(id->UniqueThread);
909 req->access = access;
910 req->attributes = attr ? attr->Attributes : 0;
911 ret = wine_server_call( req );
912 *handle = wine_server_ptr_handle( reply->handle );
914 SERVER_END_REQ;
915 return ret;
919 /******************************************************************************
920 * NtSuspendThread (NTDLL.@)
921 * ZwSuspendThread (NTDLL.@)
923 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
925 NTSTATUS ret;
927 SERVER_START_REQ( suspend_thread )
929 req->handle = wine_server_obj_handle( handle );
930 if (!(ret = wine_server_call( req ))) *count = reply->count;
932 SERVER_END_REQ;
933 return ret;
937 /******************************************************************************
938 * NtResumeThread (NTDLL.@)
939 * ZwResumeThread (NTDLL.@)
941 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
943 NTSTATUS ret;
945 SERVER_START_REQ( resume_thread )
947 req->handle = wine_server_obj_handle( handle );
948 if (!(ret = wine_server_call( req ))) *count = reply->count;
950 SERVER_END_REQ;
951 return ret;
955 /******************************************************************************
956 * NtAlertResumeThread (NTDLL.@)
957 * ZwAlertResumeThread (NTDLL.@)
959 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
961 FIXME( "stub: should alert thread %p\n", handle );
962 return NtResumeThread( handle, count );
966 /******************************************************************************
967 * NtAlertThread (NTDLL.@)
968 * ZwAlertThread (NTDLL.@)
970 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
972 FIXME( "stub: %p\n", handle );
973 return STATUS_NOT_IMPLEMENTED;
977 /******************************************************************************
978 * NtTerminateThread (NTDLL.@)
979 * ZwTerminateThread (NTDLL.@)
981 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
983 NTSTATUS ret;
984 BOOL self;
986 SERVER_START_REQ( terminate_thread )
988 req->handle = wine_server_obj_handle( handle );
989 req->exit_code = exit_code;
990 ret = wine_server_call( req );
991 self = !ret && reply->self;
993 SERVER_END_REQ;
995 if (self) abort_thread( exit_code );
996 return ret;
1000 /******************************************************************************
1001 * NtQueueApcThread (NTDLL.@)
1003 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
1004 ULONG_PTR arg2, ULONG_PTR arg3 )
1006 NTSTATUS ret;
1007 SERVER_START_REQ( queue_apc )
1009 req->handle = wine_server_obj_handle( handle );
1010 if (func)
1012 req->call.type = APC_USER;
1013 req->call.user.func = wine_server_client_ptr( func );
1014 req->call.user.args[0] = arg1;
1015 req->call.user.args[1] = arg2;
1016 req->call.user.args[2] = arg3;
1018 else req->call.type = APC_NONE; /* wake up only */
1019 ret = wine_server_call( req );
1021 SERVER_END_REQ;
1022 return ret;
1026 /***********************************************************************
1027 * NtSetContextThread (NTDLL.@)
1028 * ZwSetContextThread (NTDLL.@)
1030 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
1032 NTSTATUS ret;
1033 DWORD dummy, i;
1034 BOOL self = FALSE;
1036 #ifdef __i386__
1037 /* on i386 debug registers always require a server call */
1038 self = (handle == GetCurrentThread());
1039 if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
1041 self = (ntdll_get_thread_data()->dr0 == context->Dr0 &&
1042 ntdll_get_thread_data()->dr1 == context->Dr1 &&
1043 ntdll_get_thread_data()->dr2 == context->Dr2 &&
1044 ntdll_get_thread_data()->dr3 == context->Dr3 &&
1045 ntdll_get_thread_data()->dr6 == context->Dr6 &&
1046 ntdll_get_thread_data()->dr7 == context->Dr7);
1048 #endif
1050 if (!self)
1052 context_t server_context;
1054 context_to_server( &server_context, context );
1056 SERVER_START_REQ( set_thread_context )
1058 req->handle = wine_server_obj_handle( handle );
1059 req->suspend = 1;
1060 wine_server_add_data( req, &server_context, sizeof(server_context) );
1061 ret = wine_server_call( req );
1062 self = reply->self;
1064 SERVER_END_REQ;
1066 if (ret == STATUS_PENDING)
1068 for (i = 0; i < 100; i++)
1070 SERVER_START_REQ( set_thread_context )
1072 req->handle = wine_server_obj_handle( handle );
1073 req->suspend = 0;
1074 wine_server_add_data( req, &server_context, sizeof(server_context) );
1075 ret = wine_server_call( req );
1077 SERVER_END_REQ;
1078 if (ret == STATUS_PENDING)
1080 LARGE_INTEGER timeout;
1081 timeout.QuadPart = -10000;
1082 NtDelayExecution( FALSE, &timeout );
1084 else break;
1086 NtResumeThread( handle, &dummy );
1087 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
1090 if (ret) return ret;
1093 if (self) set_cpu_context( context );
1094 return STATUS_SUCCESS;
1098 /* convert CPU-specific flags to generic server flags */
1099 static inline unsigned int get_server_context_flags( DWORD flags )
1101 unsigned int ret = 0;
1103 flags &= 0x3f; /* mask CPU id flags */
1104 if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
1105 if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
1106 #ifdef CONTEXT_SEGMENTS
1107 if (flags & CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
1108 #endif
1109 #ifdef CONTEXT_FLOATING_POINT
1110 if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
1111 #endif
1112 #ifdef CONTEXT_DEBUG_REGISTERS
1113 if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
1114 #endif
1115 #ifdef CONTEXT_EXTENDED_REGISTERS
1116 if (flags & CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
1117 #endif
1118 return ret;
1121 /***********************************************************************
1122 * NtGetContextThread (NTDLL.@)
1123 * ZwGetContextThread (NTDLL.@)
1125 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
1127 NTSTATUS ret;
1128 DWORD dummy, i;
1129 DWORD needed_flags = context->ContextFlags;
1130 BOOL self = (handle == GetCurrentThread());
1132 #ifdef __i386__
1133 /* on i386 debug registers always require a server call */
1134 if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) self = FALSE;
1135 #endif
1137 if (!self)
1139 unsigned int server_flags = get_server_context_flags( context->ContextFlags );
1140 context_t server_context;
1142 SERVER_START_REQ( get_thread_context )
1144 req->handle = wine_server_obj_handle( handle );
1145 req->flags = server_flags;
1146 req->suspend = 1;
1147 wine_server_set_reply( req, &server_context, sizeof(server_context) );
1148 ret = wine_server_call( req );
1149 self = reply->self;
1151 SERVER_END_REQ;
1153 if (ret == STATUS_PENDING)
1155 for (i = 0; i < 100; i++)
1157 SERVER_START_REQ( get_thread_context )
1159 req->handle = wine_server_obj_handle( handle );
1160 req->flags = server_flags;
1161 req->suspend = 0;
1162 wine_server_set_reply( req, &server_context, sizeof(server_context) );
1163 ret = wine_server_call( req );
1165 SERVER_END_REQ;
1166 if (ret == STATUS_PENDING)
1168 LARGE_INTEGER timeout;
1169 timeout.QuadPart = -10000;
1170 NtDelayExecution( FALSE, &timeout );
1172 else break;
1174 NtResumeThread( handle, &dummy );
1175 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
1177 if (!ret) ret = context_from_server( context, &server_context );
1178 if (ret) return ret;
1179 needed_flags &= ~context->ContextFlags;
1182 if (self)
1184 if (needed_flags)
1186 CONTEXT ctx;
1187 RtlCaptureContext( &ctx );
1188 copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
1189 context->ContextFlags |= ctx.ContextFlags & needed_flags;
1191 #ifdef __i386__
1192 /* update the cached version of the debug registers */
1193 if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
1195 ntdll_get_thread_data()->dr0 = context->Dr0;
1196 ntdll_get_thread_data()->dr1 = context->Dr1;
1197 ntdll_get_thread_data()->dr2 = context->Dr2;
1198 ntdll_get_thread_data()->dr3 = context->Dr3;
1199 ntdll_get_thread_data()->dr6 = context->Dr6;
1200 ntdll_get_thread_data()->dr7 = context->Dr7;
1202 #endif
1204 return STATUS_SUCCESS;
1208 /******************************************************************************
1209 * NtQueryInformationThread (NTDLL.@)
1210 * ZwQueryInformationThread (NTDLL.@)
1212 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
1213 void *data, ULONG length, ULONG *ret_len )
1215 NTSTATUS status;
1217 switch(class)
1219 case ThreadBasicInformation:
1221 THREAD_BASIC_INFORMATION info;
1222 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1224 SERVER_START_REQ( get_thread_info )
1226 req->handle = wine_server_obj_handle( handle );
1227 req->tid_in = 0;
1228 if (!(status = wine_server_call( req )))
1230 info.ExitStatus = reply->exit_code;
1231 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
1232 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
1233 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
1234 info.AffinityMask = reply->affinity & affinity_mask;
1235 info.Priority = reply->priority;
1236 info.BasePriority = reply->priority; /* FIXME */
1239 SERVER_END_REQ;
1240 if (status == STATUS_SUCCESS)
1242 if (data) memcpy( data, &info, min( length, sizeof(info) ));
1243 if (ret_len) *ret_len = min( length, sizeof(info) );
1246 return status;
1247 case ThreadAffinityMask:
1249 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1250 ULONG_PTR affinity = 0;
1252 SERVER_START_REQ( get_thread_info )
1254 req->handle = wine_server_obj_handle( handle );
1255 req->tid_in = 0;
1256 if (!(status = wine_server_call( req )))
1257 affinity = reply->affinity & affinity_mask;
1259 SERVER_END_REQ;
1260 if (status == STATUS_SUCCESS)
1262 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1263 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1266 return status;
1267 case ThreadTimes:
1269 KERNEL_USER_TIMES kusrt;
1271 SERVER_START_REQ( get_thread_times )
1273 req->handle = wine_server_obj_handle( handle );
1274 status = wine_server_call( req );
1275 if (status == STATUS_SUCCESS)
1277 kusrt.CreateTime.QuadPart = reply->creation_time;
1278 kusrt.ExitTime.QuadPart = reply->exit_time;
1281 SERVER_END_REQ;
1282 if (status == STATUS_SUCCESS)
1284 /* We call times(2) for kernel time or user time */
1285 /* We can only (portably) do this for the current thread */
1286 if (handle == GetCurrentThread())
1288 struct tms time_buf;
1289 long clocks_per_sec = sysconf(_SC_CLK_TCK);
1291 times(&time_buf);
1292 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
1293 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
1295 else
1297 static BOOL reported = FALSE;
1299 kusrt.KernelTime.QuadPart = 0;
1300 kusrt.UserTime.QuadPart = 0;
1301 if (reported)
1302 TRACE("Cannot get kerneltime or usertime of other threads\n");
1303 else
1305 FIXME("Cannot get kerneltime or usertime of other threads\n");
1306 reported = TRUE;
1309 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1310 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1313 return status;
1314 case ThreadDescriptorTableEntry:
1316 #ifdef __i386__
1317 THREAD_DESCRIPTOR_INFORMATION* tdi = data;
1318 if (length < sizeof(*tdi))
1319 status = STATUS_INFO_LENGTH_MISMATCH;
1320 else if (!(tdi->Selector & 4)) /* GDT selector */
1322 unsigned sel = LOWORD(tdi->Selector) & ~3; /* ignore RPL */
1323 status = STATUS_SUCCESS;
1324 if (!sel) /* null selector */
1325 memset( &tdi->Entry, 0, sizeof(tdi->Entry) );
1326 else
1328 tdi->Entry.BaseLow = 0;
1329 tdi->Entry.HighWord.Bits.BaseMid = 0;
1330 tdi->Entry.HighWord.Bits.BaseHi = 0;
1331 tdi->Entry.LimitLow = 0xffff;
1332 tdi->Entry.HighWord.Bits.LimitHi = 0xf;
1333 tdi->Entry.HighWord.Bits.Dpl = 3;
1334 tdi->Entry.HighWord.Bits.Sys = 0;
1335 tdi->Entry.HighWord.Bits.Pres = 1;
1336 tdi->Entry.HighWord.Bits.Granularity = 1;
1337 tdi->Entry.HighWord.Bits.Default_Big = 1;
1338 tdi->Entry.HighWord.Bits.Type = 0x12;
1339 /* it has to be one of the system GDT selectors */
1340 if (sel != (wine_get_ds() & ~3) && sel != (wine_get_ss() & ~3))
1342 if (sel == (wine_get_cs() & ~3))
1343 tdi->Entry.HighWord.Bits.Type |= 8; /* code segment */
1344 else status = STATUS_ACCESS_DENIED;
1348 else
1350 SERVER_START_REQ( get_selector_entry )
1352 req->handle = wine_server_obj_handle( handle );
1353 req->entry = LOWORD(tdi->Selector) >> 3;
1354 status = wine_server_call( req );
1355 if (!status)
1357 if (!(reply->flags & WINE_LDT_FLAGS_ALLOCATED))
1358 status = STATUS_ACCESS_VIOLATION;
1359 else
1361 wine_ldt_set_base ( &tdi->Entry, (void *)reply->base );
1362 wine_ldt_set_limit( &tdi->Entry, reply->limit );
1363 wine_ldt_set_flags( &tdi->Entry, reply->flags );
1367 SERVER_END_REQ;
1369 if (status == STATUS_SUCCESS && ret_len)
1370 /* yes, that's a bit strange, but it's the way it is */
1371 *ret_len = sizeof(LDT_ENTRY);
1372 #else
1373 status = STATUS_NOT_IMPLEMENTED;
1374 #endif
1375 return status;
1377 case ThreadAmILastThread:
1379 SERVER_START_REQ(get_thread_info)
1381 req->handle = wine_server_obj_handle( handle );
1382 req->tid_in = 0;
1383 status = wine_server_call( req );
1384 if (status == STATUS_SUCCESS)
1386 BOOLEAN last = reply->last;
1387 if (data) memcpy( data, &last, min( length, sizeof(last) ));
1388 if (ret_len) *ret_len = min( length, sizeof(last) );
1391 SERVER_END_REQ;
1392 return status;
1394 case ThreadQuerySetWin32StartAddress:
1396 SERVER_START_REQ( get_thread_info )
1398 req->handle = wine_server_obj_handle( handle );
1399 req->tid_in = 0;
1400 status = wine_server_call( req );
1401 if (status == STATUS_SUCCESS)
1403 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1404 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1405 if (ret_len) *ret_len = min( length, sizeof(entry) );
1408 SERVER_END_REQ;
1409 return status;
1411 case ThreadGroupInformation:
1413 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1414 GROUP_AFFINITY affinity;
1416 memset(&affinity, 0, sizeof(affinity));
1417 affinity.Group = 0; /* Wine only supports max 64 processors */
1419 SERVER_START_REQ( get_thread_info )
1421 req->handle = wine_server_obj_handle( handle );
1422 req->tid_in = 0;
1423 if (!(status = wine_server_call( req )))
1424 affinity.Mask = reply->affinity & affinity_mask;
1426 SERVER_END_REQ;
1427 if (status == STATUS_SUCCESS)
1429 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1430 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1433 return status;
1434 case ThreadPriority:
1435 case ThreadBasePriority:
1436 case ThreadImpersonationToken:
1437 case ThreadEnableAlignmentFaultFixup:
1438 case ThreadEventPair_Reusable:
1439 case ThreadZeroTlsCell:
1440 case ThreadPerformanceCount:
1441 case ThreadIdealProcessor:
1442 case ThreadPriorityBoost:
1443 case ThreadSetTlsArrayAddress:
1444 case ThreadIsIoPending:
1445 default:
1446 FIXME( "info class %d not supported yet\n", class );
1447 return STATUS_NOT_IMPLEMENTED;
1452 /******************************************************************************
1453 * NtSetInformationThread (NTDLL.@)
1454 * ZwSetInformationThread (NTDLL.@)
1456 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
1457 LPCVOID data, ULONG length )
1459 NTSTATUS status;
1460 switch(class)
1462 case ThreadZeroTlsCell:
1463 if (handle == GetCurrentThread())
1465 LIST_ENTRY *entry;
1466 DWORD index;
1468 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1469 index = *(const DWORD *)data;
1470 if (index < TLS_MINIMUM_AVAILABLE)
1472 RtlAcquirePebLock();
1473 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1475 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1476 teb->TlsSlots[index] = 0;
1478 RtlReleasePebLock();
1480 else
1482 index -= TLS_MINIMUM_AVAILABLE;
1483 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
1484 return STATUS_INVALID_PARAMETER;
1485 RtlAcquirePebLock();
1486 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1488 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1489 if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
1491 RtlReleasePebLock();
1493 return STATUS_SUCCESS;
1495 FIXME( "ZeroTlsCell not supported on other threads\n" );
1496 return STATUS_NOT_IMPLEMENTED;
1498 case ThreadImpersonationToken:
1500 const HANDLE *phToken = data;
1501 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1502 TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
1503 SERVER_START_REQ( set_thread_info )
1505 req->handle = wine_server_obj_handle( handle );
1506 req->token = wine_server_obj_handle( *phToken );
1507 req->mask = SET_THREAD_INFO_TOKEN;
1508 status = wine_server_call( req );
1510 SERVER_END_REQ;
1512 return status;
1513 case ThreadBasePriority:
1515 const DWORD *pprio = data;
1516 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1517 SERVER_START_REQ( set_thread_info )
1519 req->handle = wine_server_obj_handle( handle );
1520 req->priority = *pprio;
1521 req->mask = SET_THREAD_INFO_PRIORITY;
1522 status = wine_server_call( req );
1524 SERVER_END_REQ;
1526 return status;
1527 case ThreadAffinityMask:
1529 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1530 ULONG_PTR req_aff;
1532 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
1533 req_aff = *(const ULONG_PTR *)data;
1534 if ((ULONG)req_aff == ~0u) req_aff = affinity_mask;
1535 else if (req_aff & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1536 else if (!req_aff) return STATUS_INVALID_PARAMETER;
1537 SERVER_START_REQ( set_thread_info )
1539 req->handle = wine_server_obj_handle( handle );
1540 req->affinity = req_aff;
1541 req->mask = SET_THREAD_INFO_AFFINITY;
1542 status = wine_server_call( req );
1544 SERVER_END_REQ;
1546 return status;
1547 case ThreadHideFromDebugger:
1548 /* pretend the call succeeded to satisfy some code protectors */
1549 return STATUS_SUCCESS;
1550 case ThreadQuerySetWin32StartAddress:
1552 const PRTL_THREAD_START_ROUTINE *entry = data;
1553 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
1554 SERVER_START_REQ( set_thread_info )
1556 req->handle = wine_server_obj_handle( handle );
1557 req->mask = SET_THREAD_INFO_ENTRYPOINT;
1558 req->entry_point = wine_server_client_ptr( *entry );
1559 status = wine_server_call( req );
1561 SERVER_END_REQ;
1563 return status;
1564 case ThreadGroupInformation:
1566 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1567 const GROUP_AFFINITY *req_aff;
1569 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
1570 if (!data) return STATUS_ACCESS_VIOLATION;
1571 req_aff = data;
1573 /* On Windows the request fails if the reserved fields are set */
1574 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
1575 return STATUS_INVALID_PARAMETER;
1577 /* Wine only supports max 64 processors */
1578 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
1579 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1580 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
1581 SERVER_START_REQ( set_thread_info )
1583 req->handle = wine_server_obj_handle( handle );
1584 req->affinity = req_aff->Mask;
1585 req->mask = SET_THREAD_INFO_AFFINITY;
1586 status = wine_server_call( req );
1588 SERVER_END_REQ;
1590 return status;
1591 case ThreadBasicInformation:
1592 case ThreadTimes:
1593 case ThreadPriority:
1594 case ThreadDescriptorTableEntry:
1595 case ThreadEnableAlignmentFaultFixup:
1596 case ThreadEventPair_Reusable:
1597 case ThreadPerformanceCount:
1598 case ThreadAmILastThread:
1599 case ThreadIdealProcessor:
1600 case ThreadPriorityBoost:
1601 case ThreadSetTlsArrayAddress:
1602 case ThreadIsIoPending:
1603 default:
1604 FIXME( "info class %d not supported yet\n", class );
1605 return STATUS_NOT_IMPLEMENTED;
1609 /******************************************************************************
1610 * NtGetCurrentProcessorNumber (NTDLL.@)
1612 * Return the processor, on which the thread is running
1615 ULONG WINAPI NtGetCurrentProcessorNumber(void)
1617 ULONG processor;
1619 #if defined(__linux__) && defined(__NR_getcpu)
1620 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
1621 if (res != -1) return processor;
1622 #endif
1624 if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
1626 ULONG_PTR thread_mask, processor_mask;
1627 NTSTATUS status;
1629 status = NtQueryInformationThread(GetCurrentThread(), ThreadAffinityMask,
1630 &thread_mask, sizeof(thread_mask), NULL);
1631 if (status == STATUS_SUCCESS)
1633 for (processor = 0; processor < NtCurrentTeb()->Peb->NumberOfProcessors; processor++)
1635 processor_mask = (1 << processor);
1636 if (thread_mask & processor_mask)
1638 if (thread_mask != processor_mask)
1639 FIXME("need multicore support (%d processors)\n",
1640 NtCurrentTeb()->Peb->NumberOfProcessors);
1641 return processor;
1647 /* fallback to the first processor */
1648 return 0;