usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / ntdll / thread.c
blob126bf76742215efbb93b54f0700558afa5037da1
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 <limits.h>
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_MMAN_H
29 #include <sys/mman.h>
30 #endif
31 #ifdef HAVE_SYS_TIMES_H
32 #include <sys/times.h>
33 #endif
34 #ifdef HAVE_SYS_SYSCALL_H
35 #include <sys/syscall.h>
36 #endif
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);
51 #ifndef PTHREAD_STACK_MIN
52 #define PTHREAD_STACK_MIN 16384
53 #endif
55 struct _KUSER_SHARED_DATA *user_shared_data = NULL;
56 static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
58 void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL;
60 /* info passed to a starting thread */
61 struct startup_info
63 TEB *teb;
64 PRTL_THREAD_START_ROUTINE entry_point;
65 void *entry_arg;
68 static PEB *peb;
69 static PEB_LDR_DATA ldr;
70 static RTL_BITMAP tls_bitmap;
71 static RTL_BITMAP tls_expansion_bitmap;
72 static RTL_BITMAP fls_bitmap;
73 static int nb_threads = 1;
75 static RTL_CRITICAL_SECTION peb_lock;
76 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
78 0, 0, &peb_lock,
79 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
80 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
82 static RTL_CRITICAL_SECTION peb_lock = { &critsect_debug, -1, 0, 0, 0, 0 };
84 #ifdef __linux__
86 #ifdef HAVE_ELF_H
87 # include <elf.h>
88 #endif
89 #ifdef HAVE_LINK_H
90 # include <link.h>
91 #endif
92 #ifdef HAVE_SYS_AUXV_H
93 # include <sys/auxv.h>
94 #endif
95 #ifndef HAVE_GETAUXVAL
96 static unsigned long getauxval( unsigned long id )
98 extern char **__wine_main_environ;
99 char **ptr = __wine_main_environ;
100 ElfW(auxv_t) *auxv;
102 while (*ptr) ptr++;
103 while (!*ptr) ptr++;
104 for (auxv = (ElfW(auxv_t) *)ptr; auxv->a_type; auxv++)
105 if (auxv->a_type == id) return auxv->a_un.a_val;
106 return 0;
108 #endif
110 static ULONG_PTR get_image_addr(void)
112 ULONG_PTR size, num, phdr_addr = getauxval( AT_PHDR );
113 ElfW(Phdr) *phdr;
115 if (!phdr_addr) return 0;
116 phdr = (ElfW(Phdr) *)phdr_addr;
117 size = getauxval( AT_PHENT );
118 num = getauxval( AT_PHNUM );
119 while (num--)
121 if (phdr->p_type == PT_PHDR) return phdr_addr - phdr->p_offset;
122 phdr = (ElfW(Phdr) *)((char *)phdr + size);
124 return 0;
127 #elif defined(__APPLE__)
128 #include <mach/mach.h>
129 #include <mach/mach_error.h>
131 static ULONG_PTR get_image_addr(void)
133 ULONG_PTR ret = 0;
134 #ifdef TASK_DYLD_INFO
135 struct task_dyld_info dyld_info;
136 mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
137 if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &size) == KERN_SUCCESS)
138 ret = dyld_info.all_image_info_addr;
139 #endif
140 return ret;
143 #else
144 static ULONG_PTR get_image_addr(void)
146 return 0;
148 #endif
150 /***********************************************************************
151 * thread_init
153 * Setup the initial thread.
155 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
157 void thread_init(void)
159 TEB *teb;
160 void *addr;
161 BOOL suspend;
162 SIZE_T size, info_size;
163 LARGE_INTEGER now;
164 NTSTATUS status;
165 struct ntdll_thread_data *thread_data;
167 virtual_init();
169 /* reserve space for shared user data */
171 addr = (void *)0x7ffe0000;
172 size = 0x10000;
173 status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size,
174 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
175 if (status)
177 MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
178 exit(1);
180 user_shared_data = addr;
181 memcpy( user_shared_data->NtSystemRoot, default_windirW, sizeof(default_windirW) );
183 /* allocate and initialize the PEB */
185 addr = NULL;
186 size = sizeof(*peb);
187 virtual_alloc_aligned( &addr, 0, &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, 1 );
188 peb = addr;
190 peb->FastPebLock = &peb_lock;
191 peb->TlsBitmap = &tls_bitmap;
192 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
193 peb->FlsBitmap = &fls_bitmap;
194 peb->LdrData = &ldr;
195 peb->OSMajorVersion = 5;
196 peb->OSMinorVersion = 1;
197 peb->OSBuildNumber = 0xA28;
198 peb->OSPlatformId = VER_PLATFORM_WIN32_NT;
199 ldr.Length = sizeof(ldr);
200 ldr.Initialized = TRUE;
201 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
202 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
203 sizeof(peb->TlsExpansionBitmapBits) * 8 );
204 RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
205 RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
206 RtlSetBits( peb->FlsBitmap, 0, 1 );
207 InitializeListHead( &peb->FlsListHead );
208 InitializeListHead( &ldr.InLoadOrderModuleList );
209 InitializeListHead( &ldr.InMemoryOrderModuleList );
210 InitializeListHead( &ldr.InInitializationOrderModuleList );
211 *(ULONG_PTR *)peb->Reserved = get_image_addr();
214 * Starting with Vista, the first user to log on has session id 1.
215 * Session id 0 is for processes that don't interact with the user (like services).
217 peb->SessionId = 1;
219 /* allocate and initialize the initial TEB */
221 signal_alloc_thread( &teb );
222 teb->Peb = peb;
223 teb->Tib.StackBase = (void *)~0UL;
224 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
225 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
227 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
228 thread_data->request_fd = -1;
229 thread_data->reply_fd = -1;
230 thread_data->wait_fd[0] = -1;
231 thread_data->wait_fd[1] = -1;
233 signal_init_thread( teb );
234 virtual_init_threading();
235 debug_init();
237 /* setup the server connection */
238 server_init_process();
239 info_size = server_init_thread( peb, &suspend );
241 /* create the process heap */
242 if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
244 MESSAGE( "wine: failed to create the process heap\n" );
245 exit(1);
248 init_directories();
249 init_user_process_params( info_size );
251 /* initialize time values in user_shared_data */
252 NtQuerySystemTime( &now );
253 user_shared_data->SystemTime.LowPart = now.u.LowPart;
254 user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
255 user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
256 user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
257 user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
258 user_shared_data->TickCountMultiplier = 1 << 24;
260 fill_cpu_info();
262 NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );
266 /***********************************************************************
267 * free_thread_data
269 static void free_thread_data( TEB *teb )
271 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
272 SIZE_T size;
274 if (teb->DeallocationStack)
276 size = 0;
277 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
279 if (thread_data->start_stack)
281 size = 0;
282 NtFreeVirtualMemory( GetCurrentProcess(), &thread_data->start_stack, &size, MEM_RELEASE );
284 signal_free_thread( teb );
288 /***********************************************************************
289 * abort_thread
291 void abort_thread( int status )
293 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
294 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( get_unix_exit_code( status ));
295 signal_exit_thread( status );
299 /***********************************************************************
300 * exit_thread
302 void exit_thread( int status )
304 close( ntdll_get_thread_data()->wait_fd[0] );
305 close( ntdll_get_thread_data()->wait_fd[1] );
306 close( ntdll_get_thread_data()->reply_fd );
307 close( ntdll_get_thread_data()->request_fd );
308 pthread_exit( UIntToPtr(status) );
312 /***********************************************************************
313 * RtlExitUserThread (NTDLL.@)
315 void WINAPI RtlExitUserThread( ULONG status )
317 static void *prev_teb;
318 TEB *teb;
320 if (status) /* send the exit code to the server (0 is already the default) */
322 SERVER_START_REQ( terminate_thread )
324 req->handle = wine_server_obj_handle( GetCurrentThread() );
325 req->exit_code = status;
326 wine_server_call( req );
328 SERVER_END_REQ;
331 if (interlocked_xchg_add( &nb_threads, -1 ) <= 1)
333 LdrShutdownProcess();
334 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
335 signal_exit_process( get_unix_exit_code( status ));
338 LdrShutdownThread();
339 RtlFreeThreadActivationContextStack();
341 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
343 if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() )))
345 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
347 if (thread_data->pthread_id)
349 pthread_join( thread_data->pthread_id, NULL );
350 free_thread_data( teb );
354 signal_exit_thread( status );
358 /***********************************************************************
359 * start_thread
361 * Startup routine for a newly created thread.
363 static void start_thread( struct startup_info *info )
365 BOOL suspend;
366 TEB *teb = info->teb;
367 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
368 struct debug_info debug_info;
370 debug_info.str_pos = debug_info.out_pos = 0;
371 thread_data->debug_info = &debug_info;
372 thread_data->pthread_id = pthread_self();
374 signal_init_thread( teb );
375 server_init_thread( info->entry_point, &suspend );
376 signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend );
380 /***********************************************************************
381 * NtCreateThreadEx (NTDLL.@)
383 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle_ptr, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
384 HANDLE process, LPTHREAD_START_ROUTINE start, void *param,
385 ULONG flags, ULONG zero_bits, ULONG stack_commit,
386 ULONG stack_reserve, void *attribute_list )
388 FIXME( "%p, %x, %p, %p, %p, %p, %x, %x, %x, %x, %p semi-stub!\n", handle_ptr, access, attr,
389 process, start, param, flags, zero_bits, stack_commit, stack_reserve, attribute_list );
391 return RtlCreateUserThread( process, NULL, flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED,
392 NULL, stack_reserve, stack_commit, (PRTL_THREAD_START_ROUTINE)start,
393 param, handle_ptr, NULL );
397 /***********************************************************************
398 * RtlCreateUserThread (NTDLL.@)
400 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
401 BOOLEAN suspended, PVOID stack_addr,
402 SIZE_T stack_reserve, SIZE_T stack_commit,
403 PRTL_THREAD_START_ROUTINE start, void *param,
404 HANDLE *handle_ptr, CLIENT_ID *id )
406 sigset_t sigset;
407 pthread_t pthread_id;
408 pthread_attr_t attr;
409 struct ntdll_thread_data *thread_data;
410 struct startup_info *info;
411 HANDLE handle = 0, actctx = 0;
412 TEB *teb = NULL;
413 DWORD tid = 0;
414 int request_pipe[2];
415 NTSTATUS status;
416 SIZE_T extra_stack = PTHREAD_STACK_MIN;
417 data_size_t len = 0;
418 struct object_attributes *objattr = NULL;
419 INITIAL_TEB stack;
421 if (process != NtCurrentProcess())
423 apc_call_t call;
424 apc_result_t result;
426 memset( &call, 0, sizeof(call) );
428 call.create_thread.type = APC_CREATE_THREAD;
429 call.create_thread.func = wine_server_client_ptr( start );
430 call.create_thread.arg = wine_server_client_ptr( param );
431 call.create_thread.reserve = stack_reserve;
432 call.create_thread.commit = stack_commit;
433 call.create_thread.suspend = suspended;
434 status = server_queue_process_apc( process, &call, &result );
435 if (status != STATUS_SUCCESS) return status;
437 if (result.create_thread.status == STATUS_SUCCESS)
439 if (id) id->UniqueThread = ULongToHandle(result.create_thread.tid);
440 if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle );
441 else NtClose( wine_server_ptr_handle( result.create_thread.handle ));
443 return result.create_thread.status;
446 if (descr)
448 OBJECT_ATTRIBUTES thread_attr;
449 InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, descr );
450 if ((status = alloc_object_attributes( &thread_attr, &objattr, &len ))) return status;
453 if (server_pipe( request_pipe ) == -1)
455 RtlFreeHeap( GetProcessHeap(), 0, objattr );
456 return STATUS_TOO_MANY_OPENED_FILES;
458 wine_server_send_fd( request_pipe[0] );
460 SERVER_START_REQ( new_thread )
462 req->process = wine_server_obj_handle( process );
463 req->access = THREAD_ALL_ACCESS;
464 req->suspend = suspended;
465 req->request_fd = request_pipe[0];
466 wine_server_add_data( req, objattr, len );
467 if (!(status = wine_server_call( req )))
469 handle = wine_server_ptr_handle( reply->handle );
470 tid = reply->tid;
472 close( request_pipe[0] );
474 SERVER_END_REQ;
476 RtlFreeHeap( GetProcessHeap(), 0, objattr );
477 if (status)
479 close( request_pipe[1] );
480 return status;
483 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
485 if ((status = signal_alloc_thread( &teb ))) goto error;
487 teb->Peb = NtCurrentTeb()->Peb;
488 teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
489 teb->ClientId.UniqueThread = ULongToHandle(tid);
490 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
491 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
493 /* create default activation context frame for new thread */
494 RtlGetActiveActivationContext(&actctx);
495 if (actctx)
497 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
499 frame = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame));
500 frame->Previous = NULL;
501 frame->ActivationContext = actctx;
502 frame->Flags = 0;
503 teb->ActivationContextStack.ActiveFrame = frame;
506 info = (struct startup_info *)(teb + 1);
507 info->teb = teb;
508 info->entry_point = start;
509 info->entry_arg = param;
511 if ((status = virtual_alloc_thread_stack( &stack, stack_reserve, stack_commit, &extra_stack )))
512 goto error;
514 teb->Tib.StackBase = stack.StackBase;
515 teb->Tib.StackLimit = stack.StackLimit;
516 teb->DeallocationStack = stack.DeallocationStack;
518 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
519 thread_data->request_fd = request_pipe[1];
520 thread_data->reply_fd = -1;
521 thread_data->wait_fd[0] = -1;
522 thread_data->wait_fd[1] = -1;
523 thread_data->start_stack = (char *)teb->Tib.StackBase;
525 pthread_attr_init( &attr );
526 pthread_attr_setstack( &attr, teb->DeallocationStack,
527 (char *)teb->Tib.StackBase + extra_stack - (char *)teb->DeallocationStack );
528 pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
529 interlocked_xchg_add( &nb_threads, 1 );
530 if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, info ))
532 interlocked_xchg_add( &nb_threads, -1 );
533 pthread_attr_destroy( &attr );
534 status = STATUS_NO_MEMORY;
535 goto error;
537 pthread_attr_destroy( &attr );
538 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
540 if (id) id->UniqueThread = ULongToHandle(tid);
541 if (handle_ptr) *handle_ptr = handle;
542 else NtClose( handle );
544 return STATUS_SUCCESS;
546 error:
547 if (teb) free_thread_data( teb );
548 if (handle) NtClose( handle );
549 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
550 close( request_pipe[1] );
551 return status;
555 /******************************************************************************
556 * RtlGetNtGlobalFlags (NTDLL.@)
558 ULONG WINAPI RtlGetNtGlobalFlags(void)
560 if (!peb) return 0; /* init not done yet */
561 return peb->NtGlobalFlag;
565 /***********************************************************************
566 * NtOpenThread (NTDLL.@)
567 * ZwOpenThread (NTDLL.@)
569 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
570 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
572 NTSTATUS ret;
574 SERVER_START_REQ( open_thread )
576 req->tid = HandleToULong(id->UniqueThread);
577 req->access = access;
578 req->attributes = attr ? attr->Attributes : 0;
579 ret = wine_server_call( req );
580 *handle = wine_server_ptr_handle( reply->handle );
582 SERVER_END_REQ;
583 return ret;
587 /******************************************************************************
588 * NtSuspendThread (NTDLL.@)
589 * ZwSuspendThread (NTDLL.@)
591 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
593 NTSTATUS ret;
595 SERVER_START_REQ( suspend_thread )
597 req->handle = wine_server_obj_handle( handle );
598 if (!(ret = wine_server_call( req )))
600 if (count) *count = reply->count;
603 SERVER_END_REQ;
604 return ret;
608 /******************************************************************************
609 * NtResumeThread (NTDLL.@)
610 * ZwResumeThread (NTDLL.@)
612 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
614 NTSTATUS ret;
616 SERVER_START_REQ( resume_thread )
618 req->handle = wine_server_obj_handle( handle );
619 if (!(ret = wine_server_call( req )))
621 if (count) *count = reply->count;
624 SERVER_END_REQ;
625 return ret;
629 /******************************************************************************
630 * NtAlertResumeThread (NTDLL.@)
631 * ZwAlertResumeThread (NTDLL.@)
633 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
635 FIXME( "stub: should alert thread %p\n", handle );
636 return NtResumeThread( handle, count );
640 /******************************************************************************
641 * NtAlertThread (NTDLL.@)
642 * ZwAlertThread (NTDLL.@)
644 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
646 FIXME( "stub: %p\n", handle );
647 return STATUS_NOT_IMPLEMENTED;
651 /******************************************************************************
652 * NtTerminateThread (NTDLL.@)
653 * ZwTerminateThread (NTDLL.@)
655 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
657 NTSTATUS ret;
658 BOOL self;
660 SERVER_START_REQ( terminate_thread )
662 req->handle = wine_server_obj_handle( handle );
663 req->exit_code = exit_code;
664 ret = wine_server_call( req );
665 self = !ret && reply->self;
667 SERVER_END_REQ;
669 if (self) abort_thread( exit_code );
670 return ret;
674 /******************************************************************************
675 * NtQueueApcThread (NTDLL.@)
677 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
678 ULONG_PTR arg2, ULONG_PTR arg3 )
680 NTSTATUS ret;
681 SERVER_START_REQ( queue_apc )
683 req->handle = wine_server_obj_handle( handle );
684 if (func)
686 req->call.type = APC_USER;
687 req->call.user.func = wine_server_client_ptr( func );
688 req->call.user.args[0] = arg1;
689 req->call.user.args[1] = arg2;
690 req->call.user.args[2] = arg3;
692 else req->call.type = APC_NONE; /* wake up only */
693 ret = wine_server_call( req );
695 SERVER_END_REQ;
696 return ret;
700 /******************************************************************************
701 * RtlPushFrame (NTDLL.@)
703 void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame )
705 frame->Previous = NtCurrentTeb()->ActiveFrame;
706 NtCurrentTeb()->ActiveFrame = frame;
710 /******************************************************************************
711 * RtlPopFrame (NTDLL.@)
713 void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame )
715 NtCurrentTeb()->ActiveFrame = frame->Previous;
719 /******************************************************************************
720 * RtlGetFrame (NTDLL.@)
722 TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void)
724 return NtCurrentTeb()->ActiveFrame;
728 /***********************************************************************
729 * set_thread_context
731 NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self )
733 NTSTATUS ret;
734 DWORD dummy, i;
736 SERVER_START_REQ( set_thread_context )
738 req->handle = wine_server_obj_handle( handle );
739 req->suspend = 1;
740 wine_server_add_data( req, context, sizeof(*context) );
741 ret = wine_server_call( req );
742 *self = reply->self;
744 SERVER_END_REQ;
746 if (ret == STATUS_PENDING)
748 for (i = 0; i < 100; i++)
750 SERVER_START_REQ( set_thread_context )
752 req->handle = wine_server_obj_handle( handle );
753 req->suspend = 0;
754 wine_server_add_data( req, context, sizeof(*context) );
755 ret = wine_server_call( req );
757 SERVER_END_REQ;
758 if (ret == STATUS_PENDING)
760 LARGE_INTEGER timeout;
761 timeout.QuadPart = -10000;
762 NtDelayExecution( FALSE, &timeout );
764 else break;
766 NtResumeThread( handle, &dummy );
767 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
770 return ret;
774 /***********************************************************************
775 * get_thread_context
777 NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self )
779 NTSTATUS ret;
780 DWORD dummy, i;
782 SERVER_START_REQ( get_thread_context )
784 req->handle = wine_server_obj_handle( handle );
785 req->flags = flags;
786 req->suspend = 1;
787 wine_server_set_reply( req, context, sizeof(*context) );
788 ret = wine_server_call( req );
789 *self = reply->self;
791 SERVER_END_REQ;
793 if (ret == STATUS_PENDING)
795 for (i = 0; i < 100; i++)
797 SERVER_START_REQ( get_thread_context )
799 req->handle = wine_server_obj_handle( handle );
800 req->flags = flags;
801 req->suspend = 0;
802 wine_server_set_reply( req, context, sizeof(*context) );
803 ret = wine_server_call( req );
805 SERVER_END_REQ;
806 if (ret == STATUS_PENDING)
808 LARGE_INTEGER timeout;
809 timeout.QuadPart = -10000;
810 NtDelayExecution( FALSE, &timeout );
812 else break;
814 NtResumeThread( handle, &dummy );
815 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
817 return ret;
821 /******************************************************************************
822 * NtQueryInformationThread (NTDLL.@)
823 * ZwQueryInformationThread (NTDLL.@)
825 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
826 void *data, ULONG length, ULONG *ret_len )
828 NTSTATUS status;
830 switch(class)
832 case ThreadBasicInformation:
834 THREAD_BASIC_INFORMATION info;
835 const ULONG_PTR affinity_mask = get_system_affinity_mask();
837 SERVER_START_REQ( get_thread_info )
839 req->handle = wine_server_obj_handle( handle );
840 req->tid_in = 0;
841 if (!(status = wine_server_call( req )))
843 info.ExitStatus = reply->exit_code;
844 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
845 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
846 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
847 info.AffinityMask = reply->affinity & affinity_mask;
848 info.Priority = reply->priority;
849 info.BasePriority = reply->priority; /* FIXME */
852 SERVER_END_REQ;
853 if (status == STATUS_SUCCESS)
855 if (data) memcpy( data, &info, min( length, sizeof(info) ));
856 if (ret_len) *ret_len = min( length, sizeof(info) );
859 return status;
860 case ThreadAffinityMask:
862 const ULONG_PTR affinity_mask = get_system_affinity_mask();
863 ULONG_PTR affinity = 0;
865 SERVER_START_REQ( get_thread_info )
867 req->handle = wine_server_obj_handle( handle );
868 req->tid_in = 0;
869 if (!(status = wine_server_call( req )))
870 affinity = reply->affinity & affinity_mask;
872 SERVER_END_REQ;
873 if (status == STATUS_SUCCESS)
875 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
876 if (ret_len) *ret_len = min( length, sizeof(affinity) );
879 return status;
880 case ThreadTimes:
882 KERNEL_USER_TIMES kusrt;
884 SERVER_START_REQ( get_thread_times )
886 req->handle = wine_server_obj_handle( handle );
887 status = wine_server_call( req );
888 if (status == STATUS_SUCCESS)
890 kusrt.CreateTime.QuadPart = reply->creation_time;
891 kusrt.ExitTime.QuadPart = reply->exit_time;
894 SERVER_END_REQ;
895 if (status == STATUS_SUCCESS)
897 /* We call times(2) for kernel time or user time */
898 /* We can only (portably) do this for the current thread */
899 if (handle == GetCurrentThread())
901 struct tms time_buf;
902 long clocks_per_sec = sysconf(_SC_CLK_TCK);
904 times(&time_buf);
905 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
906 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
908 else
910 static BOOL reported = FALSE;
912 kusrt.KernelTime.QuadPart = 0;
913 kusrt.UserTime.QuadPart = 0;
914 if (reported)
915 TRACE("Cannot get kerneltime or usertime of other threads\n");
916 else
918 FIXME("Cannot get kerneltime or usertime of other threads\n");
919 reported = TRUE;
922 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
923 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
926 return status;
927 case ThreadDescriptorTableEntry:
929 #ifdef __i386__
930 THREAD_DESCRIPTOR_INFORMATION* tdi = data;
931 if (length < sizeof(*tdi))
932 status = STATUS_INFO_LENGTH_MISMATCH;
933 else if (!(tdi->Selector & 4)) /* GDT selector */
935 unsigned sel = LOWORD(tdi->Selector) & ~3; /* ignore RPL */
936 status = STATUS_SUCCESS;
937 if (!sel) /* null selector */
938 memset( &tdi->Entry, 0, sizeof(tdi->Entry) );
939 else
941 tdi->Entry.BaseLow = 0;
942 tdi->Entry.HighWord.Bits.BaseMid = 0;
943 tdi->Entry.HighWord.Bits.BaseHi = 0;
944 tdi->Entry.LimitLow = 0xffff;
945 tdi->Entry.HighWord.Bits.LimitHi = 0xf;
946 tdi->Entry.HighWord.Bits.Dpl = 3;
947 tdi->Entry.HighWord.Bits.Sys = 0;
948 tdi->Entry.HighWord.Bits.Pres = 1;
949 tdi->Entry.HighWord.Bits.Granularity = 1;
950 tdi->Entry.HighWord.Bits.Default_Big = 1;
951 tdi->Entry.HighWord.Bits.Type = 0x12;
952 tdi->Entry.HighWord.Bits.Reserved_0 = 0;
953 /* it has to be one of the system GDT selectors */
954 if (sel != (wine_get_ds() & ~3) && sel != (wine_get_ss() & ~3))
956 if (sel == (wine_get_cs() & ~3))
957 tdi->Entry.HighWord.Bits.Type |= 8; /* code segment */
958 else if (sel == (wine_get_fs() & ~3))
960 ULONG_PTR fs_base = (ULONG_PTR)NtCurrentTeb();
961 tdi->Entry.BaseLow = fs_base & 0xffff;
962 tdi->Entry.HighWord.Bits.BaseMid = (fs_base >> 16) & 0xff;
963 tdi->Entry.HighWord.Bits.BaseHi = (fs_base >> 24) & 0xff;
964 tdi->Entry.LimitLow = 0x0fff;
965 tdi->Entry.HighWord.Bits.LimitHi = 0;
966 tdi->Entry.HighWord.Bits.Granularity = 0;
968 else status = STATUS_ACCESS_DENIED;
972 else
974 SERVER_START_REQ( get_selector_entry )
976 req->handle = wine_server_obj_handle( handle );
977 req->entry = LOWORD(tdi->Selector) >> 3;
978 status = wine_server_call( req );
979 if (!status)
981 if (!(reply->flags & WINE_LDT_FLAGS_ALLOCATED))
982 status = STATUS_ACCESS_VIOLATION;
983 else
985 wine_ldt_set_base ( &tdi->Entry, (void *)reply->base );
986 wine_ldt_set_limit( &tdi->Entry, reply->limit );
987 wine_ldt_set_flags( &tdi->Entry, reply->flags );
991 SERVER_END_REQ;
993 if (status == STATUS_SUCCESS && ret_len)
994 /* yes, that's a bit strange, but it's the way it is */
995 *ret_len = sizeof(LDT_ENTRY);
996 #else
997 status = STATUS_NOT_IMPLEMENTED;
998 #endif
999 return status;
1001 case ThreadAmILastThread:
1003 SERVER_START_REQ(get_thread_info)
1005 req->handle = wine_server_obj_handle( handle );
1006 req->tid_in = 0;
1007 status = wine_server_call( req );
1008 if (status == STATUS_SUCCESS)
1010 BOOLEAN last = reply->last;
1011 if (data) memcpy( data, &last, min( length, sizeof(last) ));
1012 if (ret_len) *ret_len = min( length, sizeof(last) );
1015 SERVER_END_REQ;
1016 return status;
1018 case ThreadQuerySetWin32StartAddress:
1020 SERVER_START_REQ( get_thread_info )
1022 req->handle = wine_server_obj_handle( handle );
1023 req->tid_in = 0;
1024 status = wine_server_call( req );
1025 if (status == STATUS_SUCCESS)
1027 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1028 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1029 if (ret_len) *ret_len = min( length, sizeof(entry) );
1032 SERVER_END_REQ;
1033 return status;
1035 case ThreadGroupInformation:
1037 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1038 GROUP_AFFINITY affinity;
1040 memset(&affinity, 0, sizeof(affinity));
1041 affinity.Group = 0; /* Wine only supports max 64 processors */
1043 SERVER_START_REQ( get_thread_info )
1045 req->handle = wine_server_obj_handle( handle );
1046 req->tid_in = 0;
1047 if (!(status = wine_server_call( req )))
1048 affinity.Mask = reply->affinity & affinity_mask;
1050 SERVER_END_REQ;
1051 if (status == STATUS_SUCCESS)
1053 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1054 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1057 return status;
1058 case ThreadIsIoPending:
1059 FIXME( "ThreadIsIoPending info class not supported yet\n" );
1060 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
1061 if (!data) return STATUS_ACCESS_DENIED;
1063 *(BOOL*)data = FALSE;
1064 if (ret_len) *ret_len = sizeof(BOOL);
1065 return STATUS_SUCCESS;
1066 case ThreadPriority:
1067 case ThreadBasePriority:
1068 case ThreadImpersonationToken:
1069 case ThreadEnableAlignmentFaultFixup:
1070 case ThreadEventPair_Reusable:
1071 case ThreadZeroTlsCell:
1072 case ThreadPerformanceCount:
1073 case ThreadIdealProcessor:
1074 case ThreadPriorityBoost:
1075 case ThreadSetTlsArrayAddress:
1076 default:
1077 FIXME( "info class %d not supported yet\n", class );
1078 return STATUS_NOT_IMPLEMENTED;
1083 /******************************************************************************
1084 * NtSetInformationThread (NTDLL.@)
1085 * ZwSetInformationThread (NTDLL.@)
1087 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
1088 LPCVOID data, ULONG length )
1090 NTSTATUS status;
1091 switch(class)
1093 case ThreadZeroTlsCell:
1094 if (handle == GetCurrentThread())
1096 LIST_ENTRY *entry;
1097 DWORD index;
1099 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1100 index = *(const DWORD *)data;
1101 if (index < TLS_MINIMUM_AVAILABLE)
1103 RtlAcquirePebLock();
1104 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1106 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1107 teb->TlsSlots[index] = 0;
1109 RtlReleasePebLock();
1111 else
1113 index -= TLS_MINIMUM_AVAILABLE;
1114 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
1115 return STATUS_INVALID_PARAMETER;
1116 RtlAcquirePebLock();
1117 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1119 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1120 if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
1122 RtlReleasePebLock();
1124 return STATUS_SUCCESS;
1126 FIXME( "ZeroTlsCell not supported on other threads\n" );
1127 return STATUS_NOT_IMPLEMENTED;
1129 case ThreadImpersonationToken:
1131 const HANDLE *phToken = data;
1132 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1133 TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
1134 SERVER_START_REQ( set_thread_info )
1136 req->handle = wine_server_obj_handle( handle );
1137 req->token = wine_server_obj_handle( *phToken );
1138 req->mask = SET_THREAD_INFO_TOKEN;
1139 status = wine_server_call( req );
1141 SERVER_END_REQ;
1143 return status;
1144 case ThreadBasePriority:
1146 const DWORD *pprio = data;
1147 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1148 SERVER_START_REQ( set_thread_info )
1150 req->handle = wine_server_obj_handle( handle );
1151 req->priority = *pprio;
1152 req->mask = SET_THREAD_INFO_PRIORITY;
1153 status = wine_server_call( req );
1155 SERVER_END_REQ;
1157 return status;
1158 case ThreadAffinityMask:
1160 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1161 ULONG_PTR req_aff;
1163 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
1164 req_aff = *(const ULONG_PTR *)data & affinity_mask;
1165 if (!req_aff) return STATUS_INVALID_PARAMETER;
1167 SERVER_START_REQ( set_thread_info )
1169 req->handle = wine_server_obj_handle( handle );
1170 req->affinity = req_aff;
1171 req->mask = SET_THREAD_INFO_AFFINITY;
1172 status = wine_server_call( req );
1174 SERVER_END_REQ;
1176 return status;
1177 case ThreadHideFromDebugger:
1178 /* pretend the call succeeded to satisfy some code protectors */
1179 return STATUS_SUCCESS;
1180 case ThreadQuerySetWin32StartAddress:
1182 const PRTL_THREAD_START_ROUTINE *entry = data;
1183 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
1184 SERVER_START_REQ( set_thread_info )
1186 req->handle = wine_server_obj_handle( handle );
1187 req->mask = SET_THREAD_INFO_ENTRYPOINT;
1188 req->entry_point = wine_server_client_ptr( *entry );
1189 status = wine_server_call( req );
1191 SERVER_END_REQ;
1193 return status;
1194 case ThreadGroupInformation:
1196 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1197 const GROUP_AFFINITY *req_aff;
1199 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
1200 if (!data) return STATUS_ACCESS_VIOLATION;
1201 req_aff = data;
1203 /* On Windows the request fails if the reserved fields are set */
1204 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
1205 return STATUS_INVALID_PARAMETER;
1207 /* Wine only supports max 64 processors */
1208 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
1209 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1210 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
1211 SERVER_START_REQ( set_thread_info )
1213 req->handle = wine_server_obj_handle( handle );
1214 req->affinity = req_aff->Mask;
1215 req->mask = SET_THREAD_INFO_AFFINITY;
1216 status = wine_server_call( req );
1218 SERVER_END_REQ;
1220 return status;
1221 case ThreadBasicInformation:
1222 case ThreadTimes:
1223 case ThreadPriority:
1224 case ThreadDescriptorTableEntry:
1225 case ThreadEnableAlignmentFaultFixup:
1226 case ThreadEventPair_Reusable:
1227 case ThreadPerformanceCount:
1228 case ThreadAmILastThread:
1229 case ThreadIdealProcessor:
1230 case ThreadPriorityBoost:
1231 case ThreadSetTlsArrayAddress:
1232 case ThreadIsIoPending:
1233 default:
1234 FIXME( "info class %d not supported yet\n", class );
1235 return STATUS_NOT_IMPLEMENTED;
1239 /******************************************************************************
1240 * NtGetCurrentProcessorNumber (NTDLL.@)
1242 * Return the processor, on which the thread is running
1245 ULONG WINAPI NtGetCurrentProcessorNumber(void)
1247 ULONG processor;
1249 #if defined(__linux__) && defined(__NR_getcpu)
1250 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
1251 if (res != -1) return processor;
1252 #endif
1254 if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
1256 ULONG_PTR thread_mask, processor_mask;
1257 NTSTATUS status;
1259 status = NtQueryInformationThread(GetCurrentThread(), ThreadAffinityMask,
1260 &thread_mask, sizeof(thread_mask), NULL);
1261 if (status == STATUS_SUCCESS)
1263 for (processor = 0; processor < NtCurrentTeb()->Peb->NumberOfProcessors; processor++)
1265 processor_mask = (1 << processor);
1266 if (thread_mask & processor_mask)
1268 if (thread_mask != processor_mask)
1269 FIXME("need multicore support (%d processors)\n",
1270 NtCurrentTeb()->Peb->NumberOfProcessors);
1271 return processor;
1277 /* fallback to the first processor */
1278 return 0;