diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index eaf2f1a45b7..4de562b9941 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -2670,6 +2670,36 @@ static void test_thread_lookup(void) "NtOpenThread returned %#x\n", status); } +static void test_thread_info(void) +{ + NTSTATUS status; + ULONG len, data; + + len = 0xdeadbeef; + data = 0xcccccccc; + status = pNtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, + &data, sizeof(data), &len ); + ok( !status, "failed %x\n", status ); + ok( data == 0 || data == 1, "wrong data %x\n", data ); + ok( len == sizeof(data), "wrong len %u\n", len ); + + len = 0xdeadbeef; + data = 0xcccccccc; + status = pNtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, + &data, sizeof(data) - 1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "failed %x\n", status ); + ok( data == 0xcccccccc, "wrong data %x\n", data ); + ok( len == 0xdeadbeef, "wrong len %u\n", len ); + + len = 0xdeadbeef; + data = 0xcccccccc; + status = pNtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, + &data, sizeof(data) + 1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "failed %x\n", status ); + ok( data == 0xcccccccc, "wrong data %x\n", data ); + ok( len == 0xdeadbeef, "wrong len %u\n", len ); +} + START_TEST(info) { char **argv; @@ -2827,4 +2857,5 @@ START_TEST(info) test_query_data_alignment(); test_thread_lookup(); + test_thread_info(); } diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index ec94338f3f9..7b8a7172414 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -45,7 +45,6 @@ static PEB_LDR_DATA ldr; static RTL_BITMAP tls_bitmap; static RTL_BITMAP tls_expansion_bitmap; static RTL_BITMAP fls_bitmap; -static int nb_threads = 1; struct ldt_copy *__wine_ldt_copy = NULL; @@ -105,7 +104,7 @@ int __cdecl __wine_dbg_output( const char *str ) TEB *thread_init( SIZE_T *info_size ) { ULONG_PTR val; - TEB *teb = unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy, info_size ); + TEB *teb = unix_funcs->init_threading( &__wine_ldt_copy, info_size ); peb = teb->Peb; peb->FastPebLock = &peb_lock; @@ -147,6 +146,8 @@ TEB *thread_init( SIZE_T *info_size ) */ void WINAPI RtlExitUserThread( ULONG status ) { + ULONG last; + if (status) /* send the exit code to the server (0 is already the default) */ { SERVER_START_REQ( terminate_thread ) @@ -158,12 +159,12 @@ void WINAPI RtlExitUserThread( ULONG status ) SERVER_END_REQ; } - if (InterlockedDecrement( &nb_threads ) <= 0) + NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); + if (last) { LdrShutdownProcess(); unix_funcs->exit_process( status ); } - LdrShutdownThread(); RtlFreeThreadActivationContextStack(); for (;;) unix_funcs->exit_thread( status ); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index c583a08c058..2be8d2d3e23 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -60,7 +60,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); #define PTHREAD_STACK_MIN 16384 #endif -static int *nb_threads; +static int nb_threads = 1; static inline int get_unix_exit_code( NTSTATUS status ) { @@ -86,7 +86,7 @@ static void pthread_exit_wrapper( int status ) /*********************************************************************** * init_threading */ -TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZE_T *size ) +TEB * CDECL init_threading( struct ldt_copy **ldt_copy, SIZE_T *size ) { TEB *teb; BOOL suspend; @@ -95,7 +95,6 @@ TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZ extern struct ldt_copy __wine_ldt_copy; *ldt_copy = &__wine_ldt_copy; #endif - nb_threads = nb_threads_ptr; teb = virtual_alloc_first_teb(); @@ -290,10 +289,10 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT (char *)teb->Tib.StackBase + extra_stack - (char *)teb->DeallocationStack ); pthread_attr_setguardsize( &pthread_attr, 0 ); pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */ - InterlockedIncrement( nb_threads ); + InterlockedIncrement( &nb_threads ); if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb )) { - InterlockedDecrement( nb_threads ); + InterlockedDecrement( &nb_threads ); virtual_free_teb( teb ); status = STATUS_NO_MEMORY; } @@ -319,7 +318,7 @@ done: void abort_thread( int status ) { pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); - if (InterlockedDecrement( nb_threads ) <= 0) abort_process( status ); + if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status ); signal_exit_thread( status, pthread_exit_wrapper ); } @@ -987,6 +986,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, case ThreadAmILastThread: { + if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH; SERVER_START_REQ( get_thread_info ) { req->handle = wine_server_obj_handle( handle ); @@ -994,9 +994,9 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, status = wine_server_call( req ); if (status == STATUS_SUCCESS) { - BOOLEAN last = reply->last; - if (data) memcpy( data, &last, min( length, sizeof(last) )); - if (ret_len) *ret_len = min( length, sizeof(last) ); + ULONG last = reply->last; + if (data) memcpy( data, &last, sizeof(last) ); + if (ret_len) *ret_len = sizeof(last); } } SERVER_END_REQ; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d6a15d5f7b6..1f4c2da0c6c 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -117,7 +117,7 @@ extern NTSTATUS CDECL server_handle_to_fd( HANDLE handle, unsigned int access, i unsigned int *options ) DECLSPEC_HIDDEN; extern void CDECL server_release_fd( HANDLE handle, int unix_fd ) DECLSPEC_HIDDEN; extern void CDECL server_init_process_done( void *relay ) DECLSPEC_HIDDEN; -extern TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZE_T *size ) DECLSPEC_HIDDEN; +extern TEB * CDECL init_threading( struct ldt_copy **ldt_copy, SIZE_T *size ) DECLSPEC_HIDDEN; extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN; extern void CDECL DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL exec_process( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 88010b695e3..19e532da474 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -29,7 +29,7 @@ struct msghdr; struct _DISPATCHER_CONTEXT; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 65 +#define NTDLL_UNIXLIB_VERSION 66 struct unix_funcs { @@ -319,7 +319,7 @@ struct unix_funcs void (CDECL *virtual_set_large_address_space)(void); /* thread/process functions */ - TEB * (CDECL *init_threading)( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZE_T *size ); + TEB * (CDECL *init_threading)( struct ldt_copy **ldt_copy, SIZE_T *size ); void (CDECL *exit_thread)( int status ); void (CDECL *exit_process)( int status ); NTSTATUS (CDECL *exec_process)( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status );