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"
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_MMAN_H
31 #ifdef HAVE_SYS_PRCTL_H
32 # include <sys/prctl.h>
34 #ifdef HAVE_SYS_TIMES_H
35 #include <sys/times.h>
37 #ifdef HAVE_SYS_SYSCALL_H
38 #include <sys/syscall.h>
41 #define NONAMELESSUNION
43 #define WIN32_NO_STATUS
45 #include "wine/library.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
48 #include "ntdll_misc.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(thread
);
54 #ifndef PTHREAD_STACK_MIN
55 #define PTHREAD_STACK_MIN 16384
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 */
68 PRTL_THREAD_START_ROUTINE entry_point
;
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
=
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 };
96 #ifdef HAVE_SYS_AUXV_H
97 # include <sys/auxv.h>
99 #ifndef HAVE_GETAUXVAL
100 static unsigned long getauxval( unsigned long id
)
102 extern char **__wine_main_environ
;
103 char **ptr
= __wine_main_environ
;
108 for (auxv
= (ElfW(auxv_t
) *)ptr
; auxv
->a_type
; auxv
++)
109 if (auxv
->a_type
== id
) return auxv
->a_un
.a_val
;
114 static ULONG_PTR
get_image_addr(void)
116 ULONG_PTR size
, num
, phdr_addr
= getauxval( AT_PHDR
);
119 if (!phdr_addr
) return 0;
120 phdr
= (ElfW(Phdr
) *)phdr_addr
;
121 size
= getauxval( AT_PHENT
);
122 num
= getauxval( AT_PHNUM
);
125 if (phdr
->p_type
== PT_PHDR
) return phdr_addr
- phdr
->p_offset
;
126 phdr
= (ElfW(Phdr
) *)((char *)phdr
+ size
);
131 #elif defined(__APPLE__)
132 #include <mach/mach.h>
133 #include <mach/mach_error.h>
135 static ULONG_PTR
get_image_addr(void)
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
;
148 static ULONG_PTR
get_image_addr(void)
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 /***********************************************************************
193 * Change the process name in the ps output.
195 static void set_process_name( int argc
, char *argv
[] )
201 #ifdef HAVE_SETPROCTITLE
202 setproctitle("-%s", argv
[1]);
203 shift_strings
= FALSE
;
207 shift_strings
= (argc
>= 2);
208 for (i
= 1; i
< argc
; i
++)
213 shift_strings
= FALSE
;
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
;
232 memmove( argv
, argv
+ 1, argc
* sizeof(argv
[0]) );
236 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
237 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
239 #if defined(HAVE_SETPROGNAME)
245 # define PR_SET_NAME 15
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
;
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( §ion
, SECTION_ALL_ACCESS
, &attr
,
271 §ion_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
);
278 if (status
!= STATUS_OBJECT_NAME_EXISTS
)
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
);
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
);
305 if (needs_close
) close( fd
);
310 /***********************************************************************
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
;
325 struct ntdll_thread_data
*thread_data
;
329 /* reserve space for shared user data */
331 addr
= (void *)0x7ffe0000;
333 status
= NtAllocateVirtualMemory( NtCurrentProcess(), &addr
, 0, &size
,
334 MEM_RESERVE
|MEM_COMMIT
, PAGE_READWRITE
);
337 MESSAGE( "wine: failed to map the shared user data: %08x\n", status
);
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();
348 peb
->FastPebLock
= &peb_lock
;
349 peb
->TlsBitmap
= &tls_bitmap
;
350 peb
->TlsExpansionBitmap
= &tls_expansion_bitmap
;
351 peb
->FlsBitmap
= &fls_bitmap
;
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).
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();
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;
397 virtual_get_system_info( &sbi
);
398 user_shared_data
->NumberOfPhysicalPages
= sbi
.MmNumberOfPhysicalPages
;
404 /***********************************************************************
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 /***********************************************************************
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
;
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
);
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
));
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 /***********************************************************************
477 * Startup routine for a newly created thread.
479 static void start_thread( struct startup_info
*info
)
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
)
523 pthread_t pthread_id
;
525 struct ntdll_thread_data
*thread_data
;
526 struct startup_info
*info
;
527 HANDLE handle
= 0, actctx
= 0;
532 SIZE_T extra_stack
= PTHREAD_STACK_MIN
;
534 struct object_attributes
*objattr
= NULL
;
537 if (process
!= NtCurrentProcess())
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
;
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
);
588 close( request_pipe
[0] );
592 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
595 close( request_pipe
[1] );
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
);
610 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
612 frame
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame
));
613 frame
->Previous
= NULL
;
614 frame
->ActivationContext
= actctx
;
616 teb
->ActivationContextStack
.ActiveFrame
= frame
;
619 info
= (struct startup_info
*)(teb
+ 1);
621 info
->entry_point
= start
;
622 info
->entry_arg
= param
;
624 if ((status
= virtual_alloc_thread_stack( &stack
, stack_reserve
, stack_commit
, &extra_stack
)))
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
;
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
;
661 if (teb
) virtual_free_teb( teb
);
662 if (handle
) NtClose( handle
);
663 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
664 close( request_pipe
[1] );
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
)
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
);
701 /******************************************************************************
702 * NtSuspendThread (NTDLL.@)
703 * ZwSuspendThread (NTDLL.@)
705 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, PULONG count
)
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
;
722 /******************************************************************************
723 * NtResumeThread (NTDLL.@)
724 * ZwResumeThread (NTDLL.@)
726 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, PULONG count
)
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
;
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
)
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
;
783 if (self
) abort_thread( exit_code
);
788 /******************************************************************************
789 * NtQueueApcThread (NTDLL.@)
791 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
792 ULONG_PTR arg2
, ULONG_PTR arg3
)
795 SERVER_START_REQ( queue_apc
)
797 req
->handle
= wine_server_obj_handle( handle
);
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
);
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 /***********************************************************************
845 NTSTATUS
set_thread_context( HANDLE handle
, const context_t
*context
, BOOL
*self
)
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
);
862 /***********************************************************************
865 NTSTATUS
get_thread_context( HANDLE handle
, context_t
*context
, unsigned int flags
, BOOL
*self
)
869 SERVER_START_REQ( get_thread_context
)
871 req
->handle
= wine_server_obj_handle( handle
);
873 wine_server_set_reply( req
, context
, sizeof(*context
) );
874 ret
= wine_server_call( req
);
876 handle
= wine_server_ptr_handle( reply
->handle
);
880 if (ret
== STATUS_PENDING
)
882 LARGE_INTEGER timeout
;
883 timeout
.QuadPart
= -1000000;
884 if (NtWaitForSingleObject( handle
, FALSE
, &timeout
))
887 return STATUS_ACCESS_DENIED
;
889 SERVER_START_REQ( get_thread_context
)
891 req
->handle
= wine_server_obj_handle( handle
);
893 wine_server_set_reply( req
, context
, sizeof(*context
) );
894 ret
= wine_server_call( req
);
902 /******************************************************************************
903 * NtQueryInformationThread (NTDLL.@)
904 * ZwQueryInformationThread (NTDLL.@)
906 NTSTATUS WINAPI
NtQueryInformationThread( HANDLE handle
, THREADINFOCLASS
class,
907 void *data
, ULONG length
, ULONG
*ret_len
)
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
);
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 */
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
) );
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
);
950 if (!(status
= wine_server_call( req
)))
951 affinity
= reply
->affinity
& affinity_mask
;
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
) );
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
;
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())
983 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
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
;
991 static BOOL reported
= FALSE
;
993 kusrt
.KernelTime
.QuadPart
= 0;
994 kusrt
.UserTime
.QuadPart
= 0;
996 TRACE("Cannot get kerneltime or usertime of other threads\n");
999 FIXME("Cannot get kerneltime or usertime of other threads\n");
1003 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
1004 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
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
);
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
) );
1029 case ThreadQuerySetWin32StartAddress
:
1031 SERVER_START_REQ( get_thread_info
)
1033 req
->handle
= wine_server_obj_handle( handle
);
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
) );
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
);
1058 if (!(status
= wine_server_call( req
)))
1059 affinity
.Mask
= reply
->affinity
& affinity_mask
;
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
) );
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
:
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
);
1088 if (!(status
= wine_server_call( req
)))
1089 count
= reply
->suspend_count
;
1094 *(ULONG
*)data
= count
;
1098 case ThreadDescription
:
1100 THREAD_DESCRIPTION_INFORMATION
*info
= data
;
1101 data_size_t len
, desc_len
= 0;
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
;
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
;
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
:
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
)
1155 case ThreadZeroTlsCell
:
1156 if (handle
== GetCurrentThread())
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();
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
);
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
);
1220 case ThreadAffinityMask
:
1222 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
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
);
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
);
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
;
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
);
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
);
1303 case ThreadBasicInformation
:
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
:
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)
1331 #if defined(__linux__) && defined(__NR_getcpu)
1332 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
1333 if (res
!= -1) return processor
;
1336 if (NtCurrentTeb()->Peb
->NumberOfProcessors
> 1)
1338 ULONG_PTR thread_mask
, processor_mask
;
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
);
1359 /* fallback to the first processor */