Commit d04ccb8e authored by Alexandre Julliard's avatar Alexandre Julliard

Use SIGUSR1 instead of SIGSTOP to suspend threads.

parent 6168a2ea
......@@ -655,6 +655,36 @@ static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
/***********************************************************************
* init_handler
*
* Handler initialization when the full context is not needed.
*/
static void init_handler( const SIGCONTEXT *sigcontext )
{
/* restore a proper %fs for the fault handler */
if (!IS_SELECTOR_SYSTEM(CS_sig(sigcontext)) ||
!IS_SELECTOR_SYSTEM(SS_sig(sigcontext))) /* 16-bit mode */
{
wine_set_fs( SYSLEVEL_Win16CurrentTeb );
}
#ifdef __HAVE_VM86
else if ((void *)EIP_sig(sigcontext) == vm86_return) /* vm86 mode */
{
/* fetch the saved %fs on the stack */
wine_set_fs( *(unsigned int *)ESP_sig(sigcontext) );
}
#endif /* __HAVE_VM86 */
#ifdef FS_sig
else /* 32-bit mode, get %fs at time of the fault */
{
wine_set_fs( FS_sig(sigcontext) );
}
#endif /* FS_sig */
wine_set_gs( NtCurrentTeb()->gs_sel );
}
/***********************************************************************
* save_fpu
*
* Set the FPU context from a sigcontext.
......@@ -1037,6 +1067,7 @@ static HANDLER_DEF(fpe_handler)
*/
static HANDLER_DEF(int_handler)
{
init_handler( HANDLER_CONTEXT );
if (!dispatch_signal(SIGINT))
{
EXCEPTION_RECORD rec;
......@@ -1074,6 +1105,19 @@ static HANDLER_DEF(abrt_handler)
}
/**********************************************************************
* usr1_handler
*
* Handler for SIGUSR1, used to signal a thread that it got suspended.
*/
static HANDLER_DEF(usr1_handler)
{
init_handler( HANDLER_CONTEXT );
/* wait with 0 timeout, will only return once the thread is no longer suspended */
WaitForMultipleObjectsEx( 0, NULL, FALSE, 0, FALSE );
}
/***********************************************************************
* set_handler
*
......@@ -1160,6 +1204,7 @@ BOOL SIGNAL_Init(void)
if (set_handler( SIGSEGV, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
if (set_handler( SIGILL, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
if (set_handler( SIGABRT, have_sigaltstack, (void (*)())abrt_handler ) == -1) goto error;
if (set_handler( SIGUSR1, have_sigaltstack, (void (*)())usr1_handler ) == -1) goto error;
#ifdef SIGBUS
if (set_handler( SIGBUS, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
#endif
......@@ -1192,6 +1237,7 @@ void SIGNAL_Reset(void)
sigaddset( &block_set, SIGALRM );
sigaddset( &block_set, SIGIO );
sigaddset( &block_set, SIGHUP );
sigaddset( &block_set, SIGUSR1 );
sigaddset( &block_set, SIGUSR2 );
sigprocmask( SIG_BLOCK, &block_set, NULL );
......
......@@ -381,6 +381,7 @@ static HANDLER_DEF(int_handler)
}
}
/**********************************************************************
* abrt_handler
*
......@@ -402,6 +403,18 @@ static HANDLER_DEF(abrt_handler)
}
/**********************************************************************
* usr1_handler
*
* Handler for SIGUSR1, used to signal a thread that it got suspended.
*/
static HANDLER_DEF(usr1_handler)
{
/* wait with 0 timeout, will only return once the thread is no longer suspended */
WaitForMultipleObjectsEx( 0, NULL, FALSE, 0, FALSE );
}
/***********************************************************************
* set_handler
*
......@@ -461,6 +474,7 @@ BOOL SIGNAL_Init(void)
if (set_handler( SIGSEGV, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
if (set_handler( SIGILL, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
if (set_handler( SIGABRT, have_sigaltstack, (void (*)())abrt_handler ) == -1) goto error;
if (set_handler( SIGUSR1, have_sigaltstack, (void (*)())usr1_handler ) == -1) goto error;
#ifdef SIGBUS
if (set_handler( SIGBUS, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
#endif
......@@ -488,6 +502,7 @@ void SIGNAL_Reset(void)
sigaddset( &block_set, SIGALRM );
sigaddset( &block_set, SIGIO );
sigaddset( &block_set, SIGHUP );
sigaddset( &block_set, SIGUSR1 );
sigaddset( &block_set, SIGUSR2 );
sigprocmask( SIG_BLOCK, &block_set, NULL );
......
......@@ -367,6 +367,19 @@ static HANDLER_DEF(abrt_handler)
restore_context( &context, HANDLER_CONTEXT );
}
/**********************************************************************
* usr1_handler
*
* Handler for SIGUSR1, used to signal a thread that it got suspended.
*/
static HANDLER_DEF(usr1_handler)
{
/* wait with 0 timeout, will only return once the thread is no longer suspended */
WaitForMultipleObjectsEx( 0, NULL, FALSE, 0, FALSE );
}
/***********************************************************************
* set_handler
*
......@@ -422,6 +435,7 @@ BOOL SIGNAL_Init(void)
if (set_handler( SIGBUS, (void (*)())bus_handler ) == -1) goto error;
if (set_handler( SIGTRAP, (void (*)())trap_handler ) == -1) goto error;
if (set_handler( SIGABRT, (void (*)())abrt_handler ) == -1) goto error;
if (set_handler( SIGUSR1, (void (*)())usr1_handler ) == -1) goto error;
return TRUE;
error:
......@@ -442,6 +456,7 @@ void SIGNAL_Reset(void)
sigaddset( &block_set, SIGALRM );
sigaddset( &block_set, SIGIO );
sigaddset( &block_set, SIGHUP );
sigaddset( &block_set, SIGUSR1 );
sigaddset( &block_set, SIGUSR2 );
sigprocmask( SIG_BLOCK, &block_set, NULL );
......
......@@ -3551,6 +3551,6 @@ union generic_reply
struct get_next_hook_reply get_next_hook_reply;
};
#define SERVER_PROTOCOL_VERSION 98
#define SERVER_PROTOCOL_VERSION 99
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -653,6 +653,8 @@ void CLIENT_InitServer(void)
sigaddset( &block_set, SIGIO );
sigaddset( &block_set, SIGINT );
sigaddset( &block_set, SIGHUP );
sigaddset( &block_set, SIGUSR1 );
sigaddset( &block_set, SIGUSR2 );
/* receive the first thread request fd on the main socket */
NtCurrentTeb()->request_fd = receive_fd( &dummy_handle );
......
......@@ -508,6 +508,14 @@ static void start_process(void)
console_app = (nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
if (console_app) current_process.flags |= PDB32_CONSOLE_PROC;
/* Install signal handlers; this cannot be done before, since we cannot
* send exceptions to the debugger before the create process event that
* is sent by REQ_INIT_PROCESS_DONE.
* We do need the handlers in place by the time the request is over, so
* we set them up here. If we segfault between here and the server call
* something is very wrong... */
if (!SIGNAL_Init()) goto error;
/* Signal the parent process to continue */
SERVER_START_REQ( init_process_done )
{
......@@ -524,11 +532,6 @@ static void start_process(void)
}
SERVER_END_REQ;
/* Install signal handlers; this cannot be done before, since we cannot
* send exceptions to the debugger before the create process event that
* is sent by REQ_INIT_PROCESS_DONE */
if (!SIGNAL_Init()) goto error;
/* create the main modref and load dependencies */
if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE )))
goto error;
......
......@@ -534,7 +534,7 @@ void *get_thread_ip( struct thread *thread )
if (suspend_for_ptrace( thread ))
{
get_thread_context( thread, CONTEXT_CONTROL, &context );
resume_thread( thread );
resume_after_ptrace( thread );
}
return (void *)context.Eip;
}
......@@ -576,7 +576,7 @@ DECL_HANDLER(get_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
get_thread_context( thread, flags, data );
resume_thread( thread );
resume_after_ptrace( thread );
}
}
release_object( thread );
......@@ -604,7 +604,7 @@ DECL_HANDLER(set_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
set_thread_context( thread, flags, get_req_data() );
resume_thread( thread );
resume_after_ptrace( thread );
}
release_object( thread );
}
......
......@@ -252,7 +252,7 @@ void *get_thread_ip( struct thread *thread )
if (suspend_for_ptrace( thread ))
{
get_thread_context( thread, CONTEXT_CONTROL, &context );
resume_thread( thread );
resume_after_ptrace( thread );
}
return (void *)context.Iar;
}
......@@ -293,7 +293,7 @@ DECL_HANDLER(get_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
get_thread_context( thread, flags, data );
resume_thread( thread );
resume_after_ptrace( thread );
}
}
release_object( thread );
......@@ -321,7 +321,7 @@ DECL_HANDLER(set_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
set_thread_context( thread, flags, get_req_data() );
resume_thread( thread );
resume_after_ptrace( thread );
}
release_object( thread );
}
......
......@@ -164,7 +164,7 @@ void *get_thread_ip( struct thread *thread )
if (suspend_for_ptrace( thread ))
{
get_thread_context( thread, CONTEXT_CONTROL, &context );
resume_thread( thread );
resume_after_ptrace( thread );
}
return (void *)context.pc;
}
......@@ -199,7 +199,7 @@ DECL_HANDLER(get_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
get_thread_context( thread, flags, data );
resume_thread( thread );
resume_after_ptrace( thread );
}
}
release_object( thread );
......@@ -227,7 +227,7 @@ DECL_HANDLER(set_thread_context)
if (flags && suspend_for_ptrace( thread ))
{
set_thread_context( thread, flags, get_req_data() );
resume_thread( thread );
resume_after_ptrace( thread );
}
release_object( thread );
}
......
......@@ -673,11 +673,7 @@ void resume_process( struct process *process )
while (thread)
{
struct thread *next = thread->proc_next;
if (!thread->suspend)
{
continue_thread( thread );
wake_thread( thread );
}
if (!thread->suspend) wake_thread( thread );
thread = next;
}
}
......@@ -781,7 +777,7 @@ static int read_process_memory( struct process *process, const int *addr, size_t
if (read_thread_int( thread, addr++, dest++ ) == -1) break;
len--;
}
resume_thread( thread );
resume_after_ptrace( thread );
}
return !len;
}
......@@ -842,7 +838,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done;
done:
resume_thread( thread );
resume_after_ptrace( thread );
}
}
......
......@@ -69,24 +69,20 @@ inline static int ptrace(int req, ...) { errno = EPERM; return -1; /*FAIL*/ }
static const int use_ptrace = 1; /* set to 0 to disable ptrace */
/* handle a status returned by wait4 */
static int handle_child_status( struct thread *thread, int pid, int status )
static int handle_child_status( struct thread *thread, int pid, int status, int want_sig )
{
if (WIFSTOPPED(status))
{
int sig = WSTOPSIG(status);
if (debug_level && thread)
fprintf( stderr, "%04x: *signal* signal=%d\n", thread->id, sig );
switch(sig)
if (sig != want_sig)
{
case SIGSTOP: /* continue at once if not suspended */
if (thread && (thread->process->suspend + thread->suspend)) break;
/* fall through */
default: /* ignore other signals for now */
/* ignore other signals for now */
if (thread && get_thread_single_step( thread ))
ptrace( PTRACE_SINGLESTEP, pid, (caddr_t)1, sig );
else
ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
break;
}
return sig;
}
......@@ -115,13 +111,13 @@ void sigchld_handler()
for (;;)
{
if (!(pid = wait4( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status );
if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status, -1 );
else break;
}
}
/* wait for a ptraced child to get a certain signal */
void wait4_thread( struct thread *thread, int signal )
static void wait4_thread( struct thread *thread, int signal )
{
int res, status;
......@@ -129,10 +125,15 @@ void wait4_thread( struct thread *thread, int signal )
{
if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
{
perror( "wait4" );
if (errno == ECHILD) /* must have died */
{
thread->unix_pid = -1;
thread->attached = 0;
}
else perror( "wait4" );
return;
}
res = handle_child_status( thread, res, status );
res = handle_child_status( thread, res, status, signal );
} while (res && res != signal);
}
......@@ -176,66 +177,48 @@ void detach_thread( struct thread *thread, int sig )
if (thread->attached)
{
/* make sure it is stopped */
suspend_thread( thread, 0 );
suspend_for_ptrace( thread );
if (sig) send_thread_signal( thread, sig );
if (thread->unix_pid == -1) return;
if (debug_level) fprintf( stderr, "%04x: *detached*\n", thread->id );
ptrace( PTRACE_DETACH, thread->unix_pid, (caddr_t)1, sig );
thread->suspend = 0; /* detach makes it continue */
thread->attached = 0;
}
else
{
if (sig) send_thread_signal( thread, sig );
if (thread->suspend + thread->process->suspend) continue_thread( thread );
}
}
/* stop a thread (at the Unix level) */
void stop_thread( struct thread *thread )
{
/* can't stop a thread while initialisation is in progress */
if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) return;
/* first try to attach to it */
if (!thread->attached)
if (attach_thread( thread )) return; /* this will have stopped it */
/* attached already, or attach failed -> send a signal */
if (thread->unix_pid == -1) return;
send_thread_signal( thread, SIGSTOP );
if (thread->attached) wait4_thread( thread, SIGSTOP );
}
/* make a thread continue (at the Unix level) */
void continue_thread( struct thread *thread )
{
if (thread->unix_pid == -1) return;
if (!thread->attached) send_thread_signal( thread, SIGCONT );
else ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
thread->unix_pid, (caddr_t)1, SIGSTOP );
else if (sig) send_thread_signal( thread, sig );
}
/* suspend a thread to allow using ptrace on it */
/* you must do a resume_thread when finished with the thread */
/* you must do a resume_after_ptrace when finished with the thread */
int suspend_for_ptrace( struct thread *thread )
{
/* can't stop a thread while initialisation is in progress */
if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) goto error;
if (thread->attached)
{
suspend_thread( thread, 0 );
send_thread_signal( thread, SIGSTOP );
wait4_thread( thread, SIGSTOP );
return 1;
}
/* can't stop a thread while initialisation is in progress */
if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) goto error;
thread->suspend++;
if (attach_thread( thread )) return 1;
thread->suspend--;
error:
set_error( STATUS_ACCESS_DENIED );
return 0;
}
/* resume a thread after we have used pthread on it */
void resume_after_ptrace( struct thread *thread )
{
if (thread->unix_pid == -1) return;
assert( thread->attached );
ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
thread->unix_pid, (caddr_t)1, 0 /* cancel the SIGSTOP */ );
}
/* read an int from a thread address space */
int read_thread_int( struct thread *thread, const int *addr, int *data )
{
errno = 0;
*data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, (caddr_t)addr, 0 );
if ( *data == -1 && errno)
{
......
......@@ -301,11 +301,18 @@ static void set_thread_info( struct thread *thread,
}
}
/* stop a thread (at the Unix level) */
void stop_thread( struct thread *thread )
{
/* can't stop a thread while initialisation is in progress */
if (is_process_init_done(thread->process)) send_thread_signal( thread, SIGUSR1 );
}
/* suspend a thread */
int suspend_thread( struct thread *thread, int check_limit )
static int suspend_thread( struct thread *thread )
{
int old_count = thread->suspend;
if (thread->suspend < MAXIMUM_SUSPEND_COUNT || !check_limit)
if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
{
if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
}
......@@ -314,16 +321,12 @@ int suspend_thread( struct thread *thread, int check_limit )
}
/* resume a thread */
int resume_thread( struct thread *thread )
static int resume_thread( struct thread *thread )
{
int old_count = thread->suspend;
if (thread->suspend > 0)
{
if (!(--thread->suspend + thread->process->suspend))
{
continue_thread( thread );
wake_thread( thread );
}
if (!(--thread->suspend + thread->process->suspend)) wake_thread( thread );
}
return old_count;
}
......@@ -500,6 +503,7 @@ static void thread_timeout( void *ptr )
wait->user = NULL;
if (thread->wait != wait) return; /* not the top-level wait, ignore it */
if (thread->suspend + thread->process->suspend > 0) return; /* suspended, ignore it */
if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d cookie=%p\n",
thread->id, STATUS_TIMEOUT, cookie );
......@@ -722,7 +726,7 @@ static void get_selector_entry( struct thread *thread, int entry,
if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
*flags = flags_buf[entry & 3];
done:
resume_thread( thread );
resume_after_ptrace( thread );
}
}
......@@ -933,7 +937,7 @@ DECL_HANDLER(suspend_thread)
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
{
if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED );
else reply->count = suspend_thread( thread, 1 );
else reply->count = suspend_thread( thread );
release_object( thread );
}
}
......
......@@ -110,8 +110,7 @@ extern struct thread *create_thread( int fd, struct process *process );
extern struct thread *get_thread_from_id( thread_id_t id );
extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access );
extern struct thread *get_thread_from_pid( int pid );
extern int suspend_thread( struct thread *thread, int check_limit );
extern int resume_thread( struct thread *thread );
extern void stop_thread( struct thread *thread );
extern int wake_thread( struct thread *thread );
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
......@@ -127,11 +126,9 @@ extern struct thread_snapshot *thread_snap( int *count );
/* ptrace functions */
extern void sigchld_handler();
extern void wait4_thread( struct thread *thread, int signal );
extern void stop_thread( struct thread *thread );
extern void continue_thread( struct thread *thread );
extern void detach_thread( struct thread *thread, int sig );
extern int suspend_for_ptrace( struct thread *thread );
extern void resume_after_ptrace( struct thread *thread );
extern int read_thread_int( struct thread *thread, const int *addr, int *data );
extern int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask );
extern void *get_thread_ip( struct thread *thread );
......
......@@ -195,6 +195,11 @@ static void dump_varargs_unicode_str( size_t size )
static void dump_varargs_context( size_t size )
{
if (!size)
{
fprintf( stderr, "{}" );
return;
}
dump_context( cur_data );
remove_data( size );
}
......@@ -202,6 +207,12 @@ static void dump_varargs_context( size_t size )
static void dump_varargs_exc_event( size_t size )
{
const CONTEXT *ptr = cur_data;
if (!size)
{
fprintf( stderr, "{}" );
return;
}
fprintf( stderr, "{context=" );
dump_context( ptr );
fprintf( stderr, ",rec=" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment