Have threads and processes exit more cleanly whenever possible.

This commit is contained in:
Alexandre Julliard 2000-03-17 15:16:57 +00:00
parent aabef02912
commit 12f29b5076
17 changed files with 160 additions and 96 deletions

View File

@ -191,6 +191,7 @@ struct terminate_process_request
{
IN int handle; /* process handle to terminate */
IN int exit_code; /* process exit code */
OUT int self; /* suicide? */
};
@ -199,6 +200,8 @@ struct terminate_thread_request
{
IN int handle; /* thread handle to terminate */
IN int exit_code; /* thread exit code */
OUT int self; /* suicide? */
OUT int last; /* last thread in this process? */
};
@ -1202,7 +1205,7 @@ enum request
REQ_NB_REQUESTS
};
#define SERVER_PROTOCOL_VERSION 3
#define SERVER_PROTOCOL_VERSION 4
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
@ -1219,7 +1222,7 @@ enum request
extern unsigned int server_call_noerr( enum request req );
extern unsigned int server_call_fd( enum request req, int fd_out, int *fd_in );
extern void server_protocol_error( const char *err, ... );
extern void server_protocol_error( const char *err, ... ) WINE_NORETURN;
/* get a pointer to the request buffer */
static inline void * WINE_UNUSED get_req_buffer(void)

View File

@ -131,6 +131,6 @@ extern TEB *THREAD_IdToTEB( DWORD id );
/* scheduler/sysdeps.c */
extern int SYSDEPS_SpawnThread( TEB *teb );
extern void SYSDEPS_SetCurThread( TEB *teb );
extern void SYSDEPS_ExitThread(void);
extern void SYSDEPS_ExitThread( int status ) WINE_NORETURN;
#endif /* __WINE_THREAD_H */

View File

@ -1223,8 +1223,8 @@ BOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Loca
#define EnumTimeFormats WINELIB_NAME_AW(EnumTimeFormats)
BOOL WINAPI EqualSid(PSID, PSID);
BOOL WINAPI EqualPrefixSid(PSID,PSID);
VOID WINAPI ExitProcess(DWORD);
VOID WINAPI ExitThread(DWORD);
VOID WINAPI ExitProcess(DWORD) WINE_NORETURN;
VOID WINAPI ExitThread(DWORD) WINE_NORETURN;
DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR,LPSTR,DWORD);
DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR,LPWSTR,DWORD);
#define ExpandEnvironmentStrings WINELIB_NAME_AW(ExpandEnvironmentStrings)

View File

@ -353,11 +353,13 @@ typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM);
/* Macro for structure packing. */
#ifdef __GNUC__
#define WINE_PACKED __attribute__ ((packed))
#define WINE_UNUSED __attribute__ ((unused))
#define WINE_PACKED __attribute__((packed))
#define WINE_UNUSED __attribute__((unused))
#define WINE_NORETURN __attribute__((noreturn))
#else
#define WINE_PACKED /* nothing */
#define WINE_UNUSED /* nothing */
#define WINE_PACKED /* nothing */
#define WINE_UNUSED /* nothing */
#define WINE_NORETURN /* nothing */
#endif
/* Macros to split words and longs. */

View File

@ -221,14 +221,13 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
* Send DLL process detach notifications. See the comment about calling
* sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
* is set, only DLLs with zero refcount are notified.
*
* NOTE: Assumes that the process critical section is held!
*
*/
void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
{
WINE_MODREF *wm;
EnterCriticalSection( &PROCESS_Current()->crit_section );
do
{
for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
@ -248,6 +247,8 @@ void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
break;
}
} while ( wm );
LeaveCriticalSection( &PROCESS_Current()->crit_section );
}
/*************************************************************************

View File

@ -77,17 +77,6 @@ static void fatal_perror( const char *err, ... )
exit(1);
}
/***********************************************************************
* CLIENT_Die
*
* Die on protocol errors or socket close
*/
static void CLIENT_Die(void)
{
close( NtCurrentTeb()->socket );
SYSDEPS_ExitThread();
}
/***********************************************************************
* server_protocol_error
*/
@ -99,7 +88,7 @@ void server_protocol_error( const char *err, ... )
fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
vfprintf( stderr, err, args );
va_end( args );
CLIENT_Die();
SYSDEPS_ExitThread(1);
}
@ -110,7 +99,7 @@ static void server_perror( const char *err )
{
fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
perror( err );
CLIENT_Die();
SYSDEPS_ExitThread(1);
}
@ -126,7 +115,7 @@ static void send_request( enum request req )
return;
if (ret == -1)
{
if (errno == EPIPE) CLIENT_Die();
if (errno == EPIPE) SYSDEPS_ExitThread(0);
server_perror( "sendmsg" );
}
server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
@ -170,7 +159,7 @@ static void send_request_fd( enum request req, int fd )
if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(req)) return;
if (ret == -1)
{
if (errno == EPIPE) CLIENT_Die();
if (errno == EPIPE) SYSDEPS_ExitThread(0);
server_perror( "sendmsg" );
}
server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
@ -190,15 +179,17 @@ static unsigned int wait_reply(void)
{
if ((ret = read( NtCurrentTeb()->socket, &res, sizeof(res) )) == sizeof(res))
return res;
if (!ret) break;
if (ret == -1)
{
if (errno == EINTR) continue;
if (errno == EPIPE) CLIENT_Die();
if (errno == EPIPE) break;
server_perror("read");
}
if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
server_protocol_error( "partial msg received %d/%d\n", ret, sizeof(res) );
}
/* the server closed the connection; time to die... */
SYSDEPS_ExitThread(0);
}
@ -248,15 +239,17 @@ static unsigned int wait_reply_fd( int *fd )
#endif
return res;
}
if (!ret) break;
if (ret == -1)
{
if (errno == EINTR) continue;
if (errno == EPIPE) CLIENT_Die();
if (errno == EPIPE) break;
server_perror("recvmsg");
}
if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
server_protocol_error( "partial seq received %d/%d\n", ret, sizeof(res) );
}
/* the server closed the connection; time to die... */
SYSDEPS_ExitThread(0);
}

View File

@ -627,12 +627,16 @@ error:
*/
void WINAPI ExitProcess( DWORD status )
{
EnterCriticalSection( &PROCESS_Current()->crit_section );
MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
LeaveCriticalSection( &PROCESS_Current()->crit_section );
struct terminate_process_request *req = get_req_buffer();
MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
TASK_KillTask( 0 );
TerminateProcess( GetCurrentProcess(), status );
/* send the exit code to the server */
req->handle = GetCurrentProcess();
req->exit_code = status;
server_call( REQ_TERMINATE_PROCESS );
exit( status );
}
/***********************************************************************
@ -649,10 +653,12 @@ void WINAPI ExitProcess16( WORD status )
*/
BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
{
BOOL ret;
struct terminate_process_request *req = get_req_buffer();
req->handle = handle;
req->exit_code = exit_code;
return !server_call( REQ_TERMINATE_PROCESS );
if ((ret = !server_call( REQ_TERMINATE_PROCESS )) && req->self) exit( exit_code );
return ret;
}

View File

@ -137,7 +137,7 @@ static void SYSDEPS_StartThread( TEB *teb )
TerminateThread( GetCurrentThread(), GetExceptionCode() );
}
__ENDTRY
SYSDEPS_ExitThread(); /* should never get here */
SYSDEPS_ExitThread(0); /* should never get here */
}
@ -153,31 +153,31 @@ int SYSDEPS_SpawnThread( TEB *teb )
#ifdef linux
if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, teb ) < 0)
CLONE_VM | CLONE_FS | SIGCHLD, teb ) < 0)
return -1;
/* FIXME: close the child socket in the parent process */
/* close( thread->socket );*/
close( teb->socket ); /* close the child socket in the parent */
return 0;
#endif
#ifdef HAVE_RFORK
DWORD *sp = (DWORD *)teb->stack_top;
*--sp = (DWORD)teb;
void **sp = (void **)teb->stack_top;
*--sp = teb;
*--sp = 0;
*--sp = (DWORD)SYSDEPS_StartThread;
__asm__(
"pushl %2;\n\t" /* RFPROC|RMEM */
*--sp = SYSDEPS_StartThread;
__asm__ __volatile__(
"pushl %2;\n\t" /* RFPROC|RFMEM|RFFDG */
"pushl $0;\n\t" /* 0 ? */
"movl %1,%%eax;\n\t" /* SYS_rfork */
".byte 0x9a; .long 0; .word 7;\n\t" /* lcall 7:0... FreeBSD syscall */
"cmpl $0, %%edx;\n\t"
"je 1f;\n\t"
"movl %0,%%esp;\n\t" /* father -> new thread */
"movl %0,%%esp;\n\t" /* child -> new thread */
"ret;\n"
"1:\n\t" /* child -> caller thread */
"1:\n\t" /* parent -> caller thread */
"addl $8,%%esp" :
: "r" (sp), "g" (SYS_rfork), "g" (RFPROC|RFMEM)
: "r" (sp), "g" (SYS_rfork), "g" (RFPROC|RFMEM|RFFDG)
: "eax", "edx");
close( teb->socket ); /* close the child socket in the parent */
return 0;
#endif
@ -202,15 +202,14 @@ int SYSDEPS_SpawnThread( TEB *teb )
* SYSDEPS_ExitThread
*
* Exit a running thread; must not return.
* Must not make any reference to the thread structures (THDB etc.) as
* they have already been deleted.
*/
void SYSDEPS_ExitThread(void)
void SYSDEPS_ExitThread( int status )
{
#if !defined(__i386__) && defined(HAVE__LWP_CREATE)
#ifdef HAVE__LWP_CREATE
close( NtCurrentTeb()->socket );
_lwp_exit();
#endif
_exit( 0 );
_exit( status );
}

View File

@ -336,8 +336,23 @@ HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
*/
void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
{
MODULE_DllThreadDetach( NULL );
TerminateThread( GetCurrentThread(), code );
struct terminate_thread_request *req = get_req_buffer();
/* send the exit code to the server */
req->handle = GetCurrentThread();
req->exit_code = code;
server_call( REQ_TERMINATE_THREAD );
if (req->last)
{
MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
TASK_KillTask( 0 );
exit( code );
}
else
{
MODULE_DllThreadDetach( NULL );
SYSDEPS_ExitThread( code );
}
}
@ -590,10 +605,16 @@ BOOL WINAPI TerminateThread(
HANDLE handle, /* [in] Handle to thread */
DWORD exitcode) /* [in] Exit code for thread */
{
BOOL ret;
struct terminate_thread_request *req = get_req_buffer();
req->handle = handle;
req->exit_code = exitcode;
return !server_call( REQ_TERMINATE_THREAD );
if ((ret = !server_call( REQ_TERMINATE_THREAD )) && req->self)
{
if (req->last) exit( exitcode );
else SYSDEPS_ExitThread( exitcode );
}
return ret;
}

View File

@ -399,10 +399,16 @@ void resume_process( struct process *process )
}
/* kill a process on the spot */
void kill_process( struct process *process, int exit_code )
static void kill_process( struct process *process, struct thread *skip, int exit_code )
{
while (process->thread_list)
kill_thread( process->thread_list, exit_code );
struct thread *thread = process->thread_list;
while (thread)
{
struct thread *next = thread->proc_next;
thread->exit_code = exit_code;
if (thread != skip) kill_thread( thread, 1 );
thread = next;
}
}
/* kill all processes being debugged by a given thread */
@ -416,7 +422,7 @@ void kill_debugged_processes( struct thread *debugger, int exit_code )
process = process->next;
if (!process) return;
process->debugger = NULL;
kill_process( process, exit_code );
kill_process( process, NULL, exit_code );
}
}
@ -678,7 +684,8 @@ DECL_HANDLER(terminate_process)
if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
{
kill_process( process, req->exit_code );
req->self = (current->process == process);
kill_process( process, current, req->exit_code );
release_object( process );
}
}

View File

@ -73,7 +73,6 @@ extern void remove_process_thread( struct process *process,
struct thread *thread );
extern void suspend_process( struct process *process );
extern void resume_process( struct process *process );
extern void kill_process( struct process *process, int exit_code );
extern void kill_debugged_processes( struct thread *debugger, int exit_code );
extern struct process_snapshot *process_snap( int *count );

View File

@ -117,21 +117,21 @@ static int attach_thread( struct thread *thread )
}
/* detach from a Unix thread and kill it */
void detach_thread( struct thread *thread )
void detach_thread( struct thread *thread, int sig )
{
if (!thread->unix_pid) return;
if (thread->attached)
{
/* make sure it is stopped */
if (!(thread->suspend + thread->process->suspend)) stop_thread( thread );
kill( thread->unix_pid, SIGTERM );
if (sig) kill( thread->unix_pid, sig );
if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
ptrace( PTRACE_DETACH, thread->unix_pid, 1, SIGTERM );
ptrace( PTRACE_DETACH, thread->unix_pid, 1, sig );
thread->attached = 0;
}
else
{
kill( thread->unix_pid, SIGTERM );
if (sig) kill( thread->unix_pid, sig );
if (thread->suspend + thread->process->suspend) continue_thread( thread );
}
}

View File

@ -98,7 +98,8 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
fprintf( stderr, "Protocol error:%p: ", thread );
vfprintf( stderr, err, args );
va_end( args );
kill_thread( thread, PROTOCOL_ERROR );
thread->exit_code = 1;
kill_thread( thread, 1 );
}
/* die on a fatal error */
@ -193,12 +194,13 @@ void read_request( struct thread *thread )
if (ret == -1)
{
perror("recvmsg");
kill_thread( thread, BROKEN_PIPE );
thread->exit_code = 1;
kill_thread( thread, 1 );
return;
}
if (!ret) /* closed pipe */
{
kill_thread( thread, BROKEN_PIPE );
kill_thread( thread, 0 );
return;
}
fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
@ -212,7 +214,6 @@ int write_request( struct thread *thread )
if (thread->pass_fd == -1)
{
ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
if (ret == sizeof(thread->error)) goto ok;
}
else /* we have an fd to send */
{
@ -231,20 +232,33 @@ int write_request( struct thread *thread )
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
close( thread->pass_fd );
thread->pass_fd = -1;
if (ret == sizeof(thread->error)) goto ok;
}
if (ret == sizeof(thread->error))
{
set_select_events( &thread->obj, POLLIN );
return 1;
}
if (ret == -1)
{
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
if (errno != EPIPE) perror("sendmsg");
if (errno == EPIPE)
{
kill_thread( thread, 0 ); /* normal death */
}
else
{
perror("sendmsg");
thread->exit_code = 1;
kill_thread( thread, 1 );
}
}
else
{
thread->exit_code = 1;
kill_thread( thread, 1 );
fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
}
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
kill_thread( thread, BROKEN_PIPE );
return -1;
ok:
set_select_events( &thread->obj, POLLIN );
return 1;
}
static void master_socket_dump( struct object *obj, int verbose )

View File

@ -16,11 +16,6 @@
/* max request length */
#define MAX_REQUEST_LENGTH 8192
/* exit code passed to remove_client on communication error */
#define OUT_OF_MEMORY -1
#define BROKEN_PIPE -2
#define PROTOCOL_ERROR -3
/* request handler definition */
#define DECL_HANDLER(name) void req_##name( struct name##_request *req )

View File

@ -137,7 +137,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend )
thread->pass_fd = -1;
thread->state = RUNNING;
thread->attached = 0;
thread->exit_code = STILL_ACTIVE;
thread->exit_code = 0;
thread->next = NULL;
thread->prev = NULL;
thread->priority = THREAD_PRIORITY_NORMAL;
@ -175,7 +175,7 @@ void thread_poll_event( struct object *obj, int event )
struct thread *thread = (struct thread *)obj;
assert( obj->ops == &thread_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, BROKEN_PIPE );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
else
{
if (event & POLLOUT) write_request( thread );
@ -556,20 +556,25 @@ static void get_selector_entry( struct thread *thread, int entry,
}
/* kill a thread on the spot */
void kill_thread( struct thread *thread, int exit_code )
void kill_thread( struct thread *thread, int violent_death )
{
if (thread->state == TERMINATED) return; /* already killed */
thread->state = TERMINATED;
thread->exit_code = exit_code;
if (current == thread) current = NULL;
if (debug_level)
fprintf( stderr,"%08x: *killed* exit_code=%d\n", (unsigned int)thread, exit_code );
if (thread->wait) end_wait( thread );
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
(unsigned int)thread, thread->exit_code );
if (thread->wait)
{
end_wait( thread );
/* if it is waiting on the socket, we don't need to send a SIGTERM */
violent_death = 0;
}
debug_exit_thread( thread );
abandon_mutexes( thread );
remove_process_thread( thread->process, thread );
wake_up( &thread->obj, 0 );
detach_thread( thread );
detach_thread( thread, violent_death ? SIGTERM : 0 );
remove_select_user( &thread->obj );
release_object( thread );
}
@ -639,9 +644,17 @@ DECL_HANDLER(terminate_thread)
{
struct thread *thread;
req->self = 0;
req->last = 0;
if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
{
kill_thread( thread, req->exit_code );
thread->exit_code = req->exit_code;
if (thread != current) kill_thread( thread, 1 );
else
{
req->self = 1;
req->last = (thread->process->running_threads == 1);
}
release_object( thread );
}
}
@ -654,7 +667,7 @@ DECL_HANDLER(get_thread_info)
if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
{
req->tid = thread;
req->exit_code = thread->exit_code;
req->exit_code = (thread->state == TERMINATED) ? thread->exit_code : STILL_ACTIVE;
req->priority = thread->priority;
release_object( thread );
}

View File

@ -74,7 +74,7 @@ extern void suspend_all_threads( void );
extern void resume_all_threads( void );
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int exit_code );
extern void kill_thread( struct thread *thread, int violent_death );
extern void wake_up( struct object *obj, int max );
extern int sleep_on( int count, struct object *objects[], int flags,
int timeout, sleep_reply func );
@ -85,7 +85,7 @@ 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 );
extern void detach_thread( struct thread *thread, int sig );
extern int suspend_for_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 );

View File

@ -297,12 +297,23 @@ static void dump_terminate_process_request( const struct terminate_process_reque
fprintf( stderr, " exit_code=%d", req->exit_code );
}
static void dump_terminate_process_reply( const struct terminate_process_request *req )
{
fprintf( stderr, " self=%d", req->self );
}
static void dump_terminate_thread_request( const struct terminate_thread_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " exit_code=%d", req->exit_code );
}
static void dump_terminate_thread_reply( const struct terminate_thread_request *req )
{
fprintf( stderr, " self=%d,", req->self );
fprintf( stderr, " last=%d", req->last );
}
static void dump_get_process_info_request( const struct get_process_info_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
@ -1366,8 +1377,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_init_process_done_reply,
(dump_func)0,
(dump_func)dump_get_thread_buffer_reply,
(dump_func)0,
(dump_func)0,
(dump_func)dump_terminate_process_reply,
(dump_func)dump_terminate_thread_reply,
(dump_func)dump_get_process_info_reply,
(dump_func)0,
(dump_func)dump_get_thread_info_reply,