Use SIGUSR1 instead of SIGSTOP to suspend threads.
This commit is contained in:
parent
6168a2ea20
commit
d04ccb8ebe
|
@ -654,6 +654,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
|
||||
*
|
||||
|
@ -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 )
|
||||
{
|
||||
if (thread->attached)
|
||||
{
|
||||
suspend_thread( thread, 0 );
|
||||
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 (thread->attached)
|
||||
{
|
||||
send_thread_signal( thread, SIGSTOP );
|
||||
wait4_thread( thread, SIGSTOP );
|
||||
return 1;
|
||||
}
|
||||
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=" );
|
||||
|
|
Loading…
Reference in New Issue