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
22 #include "wine/port.h"
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_MMAN_H
30 #ifdef HAVE_SYS_TIMES_H
31 #include <sys/times.h>
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
38 #define NONAMELESSUNION
40 #define WIN32_NO_STATUS
42 #include "wine/library.h"
43 #include "wine/server.h"
44 #include "wine/debug.h"
45 #include "ntdll_misc.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 */
60 PRTL_THREAD_START_ROUTINE entry_point
;
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 /***********************************************************************
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
)
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
)
99 SIZE_T info_size
, env_size
, size
, alloc_size
;
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
);
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
);
132 status
= NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms
, 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
;
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( ¶ms
->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( ¶ms
->DllPath
, &src
, &dst
, info
->dllpath_len
);
165 get_unicode_string( ¶ms
->ImagePathName
, &src
, &dst
, info
->imagepath_len
);
166 get_unicode_string( ¶ms
->CommandLine
, &src
, &dst
, info
->cmdline_len
);
167 get_unicode_string( ¶ms
->WindowTitle
, &src
, &dst
, info
->title_len
);
168 get_unicode_string( ¶ms
->Desktop
, &src
, &dst
, info
->desktop_len
);
169 get_unicode_string( ¶ms
->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 */
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
;
186 RtlFreeHeap( GetProcessHeap(), 0, info
);
191 #include <mach/mach.h>
192 #include <mach/mach_error.h>
194 static ULONG64
get_dyld_image_info_addr(void)
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
;
205 #endif /* __APPLE__ */
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
;
250 pthread_mutex_unlock(&thread_lock
);
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
;
263 if (thread_data
->detached
)
264 detach_thread_unlock(teb
);
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.
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()
281 /***********************************************************************
284 * Setup the initial thread.
286 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
288 HANDLE
thread_init(void)
292 SIZE_T size
, info_size
;
296 struct ntdll_thread_data
*thread_data
;
297 static struct debug_info debug_info
; /* debug info for initial thread */
299 ULONG64 dyld_image_info
;
305 /* reserve space for shared user data */
307 addr
= (void *)0x7ffe0000;
309 status
= NtAllocateVirtualMemory( NtCurrentProcess(), &addr
, 0, &size
,
310 MEM_RESERVE
|MEM_COMMIT
, PAGE_READWRITE
);
313 MESSAGE( "wine: failed to map the shared user data: %08x\n", status
);
316 user_shared_data
= addr
;
318 /* allocate and initialize the PEB */
322 NtAllocateVirtualMemory( NtCurrentProcess(), &addr
, 1, &size
,
323 MEM_COMMIT
| MEM_TOP_DOWN
, PAGE_READWRITE
);
326 peb
->ProcessParameters
= ¶ms
;
327 peb
->TlsBitmap
= &tls_bitmap
;
328 peb
->TlsExpansionBitmap
= &tls_expansion_bitmap
;
329 peb
->FlsBitmap
= &fls_bitmap
;
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
);
346 dyld_image_info
= get_dyld_image_info_addr();
348 #ifdef WORDS_BIGENDIAN
349 peb
->Reserved
[1] = dyld_image_info
& 0xFFFFFFFF;
350 peb
->Reserved
[0] = dyld_image_info
>> 32;
352 peb
->Reserved
[0] = dyld_image_info
& 0xFFFFFFFF;
353 peb
->Reserved
[1] = dyld_image_info
>> 32;
356 peb
->Reserved
[0] = dyld_image_info
& 0xFFFFFFFF;
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).
366 /* allocate and initialize the initial TEB */
368 signal_alloc_thread( &teb
);
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
;
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" );
400 /* allocate user parameters */
403 init_user_process_params( info_size
, &exe_file
);
407 if (isatty(0) || isatty(1) || isatty(2))
408 params
.ConsoleHandle
= (HANDLE
)2; /* see kernel32/kernel_private.h */
410 wine_server_fd_to_handle( 0, GENERIC_READ
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
.hStdInput
);
412 wine_server_fd_to_handle( 1, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
.hStdOutput
);
414 wine_server_fd_to_handle( 2, GENERIC_WRITE
|SYNCHRONIZE
, OBJ_INHERIT
, ¶ms
.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;
428 NtCreateKeyedEvent( &keyed_event
, GENERIC_READ
| GENERIC_WRITE
, NULL
, 0 );
434 /***********************************************************************
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
)
452 static void *prev_teb
;
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
);
467 if (interlocked_xchg_add( &nb_threads
, -1 ) <= 1)
469 LdrShutdownProcess();
474 RtlFreeThreadActivationContextStack();
476 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
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
);
490 reap_thread(NtCurrentTeb());
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
) );
508 void *(*start
)(void *);
512 /* dummy used for comparison */
513 static DWORD native_unix_start
;
515 static void call_native_cleanup(void *arg
)
517 exit_thread_common(0);
521 __hook_pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
522 void *(*start_routine
) (void *), void *parm
)
526 size_t stack
= 0, stack_commit
;
527 static size_t default_stack
;
529 IMAGE_NT_HEADERS
*nt
;
531 arg
.start
= start_routine
;
534 if (!default_stack
) {
537 if (getrlimit(RLIMIT_STACK
, &limit
) == 0 &&
538 limit
.rlim_cur
!= RLIM_INFINITY
)
539 default_stack
= limit
.rlim_cur
;
541 default_stack
= 2 * 1024 * 1024;
547 TRACE("Overriding thread creation!\n");
551 FIXME("most thread attributes ignored!\n");
553 WARN("most thread attributes ignored!\n");
555 pthread_attr_getstacksize(attr
, &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
);
572 TRACE("created thread %lx for %p/%p\n", *thread
, start_routine
, parm
);
574 case STATUS_NO_MEMORY
:
576 case STATUS_TOO_MANY_OPENED_FILES
:
579 ERR("Unhandled ntstatus %08x\n", ret
);
584 static int __hook_pthread_detach(pthread_t thread
)
586 struct ntdll_thread_data
*thread_data
;
589 if (pthread_equal(thread
, pthread_self())) {
590 TRACE("Detached self: %lx\n", pthread_self());
591 ntdll_get_thread_data()->detached
= 1;
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
);
607 thread_data
->detached
= 1;
611 detach_thread_unlock(NULL
);
613 TRACE("Could not find thread %lx to detach\n", thread
);
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
;
624 if (pthread_equal(thread
, pthread_self()))
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
);
635 TRACE("Thread %lx was dead fastpath, cleaning up\n", thread
);
638 detach_thread_unlock(NULL
);
640 ret
= __glob_pthread_join(thread
, retval
);
642 TRACE("Thread %lx join failed with %i, ignoring\n", thread
, ret
);
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");
653 TRACE("No clean up after successful join, multiple pthread_join's?\n");
657 list_remove(&thread_data
->entry
);
658 detach_thread_unlock(NULL
);
659 signal_free_thread(teb
);
664 detach_thread_unlock(NULL
);
666 TRACE("failed with %i\n", ret
);
672 /***********************************************************************
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
);
697 DPRINTF( "%04x:Starting thread proc %p (arg=%p)\n", GetCurrentThreadId(), func
, arg
);
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);
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
)
724 struct ntdll_thread_data
*thread_data
;
725 struct startup_info
*info
= NULL
;
726 HANDLE handle
= 0, actctx
= 0;
729 int request_pipe
[2], ret
;
732 if (process
!= NtCurrentProcess())
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
);
775 close( request_pipe
[0] );
781 close( request_pipe
[1] );
782 TRACE("CreateThread server request failed with %08x\n", 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
);
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
);
803 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
805 frame
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame
));
806 frame
->Previous
= NULL
;
807 frame
->ActivationContext
= actctx
;
809 teb
->ActivationContextStack
.ActiveFrame
= frame
;
812 info
= (struct startup_info
*)(teb
+ 1);
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
;
823 info
->entry_point
= start
;
824 info
->entry_arg
= param
;
827 thread_data
= (struct ntdll_thread_data
*)teb
->SpareBytes1
;
829 thread_data
->detached
= !info
->native_thread
;
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
);
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 );
849 ret
= __glob_pthread_create( &thread_data
->pthread_id
, &attr
, (void * (*)(void *))start_thread
, info
);
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
;
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
);
868 if ((void*)start
== (void*)&native_unix_start
&& id
)
869 *(pthread_t
*)id
= thread_data
->pthread_id
;
872 if (id
) id
->UniqueThread
= ULongToHandle(tid
);
873 if (handle_ptr
) *handle_ptr
= handle
;
874 else NtClose( handle
);
876 return STATUS_SUCCESS
;
879 if (teb
) signal_free_thread( teb
);
880 if (handle
) NtClose( handle
);
881 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
882 close( request_pipe
[1] );
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
)
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
);
919 /******************************************************************************
920 * NtSuspendThread (NTDLL.@)
921 * ZwSuspendThread (NTDLL.@)
923 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, PULONG count
)
927 SERVER_START_REQ( suspend_thread
)
929 req
->handle
= wine_server_obj_handle( handle
);
930 if (!(ret
= wine_server_call( req
))) *count
= reply
->count
;
937 /******************************************************************************
938 * NtResumeThread (NTDLL.@)
939 * ZwResumeThread (NTDLL.@)
941 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, PULONG count
)
945 SERVER_START_REQ( resume_thread
)
947 req
->handle
= wine_server_obj_handle( handle
);
948 if (!(ret
= wine_server_call( req
))) *count
= reply
->count
;
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
)
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
;
995 if (self
) abort_thread( exit_code
);
1000 /******************************************************************************
1001 * NtQueueApcThread (NTDLL.@)
1003 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
1004 ULONG_PTR arg2
, ULONG_PTR arg3
)
1007 SERVER_START_REQ( queue_apc
)
1009 req
->handle
= wine_server_obj_handle( handle
);
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
);
1026 /***********************************************************************
1027 * NtSetContextThread (NTDLL.@)
1028 * ZwSetContextThread (NTDLL.@)
1030 NTSTATUS WINAPI
NtSetContextThread( HANDLE handle
, const CONTEXT
*context
)
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
);
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
);
1060 wine_server_add_data( req
, &server_context
, sizeof(server_context
) );
1061 ret
= wine_server_call( 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
);
1074 wine_server_add_data( req
, &server_context
, sizeof(server_context
) );
1075 ret
= wine_server_call( req
);
1078 if (ret
== STATUS_PENDING
)
1080 LARGE_INTEGER timeout
;
1081 timeout
.QuadPart
= -10000;
1082 NtDelayExecution( FALSE
, &timeout
);
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
;
1109 #ifdef CONTEXT_FLOATING_POINT
1110 if (flags
& CONTEXT_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
1112 #ifdef CONTEXT_DEBUG_REGISTERS
1113 if (flags
& CONTEXT_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
1115 #ifdef CONTEXT_EXTENDED_REGISTERS
1116 if (flags
& CONTEXT_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
;
1121 /***********************************************************************
1122 * NtGetContextThread (NTDLL.@)
1123 * ZwGetContextThread (NTDLL.@)
1125 NTSTATUS WINAPI
NtGetContextThread( HANDLE handle
, CONTEXT
*context
)
1129 DWORD needed_flags
= context
->ContextFlags
;
1130 BOOL self
= (handle
== GetCurrentThread());
1133 /* on i386 debug registers always require a server call */
1134 if (context
->ContextFlags
& (CONTEXT_DEBUG_REGISTERS
& ~CONTEXT_i386
)) self
= FALSE
;
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
;
1147 wine_server_set_reply( req
, &server_context
, sizeof(server_context
) );
1148 ret
= wine_server_call( 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
;
1162 wine_server_set_reply( req
, &server_context
, sizeof(server_context
) );
1163 ret
= wine_server_call( req
);
1166 if (ret
== STATUS_PENDING
)
1168 LARGE_INTEGER timeout
;
1169 timeout
.QuadPart
= -10000;
1170 NtDelayExecution( FALSE
, &timeout
);
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
;
1187 RtlCaptureContext( &ctx
);
1188 copy_context( context
, &ctx
, ctx
.ContextFlags
& needed_flags
);
1189 context
->ContextFlags
|= ctx
.ContextFlags
& needed_flags
;
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
;
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
)
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
);
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 */
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
) );
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
);
1256 if (!(status
= wine_server_call( req
)))
1257 affinity
= reply
->affinity
& affinity_mask
;
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
) );
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
;
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
);
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
;
1297 static BOOL reported
= FALSE
;
1299 kusrt
.KernelTime
.QuadPart
= 0;
1300 kusrt
.UserTime
.QuadPart
= 0;
1302 TRACE("Cannot get kerneltime or usertime of other threads\n");
1305 FIXME("Cannot get kerneltime or usertime of other threads\n");
1309 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
1310 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
1314 case ThreadDescriptorTableEntry
:
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
) );
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
;
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
);
1357 if (!(reply
->flags
& WINE_LDT_FLAGS_ALLOCATED
))
1358 status
= STATUS_ACCESS_VIOLATION
;
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
);
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
);
1373 status
= STATUS_NOT_IMPLEMENTED
;
1377 case ThreadAmILastThread
:
1379 SERVER_START_REQ(get_thread_info
)
1381 req
->handle
= wine_server_obj_handle( handle
);
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
) );
1394 case ThreadQuerySetWin32StartAddress
:
1396 SERVER_START_REQ( get_thread_info
)
1398 req
->handle
= wine_server_obj_handle( handle
);
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
) );
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
);
1423 if (!(status
= wine_server_call( req
)))
1424 affinity
.Mask
= reply
->affinity
& affinity_mask
;
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
) );
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
:
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
)
1462 case ThreadZeroTlsCell
:
1463 if (handle
== GetCurrentThread())
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();
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
);
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
);
1527 case ThreadAffinityMask
:
1529 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
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
);
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
);
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
;
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
);
1591 case ThreadBasicInformation
:
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
:
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)
1619 #if defined(__linux__) && defined(__NR_getcpu)
1620 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
1621 if (res
!= -1) return processor
;
1624 if (NtCurrentTeb()->Peb
->NumberOfProcessors
> 1)
1626 ULONG_PTR thread_mask
, processor_mask
;
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
);
1647 /* fallback to the first processor */