diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index d3a37e81932..d0b9072c98b 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -68,7 +68,7 @@ extern NTSTATUS signal_alloc_thread( TEB **teb ) DECLSPEC_HIDDEN; extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_process(void) DECLSPEC_HIDDEN; -extern NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) DECLSPEC_HIDDEN; +extern NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) DECLSPEC_HIDDEN; extern NTSTATUS signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN; extern void version_init( const WCHAR *appname ) DECLSPEC_HIDDEN; extern void debug_init(void) DECLSPEC_HIDDEN; @@ -85,7 +85,7 @@ extern unsigned int server_cpus DECLSPEC_HIDDEN; extern BOOL is_wow64 DECLSPEC_HIDDEN; extern void server_init_process(void) DECLSPEC_HIDDEN; extern NTSTATUS server_init_process_done(void) DECLSPEC_HIDDEN; -extern size_t server_init_thread( void *entry_point ) DECLSPEC_HIDDEN; +extern size_t server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN terminate_thread( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index a57c3a8ea29..5c136738c7f 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -1470,7 +1470,7 @@ NTSTATUS server_init_process_done(void) * * Send an init thread request. Return 0 if OK. */ -size_t server_init_thread( void *entry_point ) +size_t server_init_thread( void *entry_point, BOOL *suspend ) { static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" }; static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); @@ -1511,6 +1511,7 @@ size_t server_init_thread( void *entry_point ) info_size = reply->info_size; server_start_time = reply->server_start; server_cpus = reply->all_cpus; + *suspend = reply->suspend; } SERVER_END_REQ; diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 3ff8c9124cf..924374669ee 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -1029,11 +1029,21 @@ static void thread_startup( void *param ) /*********************************************************************** * signal_start_thread */ -NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) +NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) { NTSTATUS status; + CONTEXT context = { 0 }; struct startup_info info = { entry, arg }; + /* build the initial context */ + context.ContextFlags = CONTEXT_FULL; + context.R0 = (DWORD)entry; + context.R1 = (DWORD)arg; + context.Sp = (DWORD)NtCurrentTeb()->Tib.StackBase; + context.Pc = (DWORD)call_thread_entry_point; + + if (suspend) wait_suspend( &context ); + if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index e0e424e9eda..b25a04ff831 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -900,11 +900,21 @@ static void thread_startup( void *param ) /*********************************************************************** * signal_start_thread */ -NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) +NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) { NTSTATUS status; + CONTEXT context = { 0 }; struct startup_info info = { entry, arg }; + /* build the initial context */ + context.ContextFlags = CONTEXT_FULL; + context.X0 = (DWORD_PTR)entry; + context.X1 = (DWORD_PTR)arg; + context.Sp = (DWORD_PTR)NtCurrentTeb()->Tib.StackBase; + context.Pc = (DWORD_PTR)call_thread_entry_point; + + if (suspend) wait_suspend( &context ); + if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 074ad3befde..5de078d148d 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -2618,11 +2618,29 @@ static void thread_startup( void *param ) /*********************************************************************** * signal_start_thread */ -NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) +NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) { NTSTATUS status; + CONTEXT context = { 0 }; struct startup_info info = { entry, arg }; + /* build the initial context */ + context.ContextFlags = CONTEXT_FULL; + context.SegCs = wine_get_cs(); + context.SegDs = wine_get_ds(); + context.SegEs = wine_get_es(); + context.SegFs = wine_get_fs(); + context.SegGs = wine_get_gs(); + context.SegSs = wine_get_ss(); + context.Eax = (DWORD)entry; + context.Ebx = (DWORD)arg; + context.Esp = (DWORD)NtCurrentTeb()->Tib.StackBase - 16; + context.Eip = (DWORD)call_thread_entry_point; + ((void **)context.Esp)[1] = entry; + ((void **)context.Esp)[2] = arg; + + if (suspend) wait_suspend( &context ); + if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index c5b3fdb8829..26c5db274b2 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -1102,11 +1102,21 @@ static void thread_startup( void *param ) /*********************************************************************** * signal_start_thread */ -NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) +NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) { NTSTATUS status; + CONTEXT context = { 0 }; struct startup_info info = { entry, arg }; + /* build the initial context */ + context.ContextFlags = CONTEXT_FULL; + context.Gpr1 = (DWORD)NtCurrentTeb()->Tib.StackBase; + context.Gpr3 = (DWORD)entry; + context.Gpr4 = (DWORD)arg; + context.Iar = (DWORD)call_thread_entry_point; + + if (suspend) wait_suspend( &context ); + if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 024af8e4878..24da31f8bfa 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -3160,11 +3160,24 @@ static void thread_startup( void *param ) /*********************************************************************** * signal_start_thread */ -NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) +NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) { NTSTATUS status; + CONTEXT context = { 0 }; struct startup_info info = { entry, arg }; + /* build the initial context */ + context.ContextFlags = CONTEXT_FULL; + __asm__( "movw %%cs,%0" : "=m" (context.SegCs) ); + __asm__( "movw %%ss,%0" : "=m" (context.SegSs) ); + __asm__( "fxsave %0" : "=m" (context.u.FltSave) ); + context.Rcx = (ULONG_PTR)entry; + context.Rdx = (ULONG_PTR)arg; + context.Rsp = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase - 0x28; + context.Rip = (ULONG_PTR)call_thread_entry_point; + + if (suspend) wait_suspend( &context ); + if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 18d0fe1b1c4..21624c8ae3c 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -272,6 +272,7 @@ HANDLE thread_init(void) { TEB *teb; void *addr; + BOOL suspend; SIZE_T size, info_size; HANDLE exe_file = 0; LARGE_INTEGER now; @@ -359,7 +360,7 @@ HANDLE thread_init(void) /* setup the server connection */ server_init_process(); - info_size = server_init_thread( peb ); + info_size = server_init_thread( peb, &suspend ); /* create the process heap */ if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ))) @@ -496,6 +497,7 @@ void exit_thread( int status ) */ static void start_thread( struct startup_info *info ) { + BOOL suspend; NTSTATUS status; TEB *teb = info->teb; struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; @@ -507,8 +509,8 @@ static void start_thread( struct startup_info *info ) thread_data->pthread_id = pthread_self(); signal_init_thread( teb ); - server_init_thread( info->entry_point ); - status = signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg ); + server_init_thread( info->entry_point, &suspend ); + status = signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend ); NtTerminateThread( GetCurrentThread(), status ); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2bc277901ef..d8a93b68805 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -827,7 +827,7 @@ struct init_thread_reply data_size_t info_size; int version; unsigned int all_cpus; - char __pad_36[4]; + int suspend; }; @@ -6475,6 +6475,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 543 +#define SERVER_PROTOCOL_VERSION 544 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 2e74d60b7c4..a3f46409f81 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -807,6 +807,7 @@ struct rawinput_device data_size_t info_size; /* total size of startup info */ int version; /* protocol version */ unsigned int all_cpus; /* bitset of supported CPUs */ + int suspend; /* is thread suspended? */ @END diff --git a/server/request.h b/server/request.h index 7747ce30f58..5bcdc7e31c9 100644 --- a/server/request.h +++ b/server/request.h @@ -782,6 +782,7 @@ C_ASSERT( FIELD_OFFSET(struct init_thread_reply, server_start) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, info_size) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, version) == 28 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, all_cpus) == 32 ); +C_ASSERT( FIELD_OFFSET(struct init_thread_reply, suspend) == 36 ); C_ASSERT( sizeof(struct init_thread_reply) == 40 ); C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct terminate_process_request, exit_code) == 16 ); diff --git a/server/thread.c b/server/thread.c index 858b4500a9c..2a57bc9e409 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1323,7 +1323,6 @@ DECL_HANDLER(init_thread) if (process->unix_pid != current->unix_pid) process->unix_pid = -1; /* can happen with linuxthreads */ init_thread_context( current ); - stop_thread_if_suspended( current ); generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry ); set_thread_affinity( current, current->affinity ); } @@ -1334,6 +1333,7 @@ DECL_HANDLER(init_thread) reply->version = SERVER_PROTOCOL_VERSION; reply->server_start = server_start_time; reply->all_cpus = supported_cpus & get_prefix_cpu_mask(); + reply->suspend = (current->suspend || process->suspend); return; error: diff --git a/server/trace.c b/server/trace.c index 6662d9af207..7f84e2a02f1 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1306,6 +1306,7 @@ static void dump_init_thread_reply( const struct init_thread_reply *req ) fprintf( stderr, ", info_size=%u", req->info_size ); fprintf( stderr, ", version=%d", req->version ); fprintf( stderr, ", all_cpus=%08x", req->all_cpus ); + fprintf( stderr, ", suspend=%d", req->suspend ); } static void dump_terminate_process_request( const struct terminate_process_request *req )