ntdll: Move the debug functions to the Unix library.
[wine.git] / dlls / ntdll / thread.c
blob2de2804f8c96644027ef49cc73971d1b721af042
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_PRCTL_H
32 # include <sys/prctl.h>
33 #endif
34 #ifdef HAVE_SYS_TIMES_H
35 #include <sys/times.h>
36 #endif
37 #ifdef HAVE_SYS_SYSCALL_H
38 #include <sys/syscall.h>
39 #endif
41 #define NONAMELESSUNION
42 #include "ntstatus.h"
43 #define WIN32_NO_STATUS
44 #include "winternl.h"
45 #include "wine/library.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
48 #include "ntdll_misc.h"
49 #include "ddk/wdm.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(thread);
54 #ifndef PTHREAD_STACK_MIN
55 #define PTHREAD_STACK_MIN 16384
56 #endif
58 struct _KUSER_SHARED_DATA *user_shared_data = NULL;
59 static size_t user_shared_data_size;
60 static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
62 void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL;
64 /* info passed to a starting thread */
65 struct startup_info
67 TEB *teb;
68 PRTL_THREAD_START_ROUTINE entry_point;
69 void *entry_arg;
72 static PEB *peb;
73 static PEB_LDR_DATA ldr;
74 static RTL_BITMAP tls_bitmap;
75 static RTL_BITMAP tls_expansion_bitmap;
76 static RTL_BITMAP fls_bitmap;
77 static int nb_threads = 1;
79 static RTL_CRITICAL_SECTION peb_lock;
80 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
82 0, 0, &peb_lock,
83 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
84 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
86 static RTL_CRITICAL_SECTION peb_lock = { &critsect_debug, -1, 0, 0, 0, 0 };
88 #ifdef __linux__
90 #ifdef HAVE_ELF_H
91 # include <elf.h>
92 #endif
93 #ifdef HAVE_LINK_H
94 # include <link.h>
95 #endif
96 #ifdef HAVE_SYS_AUXV_H
97 # include <sys/auxv.h>
98 #endif
99 #ifndef HAVE_GETAUXVAL
100 static unsigned long getauxval( unsigned long id )
102 extern char **__wine_main_environ;
103 char **ptr = __wine_main_environ;
104 ElfW(auxv_t) *auxv;
106 while (*ptr) ptr++;
107 while (!*ptr) ptr++;
108 for (auxv = (ElfW(auxv_t) *)ptr; auxv->a_type; auxv++)
109 if (auxv->a_type == id) return auxv->a_un.a_val;
110 return 0;
112 #endif
114 static ULONG_PTR get_image_addr(void)
116 ULONG_PTR size, num, phdr_addr = getauxval( AT_PHDR );
117 ElfW(Phdr) *phdr;
119 if (!phdr_addr) return 0;
120 phdr = (ElfW(Phdr) *)phdr_addr;
121 size = getauxval( AT_PHENT );
122 num = getauxval( AT_PHNUM );
123 while (num--)
125 if (phdr->p_type == PT_PHDR) return phdr_addr - phdr->p_offset;
126 phdr = (ElfW(Phdr) *)((char *)phdr + size);
128 return 0;
131 #elif defined(__APPLE__)
132 #include <mach/mach.h>
133 #include <mach/mach_error.h>
135 static ULONG_PTR get_image_addr(void)
137 ULONG_PTR ret = 0;
138 #ifdef TASK_DYLD_INFO
139 struct task_dyld_info dyld_info;
140 mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
141 if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &size) == KERN_SUCCESS)
142 ret = dyld_info.all_image_info_addr;
143 #endif
144 return ret;
147 #else
148 static ULONG_PTR get_image_addr(void)
150 return 0;
152 #endif
155 /***********************************************************************
156 * __wine_dbg_get_channel_flags (NTDLL.@)
158 * Get the flags to use for a given channel, possibly setting them too in case of lazy init
160 unsigned char __cdecl __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel )
162 return unix_funcs->dbg_get_channel_flags( channel );
165 /***********************************************************************
166 * __wine_dbg_strdup (NTDLL.@)
168 const char * __cdecl __wine_dbg_strdup( const char *str )
170 return unix_funcs->dbg_strdup( str );
173 /***********************************************************************
174 * __wine_dbg_header (NTDLL.@)
176 int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
177 const char *function )
179 return unix_funcs->dbg_header( cls, channel, function );
182 /***********************************************************************
183 * __wine_dbg_output (NTDLL.@)
185 int __cdecl __wine_dbg_output( const char *str )
187 return unix_funcs->dbg_output( str );
190 /***********************************************************************
191 * set_process_name
193 * Change the process name in the ps output.
195 static void set_process_name( int argc, char *argv[] )
197 BOOL shift_strings;
198 char *p, *name;
199 int i;
201 #ifdef HAVE_SETPROCTITLE
202 setproctitle("-%s", argv[1]);
203 shift_strings = FALSE;
204 #else
205 p = argv[0];
207 shift_strings = (argc >= 2);
208 for (i = 1; i < argc; i++)
210 p += strlen(p) + 1;
211 if (p != argv[i])
213 shift_strings = FALSE;
214 break;
217 #endif
219 if (shift_strings)
221 int offset = argv[1] - argv[0];
222 char *end = argv[argc-1] + strlen(argv[argc-1]) + 1;
223 memmove( argv[0], argv[1], end - argv[1] );
224 memset( end - offset, 0, offset );
225 for (i = 1; i < argc; i++)
226 argv[i-1] = argv[i] - offset;
227 argv[i-1] = NULL;
229 else
231 /* remove argv[0] */
232 memmove( argv, argv + 1, argc * sizeof(argv[0]) );
235 name = argv[0];
236 if ((p = strrchr( name, '\\' ))) name = p + 1;
237 if ((p = strrchr( name, '/' ))) name = p + 1;
239 #if defined(HAVE_SETPROGNAME)
240 setprogname( name );
241 #endif
243 #ifdef HAVE_PRCTL
244 #ifndef PR_SET_NAME
245 # define PR_SET_NAME 15
246 #endif
247 prctl( PR_SET_NAME, name );
248 #endif /* HAVE_PRCTL */
251 HANDLE user_shared_data_init_done(void)
253 static const WCHAR wine_usdW[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
254 '\\','_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a',0};
255 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
256 UNICODE_STRING wine_usd_str;
257 LARGE_INTEGER section_size;
258 NTSTATUS status;
259 HANDLE section;
260 SIZE_T size;
261 void *addr;
262 ULONG old_prot;
263 int res, fd, needs_close;
265 section_size.HighPart = 0;
266 section_size.LowPart = user_shared_data_size;
268 RtlInitUnicodeString( &wine_usd_str, wine_usdW );
269 InitializeObjectAttributes( &attr, &wine_usd_str, OBJ_OPENIF, NULL, NULL );
270 if ((status = NtCreateSection( &section, SECTION_ALL_ACCESS, &attr,
271 &section_size, PAGE_READWRITE, SEC_COMMIT, NULL )) &&
272 status != STATUS_OBJECT_NAME_EXISTS)
274 MESSAGE( "wine: failed to create or open the USD section: %08x\n", status );
275 exit(1);
278 if (status != STATUS_OBJECT_NAME_EXISTS)
280 addr = NULL;
281 size = user_shared_data_size;
283 if ((status = NtMapViewOfSection( section, NtCurrentProcess(), &addr, 0, 0, 0,
284 &size, 0, 0, PAGE_READWRITE )))
286 MESSAGE( "wine: failed to initialize the USD section: %08x\n", status );
287 exit(1);
290 memcpy( addr, user_shared_data, user_shared_data_size );
291 NtUnmapViewOfSection( NtCurrentProcess(), addr );
294 addr = user_shared_data;
295 size = user_shared_data_size;
296 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READONLY, &old_prot );
298 if ((res = server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) ||
299 (user_shared_data != mmap( user_shared_data, user_shared_data_size,
300 PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0 )))
302 MESSAGE( "wine: failed to remap the process USD: %d\n", res );
303 exit(1);
305 if (needs_close) close( fd );
307 return section;
310 /***********************************************************************
311 * thread_init
313 * Setup the initial thread.
315 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
317 TEB *thread_init(void)
319 SYSTEM_BASIC_INFORMATION sbi;
320 TEB *teb;
321 void *addr;
322 SIZE_T size;
323 LARGE_INTEGER now;
324 NTSTATUS status;
325 struct ntdll_thread_data *thread_data;
327 virtual_init();
329 /* reserve space for shared user data */
331 addr = (void *)0x7ffe0000;
332 size = 0x1000;
333 status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size,
334 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
335 if (status)
337 MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
338 exit(1);
340 user_shared_data = addr;
341 user_shared_data_size = size;
342 memcpy( user_shared_data->NtSystemRoot, default_windirW, sizeof(default_windirW) );
344 /* allocate and initialize the PEB and initial TEB */
346 teb = virtual_alloc_first_teb();
347 peb = teb->Peb;
348 peb->FastPebLock = &peb_lock;
349 peb->TlsBitmap = &tls_bitmap;
350 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
351 peb->FlsBitmap = &fls_bitmap;
352 peb->LdrData = &ldr;
353 peb->OSMajorVersion = 5;
354 peb->OSMinorVersion = 1;
355 peb->OSBuildNumber = 0xA28;
356 peb->OSPlatformId = VER_PLATFORM_WIN32_NT;
357 ldr.Length = sizeof(ldr);
358 ldr.Initialized = TRUE;
359 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
360 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
361 sizeof(peb->TlsExpansionBitmapBits) * 8 );
362 RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
363 RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
364 RtlSetBits( peb->FlsBitmap, 0, 1 );
365 InitializeListHead( &peb->FlsListHead );
366 InitializeListHead( &ldr.InLoadOrderModuleList );
367 InitializeListHead( &ldr.InMemoryOrderModuleList );
368 InitializeListHead( &ldr.InInitializationOrderModuleList );
369 *(ULONG_PTR *)peb->Reserved = get_image_addr();
372 * Starting with Vista, the first user to log on has session id 1.
373 * Session id 0 is for processes that don't interact with the user (like services).
375 peb->SessionId = 1;
377 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
378 thread_data->request_fd = -1;
379 thread_data->reply_fd = -1;
380 thread_data->wait_fd[0] = -1;
381 thread_data->wait_fd[1] = -1;
383 unix_funcs->dbg_init();
384 init_paths();
385 set_process_name( __wine_main_argc, __wine_main_argv );
387 /* initialize time values in user_shared_data */
388 NtQuerySystemTime( &now );
389 user_shared_data->SystemTime.LowPart = now.u.LowPart;
390 user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
391 user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
392 user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
393 user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
394 user_shared_data->TickCountMultiplier = 1 << 24;
395 fill_cpu_info();
397 virtual_get_system_info( &sbi );
398 user_shared_data->NumberOfPhysicalPages = sbi.MmNumberOfPhysicalPages;
400 return teb;
404 /***********************************************************************
405 * abort_thread
407 void abort_thread( int status )
409 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
410 if (InterlockedDecrement( &nb_threads ) <= 0) _exit( get_unix_exit_code( status ));
411 signal_exit_thread( status );
415 /***********************************************************************
416 * exit_thread
418 void exit_thread( int status )
420 close( ntdll_get_thread_data()->wait_fd[0] );
421 close( ntdll_get_thread_data()->wait_fd[1] );
422 close( ntdll_get_thread_data()->reply_fd );
423 close( ntdll_get_thread_data()->request_fd );
424 pthread_exit( UIntToPtr(status) );
428 /***********************************************************************
429 * RtlExitUserThread (NTDLL.@)
431 void WINAPI RtlExitUserThread( ULONG status )
433 static void *prev_teb;
434 TEB *teb;
436 if (status) /* send the exit code to the server (0 is already the default) */
438 SERVER_START_REQ( terminate_thread )
440 req->handle = wine_server_obj_handle( GetCurrentThread() );
441 req->exit_code = status;
442 wine_server_call( req );
444 SERVER_END_REQ;
447 if (InterlockedDecrement( &nb_threads ) <= 0)
449 LdrShutdownProcess();
450 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
451 signal_exit_process( get_unix_exit_code( status ));
454 LdrShutdownThread();
455 RtlFreeThreadActivationContextStack();
457 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
459 if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() )))
461 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
463 if (thread_data->pthread_id)
465 pthread_join( thread_data->pthread_id, NULL );
466 virtual_free_teb( teb );
470 signal_exit_thread( status );
474 /***********************************************************************
475 * start_thread
477 * Startup routine for a newly created thread.
479 static void start_thread( struct startup_info *info )
481 BOOL suspend;
482 TEB *teb = info->teb;
483 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
484 struct debug_info debug_info;
486 debug_info.str_pos = debug_info.out_pos = 0;
487 thread_data->debug_info = &debug_info;
488 thread_data->pthread_id = pthread_self();
490 signal_init_thread( teb );
491 server_init_thread( info->entry_point, &suspend );
492 signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend );
496 /***********************************************************************
497 * NtCreateThreadEx (NTDLL.@)
499 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle_ptr, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
500 HANDLE process, LPTHREAD_START_ROUTINE start, void *param,
501 ULONG flags, ULONG zero_bits, ULONG stack_commit,
502 ULONG stack_reserve, void *attribute_list )
504 FIXME( "%p, %x, %p, %p, %p, %p, %x, %x, %x, %x, %p semi-stub!\n", handle_ptr, access, attr,
505 process, start, param, flags, zero_bits, stack_commit, stack_reserve, attribute_list );
507 return RtlCreateUserThread( process, NULL, flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED,
508 NULL, stack_reserve, stack_commit, (PRTL_THREAD_START_ROUTINE)start,
509 param, handle_ptr, NULL );
513 /***********************************************************************
514 * RtlCreateUserThread (NTDLL.@)
516 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
517 BOOLEAN suspended, PVOID stack_addr,
518 SIZE_T stack_reserve, SIZE_T stack_commit,
519 PRTL_THREAD_START_ROUTINE start, void *param,
520 HANDLE *handle_ptr, CLIENT_ID *id )
522 sigset_t sigset;
523 pthread_t pthread_id;
524 pthread_attr_t attr;
525 struct ntdll_thread_data *thread_data;
526 struct startup_info *info;
527 HANDLE handle = 0, actctx = 0;
528 TEB *teb = NULL;
529 DWORD tid = 0;
530 int request_pipe[2];
531 NTSTATUS status;
532 SIZE_T extra_stack = PTHREAD_STACK_MIN;
533 data_size_t len = 0;
534 struct object_attributes *objattr = NULL;
535 INITIAL_TEB stack;
537 if (process != NtCurrentProcess())
539 apc_call_t call;
540 apc_result_t result;
542 memset( &call, 0, sizeof(call) );
544 call.create_thread.type = APC_CREATE_THREAD;
545 call.create_thread.func = wine_server_client_ptr( start );
546 call.create_thread.arg = wine_server_client_ptr( param );
547 call.create_thread.reserve = stack_reserve;
548 call.create_thread.commit = stack_commit;
549 call.create_thread.suspend = suspended;
550 status = server_queue_process_apc( process, &call, &result );
551 if (status != STATUS_SUCCESS) return status;
553 if (result.create_thread.status == STATUS_SUCCESS)
555 if (id) id->UniqueThread = ULongToHandle(result.create_thread.tid);
556 if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle );
557 else NtClose( wine_server_ptr_handle( result.create_thread.handle ));
559 return result.create_thread.status;
562 if (descr)
564 OBJECT_ATTRIBUTES thread_attr;
565 InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, descr );
566 if ((status = alloc_object_attributes( &thread_attr, &objattr, &len ))) return status;
569 if (server_pipe( request_pipe ) == -1)
571 RtlFreeHeap( GetProcessHeap(), 0, objattr );
572 return STATUS_TOO_MANY_OPENED_FILES;
574 wine_server_send_fd( request_pipe[0] );
576 SERVER_START_REQ( new_thread )
578 req->process = wine_server_obj_handle( process );
579 req->access = THREAD_ALL_ACCESS;
580 req->suspend = suspended;
581 req->request_fd = request_pipe[0];
582 wine_server_add_data( req, objattr, len );
583 if (!(status = wine_server_call( req )))
585 handle = wine_server_ptr_handle( reply->handle );
586 tid = reply->tid;
588 close( request_pipe[0] );
590 SERVER_END_REQ;
592 RtlFreeHeap( GetProcessHeap(), 0, objattr );
593 if (status)
595 close( request_pipe[1] );
596 return status;
599 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
601 if ((status = virtual_alloc_teb( &teb ))) goto error;
603 teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
604 teb->ClientId.UniqueThread = ULongToHandle(tid);
606 /* create default activation context frame for new thread */
607 RtlGetActiveActivationContext(&actctx);
608 if (actctx)
610 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
612 frame = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame));
613 frame->Previous = NULL;
614 frame->ActivationContext = actctx;
615 frame->Flags = 0;
616 teb->ActivationContextStack.ActiveFrame = frame;
619 info = (struct startup_info *)(teb + 1);
620 info->teb = teb;
621 info->entry_point = start;
622 info->entry_arg = param;
624 if ((status = virtual_alloc_thread_stack( &stack, stack_reserve, stack_commit, &extra_stack )))
625 goto error;
627 teb->Tib.StackBase = stack.StackBase;
628 teb->Tib.StackLimit = stack.StackLimit;
629 teb->DeallocationStack = stack.DeallocationStack;
631 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
632 thread_data->request_fd = request_pipe[1];
633 thread_data->reply_fd = -1;
634 thread_data->wait_fd[0] = -1;
635 thread_data->wait_fd[1] = -1;
636 thread_data->start_stack = (char *)teb->Tib.StackBase;
638 pthread_attr_init( &attr );
639 pthread_attr_setstack( &attr, teb->DeallocationStack,
640 (char *)teb->Tib.StackBase + extra_stack - (char *)teb->DeallocationStack );
641 pthread_attr_setguardsize( &attr, 0 );
642 pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
643 InterlockedIncrement( &nb_threads );
644 if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, info ))
646 InterlockedDecrement( &nb_threads );
647 pthread_attr_destroy( &attr );
648 status = STATUS_NO_MEMORY;
649 goto error;
651 pthread_attr_destroy( &attr );
652 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
654 if (id) id->UniqueThread = ULongToHandle(tid);
655 if (handle_ptr) *handle_ptr = handle;
656 else NtClose( handle );
658 return STATUS_SUCCESS;
660 error:
661 if (teb) virtual_free_teb( teb );
662 if (handle) NtClose( handle );
663 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
664 close( request_pipe[1] );
665 return status;
669 /******************************************************************************
670 * RtlGetNtGlobalFlags (NTDLL.@)
672 ULONG WINAPI RtlGetNtGlobalFlags(void)
674 if (!peb) return 0; /* init not done yet */
675 return peb->NtGlobalFlag;
679 /***********************************************************************
680 * NtOpenThread (NTDLL.@)
681 * ZwOpenThread (NTDLL.@)
683 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
684 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
686 NTSTATUS ret;
688 SERVER_START_REQ( open_thread )
690 req->tid = HandleToULong(id->UniqueThread);
691 req->access = access;
692 req->attributes = attr ? attr->Attributes : 0;
693 ret = wine_server_call( req );
694 *handle = wine_server_ptr_handle( reply->handle );
696 SERVER_END_REQ;
697 return ret;
701 /******************************************************************************
702 * NtSuspendThread (NTDLL.@)
703 * ZwSuspendThread (NTDLL.@)
705 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
707 NTSTATUS ret;
709 SERVER_START_REQ( suspend_thread )
711 req->handle = wine_server_obj_handle( handle );
712 if (!(ret = wine_server_call( req )))
714 if (count) *count = reply->count;
717 SERVER_END_REQ;
718 return ret;
722 /******************************************************************************
723 * NtResumeThread (NTDLL.@)
724 * ZwResumeThread (NTDLL.@)
726 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
728 NTSTATUS ret;
730 SERVER_START_REQ( resume_thread )
732 req->handle = wine_server_obj_handle( handle );
733 if (!(ret = wine_server_call( req )))
735 if (count) *count = reply->count;
738 SERVER_END_REQ;
739 return ret;
743 /******************************************************************************
744 * NtAlertResumeThread (NTDLL.@)
745 * ZwAlertResumeThread (NTDLL.@)
747 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
749 FIXME( "stub: should alert thread %p\n", handle );
750 return NtResumeThread( handle, count );
754 /******************************************************************************
755 * NtAlertThread (NTDLL.@)
756 * ZwAlertThread (NTDLL.@)
758 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
760 FIXME( "stub: %p\n", handle );
761 return STATUS_NOT_IMPLEMENTED;
765 /******************************************************************************
766 * NtTerminateThread (NTDLL.@)
767 * ZwTerminateThread (NTDLL.@)
769 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
771 NTSTATUS ret;
772 BOOL self;
774 SERVER_START_REQ( terminate_thread )
776 req->handle = wine_server_obj_handle( handle );
777 req->exit_code = exit_code;
778 ret = wine_server_call( req );
779 self = !ret && reply->self;
781 SERVER_END_REQ;
783 if (self) abort_thread( exit_code );
784 return ret;
788 /******************************************************************************
789 * NtQueueApcThread (NTDLL.@)
791 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
792 ULONG_PTR arg2, ULONG_PTR arg3 )
794 NTSTATUS ret;
795 SERVER_START_REQ( queue_apc )
797 req->handle = wine_server_obj_handle( handle );
798 if (func)
800 req->call.type = APC_USER;
801 req->call.user.user.func = wine_server_client_ptr( func );
802 req->call.user.user.args[0] = arg1;
803 req->call.user.user.args[1] = arg2;
804 req->call.user.user.args[2] = arg3;
806 else req->call.type = APC_NONE; /* wake up only */
807 ret = wine_server_call( req );
809 SERVER_END_REQ;
810 return ret;
814 /******************************************************************************
815 * RtlPushFrame (NTDLL.@)
817 void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame )
819 frame->Previous = NtCurrentTeb()->ActiveFrame;
820 NtCurrentTeb()->ActiveFrame = frame;
824 /******************************************************************************
825 * RtlPopFrame (NTDLL.@)
827 void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame )
829 NtCurrentTeb()->ActiveFrame = frame->Previous;
833 /******************************************************************************
834 * RtlGetFrame (NTDLL.@)
836 TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void)
838 return NtCurrentTeb()->ActiveFrame;
842 /***********************************************************************
843 * set_thread_context
845 NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self )
847 NTSTATUS ret;
849 SERVER_START_REQ( set_thread_context )
851 req->handle = wine_server_obj_handle( handle );
852 wine_server_add_data( req, context, sizeof(*context) );
853 ret = wine_server_call( req );
854 *self = reply->self;
856 SERVER_END_REQ;
858 return ret;
862 /***********************************************************************
863 * get_thread_context
865 NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self )
867 NTSTATUS ret;
869 SERVER_START_REQ( get_thread_context )
871 req->handle = wine_server_obj_handle( handle );
872 req->flags = flags;
873 wine_server_set_reply( req, context, sizeof(*context) );
874 ret = wine_server_call( req );
875 *self = reply->self;
876 handle = wine_server_ptr_handle( reply->handle );
878 SERVER_END_REQ;
880 if (ret == STATUS_PENDING)
882 LARGE_INTEGER timeout;
883 timeout.QuadPart = -1000000;
884 if (NtWaitForSingleObject( handle, FALSE, &timeout ))
886 NtClose( handle );
887 return STATUS_ACCESS_DENIED;
889 SERVER_START_REQ( get_thread_context )
891 req->handle = wine_server_obj_handle( handle );
892 req->flags = flags;
893 wine_server_set_reply( req, context, sizeof(*context) );
894 ret = wine_server_call( req );
896 SERVER_END_REQ;
898 return ret;
902 /******************************************************************************
903 * NtQueryInformationThread (NTDLL.@)
904 * ZwQueryInformationThread (NTDLL.@)
906 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
907 void *data, ULONG length, ULONG *ret_len )
909 NTSTATUS status;
911 switch(class)
913 case ThreadBasicInformation:
915 THREAD_BASIC_INFORMATION info;
916 const ULONG_PTR affinity_mask = get_system_affinity_mask();
918 SERVER_START_REQ( get_thread_info )
920 req->handle = wine_server_obj_handle( handle );
921 req->tid_in = 0;
922 if (!(status = wine_server_call( req )))
924 info.ExitStatus = reply->exit_code;
925 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
926 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
927 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
928 info.AffinityMask = reply->affinity & affinity_mask;
929 info.Priority = reply->priority;
930 info.BasePriority = reply->priority; /* FIXME */
933 SERVER_END_REQ;
934 if (status == STATUS_SUCCESS)
936 if (data) memcpy( data, &info, min( length, sizeof(info) ));
937 if (ret_len) *ret_len = min( length, sizeof(info) );
940 return status;
941 case ThreadAffinityMask:
943 const ULONG_PTR affinity_mask = get_system_affinity_mask();
944 ULONG_PTR affinity = 0;
946 SERVER_START_REQ( get_thread_info )
948 req->handle = wine_server_obj_handle( handle );
949 req->tid_in = 0;
950 if (!(status = wine_server_call( req )))
951 affinity = reply->affinity & affinity_mask;
953 SERVER_END_REQ;
954 if (status == STATUS_SUCCESS)
956 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
957 if (ret_len) *ret_len = min( length, sizeof(affinity) );
960 return status;
961 case ThreadTimes:
963 KERNEL_USER_TIMES kusrt;
965 SERVER_START_REQ( get_thread_times )
967 req->handle = wine_server_obj_handle( handle );
968 status = wine_server_call( req );
969 if (status == STATUS_SUCCESS)
971 kusrt.CreateTime.QuadPart = reply->creation_time;
972 kusrt.ExitTime.QuadPart = reply->exit_time;
975 SERVER_END_REQ;
976 if (status == STATUS_SUCCESS)
978 /* We call times(2) for kernel time or user time */
979 /* We can only (portably) do this for the current thread */
980 if (handle == GetCurrentThread())
982 struct tms time_buf;
983 long clocks_per_sec = sysconf(_SC_CLK_TCK);
985 times(&time_buf);
986 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
987 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
989 else
991 static BOOL reported = FALSE;
993 kusrt.KernelTime.QuadPart = 0;
994 kusrt.UserTime.QuadPart = 0;
995 if (reported)
996 TRACE("Cannot get kerneltime or usertime of other threads\n");
997 else
999 FIXME("Cannot get kerneltime or usertime of other threads\n");
1000 reported = TRUE;
1003 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1004 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1007 return status;
1009 case ThreadDescriptorTableEntry:
1010 return get_thread_ldt_entry( handle, data, length, ret_len );
1012 case ThreadAmILastThread:
1014 SERVER_START_REQ(get_thread_info)
1016 req->handle = wine_server_obj_handle( handle );
1017 req->tid_in = 0;
1018 status = wine_server_call( req );
1019 if (status == STATUS_SUCCESS)
1021 BOOLEAN last = reply->last;
1022 if (data) memcpy( data, &last, min( length, sizeof(last) ));
1023 if (ret_len) *ret_len = min( length, sizeof(last) );
1026 SERVER_END_REQ;
1027 return status;
1029 case ThreadQuerySetWin32StartAddress:
1031 SERVER_START_REQ( get_thread_info )
1033 req->handle = wine_server_obj_handle( handle );
1034 req->tid_in = 0;
1035 status = wine_server_call( req );
1036 if (status == STATUS_SUCCESS)
1038 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1039 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1040 if (ret_len) *ret_len = min( length, sizeof(entry) );
1043 SERVER_END_REQ;
1044 return status;
1046 case ThreadGroupInformation:
1048 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1049 GROUP_AFFINITY affinity;
1051 memset(&affinity, 0, sizeof(affinity));
1052 affinity.Group = 0; /* Wine only supports max 64 processors */
1054 SERVER_START_REQ( get_thread_info )
1056 req->handle = wine_server_obj_handle( handle );
1057 req->tid_in = 0;
1058 if (!(status = wine_server_call( req )))
1059 affinity.Mask = reply->affinity & affinity_mask;
1061 SERVER_END_REQ;
1062 if (status == STATUS_SUCCESS)
1064 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1065 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1068 return status;
1069 case ThreadIsIoPending:
1070 FIXME( "ThreadIsIoPending info class not supported yet\n" );
1071 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
1072 if (!data) return STATUS_ACCESS_DENIED;
1074 *(BOOL*)data = FALSE;
1075 if (ret_len) *ret_len = sizeof(BOOL);
1076 return STATUS_SUCCESS;
1077 case ThreadSuspendCount:
1079 ULONG count = 0;
1081 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
1082 if (!data) return STATUS_ACCESS_VIOLATION;
1084 SERVER_START_REQ( get_thread_info )
1086 req->handle = wine_server_obj_handle( handle );
1087 req->tid_in = 0;
1088 if (!(status = wine_server_call( req )))
1089 count = reply->suspend_count;
1091 SERVER_END_REQ;
1093 if (!status)
1094 *(ULONG *)data = count;
1096 return status;
1098 case ThreadDescription:
1100 THREAD_DESCRIPTION_INFORMATION *info = data;
1101 data_size_t len, desc_len = 0;
1102 WCHAR *ptr;
1104 len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
1105 ptr = info ? (WCHAR *)(info + 1) : NULL;
1107 SERVER_START_REQ( get_thread_info )
1109 req->handle = wine_server_obj_handle( handle );
1110 if (ptr) wine_server_set_reply( req, ptr, len );
1111 status = wine_server_call( req );
1112 desc_len = reply->desc_len;
1114 SERVER_END_REQ;
1116 if (!info)
1117 status = STATUS_BUFFER_TOO_SMALL;
1118 else if (status == STATUS_SUCCESS)
1120 info->Description.Length = info->Description.MaximumLength = desc_len;
1121 info->Description.Buffer = ptr;
1124 if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
1125 *ret_len = sizeof(*info) + desc_len;
1127 return status;
1128 case ThreadPriority:
1129 case ThreadBasePriority:
1130 case ThreadImpersonationToken:
1131 case ThreadEnableAlignmentFaultFixup:
1132 case ThreadEventPair_Reusable:
1133 case ThreadZeroTlsCell:
1134 case ThreadPerformanceCount:
1135 case ThreadIdealProcessor:
1136 case ThreadPriorityBoost:
1137 case ThreadSetTlsArrayAddress:
1138 default:
1139 FIXME( "info class %d not supported yet\n", class );
1140 return STATUS_NOT_IMPLEMENTED;
1145 /******************************************************************************
1146 * NtSetInformationThread (NTDLL.@)
1147 * ZwSetInformationThread (NTDLL.@)
1149 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
1150 LPCVOID data, ULONG length )
1152 NTSTATUS status;
1153 switch(class)
1155 case ThreadZeroTlsCell:
1156 if (handle == GetCurrentThread())
1158 LIST_ENTRY *entry;
1159 DWORD index;
1161 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1162 index = *(const DWORD *)data;
1163 if (index < TLS_MINIMUM_AVAILABLE)
1165 RtlAcquirePebLock();
1166 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1168 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1169 teb->TlsSlots[index] = 0;
1171 RtlReleasePebLock();
1173 else
1175 index -= TLS_MINIMUM_AVAILABLE;
1176 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
1177 return STATUS_INVALID_PARAMETER;
1178 RtlAcquirePebLock();
1179 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1181 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
1182 if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
1184 RtlReleasePebLock();
1186 return STATUS_SUCCESS;
1188 FIXME( "ZeroTlsCell not supported on other threads\n" );
1189 return STATUS_NOT_IMPLEMENTED;
1191 case ThreadImpersonationToken:
1193 const HANDLE *phToken = data;
1194 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1195 TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
1196 SERVER_START_REQ( set_thread_info )
1198 req->handle = wine_server_obj_handle( handle );
1199 req->token = wine_server_obj_handle( *phToken );
1200 req->mask = SET_THREAD_INFO_TOKEN;
1201 status = wine_server_call( req );
1203 SERVER_END_REQ;
1205 return status;
1206 case ThreadBasePriority:
1208 const DWORD *pprio = data;
1209 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1210 SERVER_START_REQ( set_thread_info )
1212 req->handle = wine_server_obj_handle( handle );
1213 req->priority = *pprio;
1214 req->mask = SET_THREAD_INFO_PRIORITY;
1215 status = wine_server_call( req );
1217 SERVER_END_REQ;
1219 return status;
1220 case ThreadAffinityMask:
1222 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1223 ULONG_PTR req_aff;
1225 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
1226 req_aff = *(const ULONG_PTR *)data & affinity_mask;
1227 if (!req_aff) return STATUS_INVALID_PARAMETER;
1229 SERVER_START_REQ( set_thread_info )
1231 req->handle = wine_server_obj_handle( handle );
1232 req->affinity = req_aff;
1233 req->mask = SET_THREAD_INFO_AFFINITY;
1234 status = wine_server_call( req );
1236 SERVER_END_REQ;
1238 return status;
1239 case ThreadHideFromDebugger:
1240 /* pretend the call succeeded to satisfy some code protectors */
1241 return STATUS_SUCCESS;
1242 case ThreadQuerySetWin32StartAddress:
1244 const PRTL_THREAD_START_ROUTINE *entry = data;
1245 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
1246 SERVER_START_REQ( set_thread_info )
1248 req->handle = wine_server_obj_handle( handle );
1249 req->mask = SET_THREAD_INFO_ENTRYPOINT;
1250 req->entry_point = wine_server_client_ptr( *entry );
1251 status = wine_server_call( req );
1253 SERVER_END_REQ;
1255 return status;
1256 case ThreadGroupInformation:
1258 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1259 const GROUP_AFFINITY *req_aff;
1261 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
1262 if (!data) return STATUS_ACCESS_VIOLATION;
1263 req_aff = data;
1265 /* On Windows the request fails if the reserved fields are set */
1266 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
1267 return STATUS_INVALID_PARAMETER;
1269 /* Wine only supports max 64 processors */
1270 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
1271 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1272 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
1273 SERVER_START_REQ( set_thread_info )
1275 req->handle = wine_server_obj_handle( handle );
1276 req->affinity = req_aff->Mask;
1277 req->mask = SET_THREAD_INFO_AFFINITY;
1278 status = wine_server_call( req );
1280 SERVER_END_REQ;
1282 return status;
1283 case ThreadDescription:
1285 const THREAD_DESCRIPTION_INFORMATION *info = data;
1287 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
1288 if (!info) return STATUS_ACCESS_VIOLATION;
1290 if (info->Description.Length != info->Description.MaximumLength) return STATUS_INVALID_PARAMETER;
1291 if (info->Description.Length && !info->Description.Buffer) return STATUS_ACCESS_VIOLATION;
1293 SERVER_START_REQ( set_thread_info )
1295 req->handle = wine_server_obj_handle( handle );
1296 req->mask = SET_THREAD_INFO_DESCRIPTION;
1297 wine_server_add_data( req, info->Description.Buffer, info->Description.Length );
1298 status = wine_server_call( req );
1300 SERVER_END_REQ;
1302 return status;
1303 case ThreadBasicInformation:
1304 case ThreadTimes:
1305 case ThreadPriority:
1306 case ThreadDescriptorTableEntry:
1307 case ThreadEnableAlignmentFaultFixup:
1308 case ThreadEventPair_Reusable:
1309 case ThreadPerformanceCount:
1310 case ThreadAmILastThread:
1311 case ThreadIdealProcessor:
1312 case ThreadPriorityBoost:
1313 case ThreadSetTlsArrayAddress:
1314 case ThreadIsIoPending:
1315 default:
1316 FIXME( "info class %d not supported yet\n", class );
1317 return STATUS_NOT_IMPLEMENTED;
1321 /******************************************************************************
1322 * NtGetCurrentProcessorNumber (NTDLL.@)
1324 * Return the processor, on which the thread is running
1327 ULONG WINAPI NtGetCurrentProcessorNumber(void)
1329 ULONG processor;
1331 #if defined(__linux__) && defined(__NR_getcpu)
1332 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
1333 if (res != -1) return processor;
1334 #endif
1336 if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
1338 ULONG_PTR thread_mask, processor_mask;
1339 NTSTATUS status;
1341 status = NtQueryInformationThread(GetCurrentThread(), ThreadAffinityMask,
1342 &thread_mask, sizeof(thread_mask), NULL);
1343 if (status == STATUS_SUCCESS)
1345 for (processor = 0; processor < NtCurrentTeb()->Peb->NumberOfProcessors; processor++)
1347 processor_mask = (1 << processor);
1348 if (thread_mask & processor_mask)
1350 if (thread_mask != processor_mask)
1351 FIXME("need multicore support (%d processors)\n",
1352 NtCurrentTeb()->Peb->NumberOfProcessors);
1353 return processor;
1359 /* fallback to the first processor */
1360 return 0;