diff --git a/include/server.h b/include/server.h index 4e56dc42c51..fe14a9b778e 100644 --- a/include/server.h +++ b/include/server.h @@ -195,6 +195,15 @@ struct resume_thread_reply }; +/* Debugger support: freeze / unfreeze */ +struct debugger_request +{ + int op; /* operation type */ +}; + +enum debugger_op { DEBUGGER_FREEZE_ALL, DEBUGGER_UNFREEZE_ALL }; + + /* Queue an APC for a thread */ struct queue_apc_request { @@ -694,6 +703,7 @@ extern int CLIENT_InitServer(void); struct _THDB; extern int CLIENT_SetDebug( int level ); +extern int CLIENT_DebuggerRequest( int op ); extern int CLIENT_InitThread(void); #endif /* __WINE_SERVER__ */ diff --git a/include/server/request.h b/include/server/request.h index 56ecfaae9f0..6167edd31d4 100644 --- a/include/server/request.h +++ b/include/server/request.h @@ -18,6 +18,7 @@ enum request REQ_SET_THREAD_INFO, REQ_SUSPEND_THREAD, REQ_RESUME_THREAD, + REQ_DEBUGGER, REQ_QUEUE_APC, REQ_CLOSE_HANDLE, REQ_GET_HANDLE_INFO, @@ -80,6 +81,7 @@ DECL_HANDLER(get_thread_info); DECL_HANDLER(set_thread_info); DECL_HANDLER(suspend_thread); DECL_HANDLER(resume_thread); +DECL_HANDLER(debugger); DECL_HANDLER(queue_apc); DECL_HANDLER(close_handle); DECL_HANDLER(get_handle_info); @@ -139,6 +141,7 @@ static const struct handler { { (void(*)())req_set_thread_info, sizeof(struct set_thread_info_request) }, { (void(*)())req_suspend_thread, sizeof(struct suspend_thread_request) }, { (void(*)())req_resume_thread, sizeof(struct resume_thread_request) }, + { (void(*)())req_debugger, sizeof(struct debugger_request) }, { (void(*)())req_queue_apc, sizeof(struct queue_apc_request) }, { (void(*)())req_close_handle, sizeof(struct close_handle_request) }, { (void(*)())req_get_handle_info, sizeof(struct get_handle_info_request) }, diff --git a/include/server/thread.h b/include/server/thread.h index af56773e411..bc77a37dc4e 100644 --- a/include/server/thread.h +++ b/include/server/thread.h @@ -59,6 +59,8 @@ extern void set_thread_info( struct thread *thread, struct set_thread_info_request *req ); extern int suspend_thread( struct thread *thread ); extern int resume_thread( struct thread *thread ); +extern void suspend_all_threads( void ); +extern void resume_all_threads( void ); extern int send_reply( struct thread *thread, int pass_fd, int n, ... /* arg_1, len_1, ..., arg_n, len_n */ ); extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); diff --git a/scheduler/client.c b/scheduler/client.c index d08652b7eeb..e013044a351 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -293,6 +293,9 @@ int CLIENT_InitServer(void) perror("fork"); exit(1); case 0: /* child */ + close( fd[1] ); + break; + default: /* parent */ close( fd[0] ); sprintf( buffer, "%d", fd[1] ); /*#define EXEC_SERVER*/ @@ -303,9 +306,6 @@ int CLIENT_InitServer(void) #endif create_initial_thread( fd[1] ); exit(0); - default: /* parent */ - close( fd[1] ); - break; } return fd[0]; } @@ -341,3 +341,17 @@ int CLIENT_SetDebug( int level ) CLIENT_SendRequest( REQ_SET_DEBUG, -1, 1, &level, sizeof(level) ); return CLIENT_WaitReply( NULL, NULL, 0 ); } + +/*********************************************************************** + * CLIENT_DebuggerRequest + * + * Send a debugger support request. Return 0 if OK. + */ +int CLIENT_DebuggerRequest( int op ) +{ + struct debugger_request req; + req.op = op; + CLIENT_SendRequest( REQ_DEBUGGER, -1, 1, &req, sizeof(req) ); + return CLIENT_WaitReply( NULL, NULL, 0 ); +} + diff --git a/server/request.c b/server/request.c index 25bd3534f5c..01d64c5ca71 100644 --- a/server/request.c +++ b/server/request.c @@ -315,6 +315,23 @@ DECL_HANDLER(set_thread_info) send_reply( current, -1, 0 ); } +/* debugger support operations */ +DECL_HANDLER(debugger) +{ + switch ( req->op ) + { + case DEBUGGER_FREEZE_ALL: + suspend_all_threads(); + break; + + case DEBUGGER_UNFREEZE_ALL: + resume_all_threads(); + break; + } + + send_reply( current, -1, 0 ); +} + /* suspend a thread */ DECL_HANDLER(suspend_thread) { diff --git a/server/thread.c b/server/thread.c index bf8a2ca19bf..e86cd6d9f24 100644 --- a/server/thread.c +++ b/server/thread.c @@ -102,6 +102,7 @@ void create_initial_thread( int fd ) initial_thread.process = create_initial_process(); add_process_thread( initial_thread.process, &initial_thread ); add_client( fd, &initial_thread ); + grab_object( &initial_thread ); /* so that we never free it */ select_loop(); } @@ -242,6 +243,24 @@ int resume_thread( struct thread *thread ) return old_count; } +/* suspend all threads but the current */ +void suspend_all_threads( void ) +{ + struct thread *thread; + for ( thread = first_thread; thread; thread = thread->next ) + if ( thread != current ) + suspend_thread( thread ); +} + +/* resume all threads but the current */ +void resume_all_threads( void ) +{ + struct thread *thread; + for ( thread = first_thread; thread; thread = thread->next ) + if ( thread != current ) + resume_thread( thread ); +} + /* send a reply to a thread */ int send_reply( struct thread *thread, int pass_fd, int n, ... /* arg_1, len_1, ..., arg_n, len_n */ ) diff --git a/server/trace.c b/server/trace.c index f1ab987e90c..260b16b22c9 100644 --- a/server/trace.c +++ b/server/trace.c @@ -160,6 +160,12 @@ static int dump_resume_thread_reply( struct resume_thread_reply *req, int len ) return (int)sizeof(*req); } +static int dump_debugger_request( struct debugger_request *req, int len ) +{ + fprintf( stderr, " op=%d", req->op ); + return (int)sizeof(*req); +} + static int dump_queue_apc_request( struct queue_apc_request *req, int len ) { fprintf( stderr, " handle=%d,", req->handle ); @@ -663,6 +669,8 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] = (void(*)())dump_suspend_thread_reply }, { (int(*)(void *,int))dump_resume_thread_request, (void(*)())dump_resume_thread_reply }, + { (int(*)(void *,int))dump_debugger_request, + (void(*)())0 }, { (int(*)(void *,int))dump_queue_apc_request, (void(*)())0 }, { (int(*)(void *,int))dump_close_handle_request, @@ -762,6 +770,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = "set_thread_info", "suspend_thread", "resume_thread", + "debugger", "queue_apc", "close_handle", "get_handle_info",