From: Fan WenJie fanwj@mail.ustc.edu.cn
Signed-off-by: Fan WenJie fanwj@mail.ustc.edu.cn --- dlls/ntdll/unix/signal_arm.c | 8 +++++ dlls/ntdll/unix/signal_arm64.c | 8 +++++ dlls/ntdll/unix/signal_i386.c | 13 ++++++++ dlls/ntdll/unix/signal_x86_64.c | 8 +++++ dlls/ntdll/unix/thread.c | 54 +++++++++++++++++++++------------ dlls/ntdll/unix/unix_private.h | 2 ++ dlls/ntdll/unix/virtual.c | 1 + 7 files changed, 74 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 640ea39f5d9..f37e907b50f 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -1798,4 +1798,12 @@ __ASM_GLOBAL_FUNC( __wine_longjmp, "mov r0, r1\n\t" /* retval */ "bx r2" )
+/*********************************************************************** + * coroutine_create + */ +__ASM_GLOBAL_FUNC( coroutine_create, + "mov lr, #0 \n\t" /* retaddr = 0 */ + "mov sp, r1 \n\t" /* $sp = sp */ + "bx r2 \n\t" /* jmp start_coroutine */ ) + #endif /* __arm__ */ diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index f232ecf92a9..c54a5de00b3 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1905,4 +1905,12 @@ __ASM_GLOBAL_FUNC( __wine_longjmp, "mov x0, x1\n\t" /* retval */ "ret" )
+/*********************************************************************** + * coroutine_create + */ +__ASM_GLOBAL_FUNC( coroutine_create, + "mov lr, #0 \n\t" /* retaddr = 0 */ + "mov sp, x1 \n\t" /* $sp = sp */ + "br x2 \n\t" /* jmp start_coroutine */ ) + #endif /* __aarch64__ */ diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 89af605443d..92706da50b6 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2809,4 +2809,17 @@ __ASM_GLOBAL_FUNC( __wine_longjmp, "addl $4,%esp\n\t" /* get rid of return address */ "jmp *20(%ecx)\n\t" /* jmp_buf.Eip */ )
+/*********************************************************************** + * coroutine_create + */ +__ASM_GLOBAL_FUNC( coroutine_create, + "movl 8(%esp), %eax \n\t" /* sp = *(oldsp + 8) */ + "leal -20(%eax), %eax \n\t" /* sp = sp - 20 */ + "xchgl %eax, %esp \n\t" /* %esp = sp, %eax = oldsp */ + "movl 4(%eax), %ecx \n\t" /* params = *(oldsp + 4) */ + "movl %ecx, 4(%esp) \n\t" /* *(sp + 4) = params */ + "movl $0, (%esp) \n\t" /* retaddr = 0 */ + "movl 12(%eax), %eax \n\t" /* start_coroutine = *(oldsp + 12) */ + "jmp *%eax \n\t" /* jmp start_coroutine */ ) + #endif /* __i386__ */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 97d3a009c03..ca578bebc62 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -3028,4 +3028,12 @@ __ASM_GLOBAL_FUNC( __wine_longjmp, "movq 0x10(%rcx),%rsp\n\t" /* jmp_buf->Rsp */ "jmp *%rdx" )
+/*********************************************************************** + * coroutine_create + */ +__ASM_GLOBAL_FUNC( coroutine_create, + "movq %rsi, %rsp \n\t" /* %rsp = sp */ + "pushq $0 \n\t" /* retaddr = 0 */ + "jmp *%rdx \n\t" /* jmp start_coroutine */ ) + #endif /* __x86_64__ */ diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 6c20ec2d395..96c8284daaf 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1082,10 +1082,16 @@ static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] */ static void pthread_exit_wrapper( int status ) { - close( ntdll_get_thread_data()->wait_fd[0] ); - close( ntdll_get_thread_data()->wait_fd[1] ); - close( ntdll_get_thread_data()->reply_fd ); - close( ntdll_get_thread_data()->request_fd ); + struct ntdll_thread_data *thread_data = ntdll_get_thread_data(); + close( thread_data->wait_fd[0] ); + close( thread_data->wait_fd[1] ); + close( thread_data->reply_fd ); + close( thread_data->request_fd ); + if (thread_data->exit_buf) + { + thread_data->cpu_data[0] = UIntToPtr(status); + __wine_longjmp((__wine_jmp_buf*)thread_data->exit_buf, 1 ); + } pthread_exit( UIntToPtr(status) ); }
@@ -1095,8 +1101,9 @@ static void pthread_exit_wrapper( int status ) * * Startup routine for a newly created thread. */ -static void start_thread( TEB *teb ) +static void DECLSPEC_NORETURN start_thread( void* params ) { + TEB *teb = (TEB *)params; struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; BOOL suspend;
@@ -1106,6 +1113,26 @@ static void start_thread( TEB *teb ) signal_start_thread( thread_data->start, thread_data->param, suspend, teb ); }
+static void* start_thread_wrapper(void *params) +{ + __wine_jmp_buf current_buf; + TEB* teb = (TEB*)params; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; + char* sp = ((char*)thread_data->kernel_stack) + kernel_stack_size; + thread_data->exit_buf = ¤t_buf; + if (__wine_setjmpex(¤t_buf, NULL)) + { + void* exit_code = thread_data->cpu_data[0]; + virtual_free_teb(teb); + pthread_exit(exit_code); + } + else + { + coroutine_create(teb, sp, &start_thread); + } + return NULL; +} +
/*********************************************************************** * get_machine_context_size @@ -1374,11 +1401,11 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT thread_data->param = param;
pthread_attr_init( &pthread_attr ); - pthread_attr_setstack( &pthread_attr, thread_data->kernel_stack, kernel_stack_size ); + pthread_attr_setstacksize( &pthread_attr, 0x2000 ); pthread_attr_setguardsize( &pthread_attr, 0 ); pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */ InterlockedIncrement( &nb_threads ); - if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb )) + if (pthread_create( &pthread_id, &pthread_attr, start_thread_wrapper, teb )) { InterlockedDecrement( &nb_threads ); virtual_free_teb( teb ); @@ -1424,23 +1451,10 @@ void abort_process( int status ) */ static DECLSPEC_NORETURN void exit_thread( int status ) { - static void *prev_teb; - TEB *teb; - pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
if (InterlockedDecrement( &nb_threads ) <= 0) exit_process( status );
- if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() ))) - { - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; - - if (thread_data->pthread_id) - { - pthread_join( thread_data->pthread_id, NULL ); - virtual_free_teb( teb ); - } - } signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() ); }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index eac6434b64d..177539604ec 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -90,6 +90,7 @@ struct ntdll_thread_data PRTL_THREAD_START_ROUTINE start; /* thread entry point */ void *param; /* thread entry point parameter */ void *jmp_buf; /* setjmp buffer for exception handling */ + void *exit_buf; /* setjmp buffer for exit handling */ };
C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) ); @@ -327,6 +328,7 @@ extern NTSTATUS call_user_apc_dispatcher( CONTEXT *context_ptr, ULONG_PTR arg1, extern NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN; extern void call_raise_user_exception_dispatcher(void) DECLSPEC_HIDDEN;
+extern void DECLSPEC_NORETURN coroutine_create(void* params, void* sp, void DECLSPEC_NORETURN(*start_coroutine)(void*)); #define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */
#define TICKSPERSEC 10000000 diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b33b45ad07f..dad81a377cc 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3182,6 +3182,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; thread_data->wait_fd[1] = -1; + thread_data->exit_buf = NULL; list_add_head( &teb_list, &thread_data->entry ); return teb; }