server: Redesign the server shutdown processing.

System processes are now killed only after the server persistence
delay has expired. New processes are not allowed to start during
shutdown.
This commit is contained in:
Alexandre Julliard 2008-01-02 16:16:00 +01:00
parent 307cb09a62
commit af268c6211
6 changed files with 69 additions and 49 deletions

View File

@ -53,7 +53,9 @@
static struct list process_list = LIST_INIT(process_list);
static int running_processes, user_processes;
static struct event *user_process_event; /* signaled when all user processes have exited */
static struct event *shutdown_event; /* signaled when shutdown starts */
static struct timeout_user *shutdown_timeout; /* timeout for server shutdown */
static int shutting_down; /* are we in the process of shutting down the server? */
/* process operations */
@ -227,17 +229,32 @@ static void set_process_startup_state( struct process *process, enum startup_sta
}
}
/* callback for server shutdown */
static void server_shutdown_timeout( void *arg )
{
shutdown_timeout = NULL;
if (!running_processes) close_master_socket( 0 );
else
{
if (debug_level) fprintf( stderr, "wineserver: shutting down\n" );
if (shutdown_event) set_event( shutdown_event );
/* leave 2 seconds for system processes to exit */
close_master_socket( 2 * -TICKS_PER_SEC );
shutting_down = 1;
}
}
/* final cleanup once we are sure a process is really dead */
static void process_died( struct process *process )
{
if (debug_level) fprintf( stderr, "%04x: *process killed*\n", process->id );
if (!process->is_system)
{
if (!--user_processes && user_process_event)
set_event( user_process_event );
if (!--user_processes && master_socket_timeout != TIMEOUT_INFINITE)
shutdown_timeout = add_timeout_user( master_socket_timeout, server_shutdown_timeout, NULL );
}
release_object( process );
if (!--running_processes) close_master_socket();
if (!--running_processes && shutting_down) close_master_socket( 0 );
}
/* callback for process sigkill timeout */
@ -353,7 +370,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
error:
if (process) release_object( process );
/* if we failed to start our first process, close everything down */
if (!running_processes) close_master_socket();
if (!running_processes) close_master_socket( 0 );
return NULL;
}
@ -558,7 +575,7 @@ static void terminate_process( struct process *process, struct thread *skip, int
}
/* kill all processes */
void kill_all_processes( struct process *skip, int exit_code )
static void kill_all_processes( struct process *skip, int exit_code )
{
for (;;)
{
@ -574,6 +591,19 @@ void kill_all_processes( struct process *skip, int exit_code )
}
}
/* forced shutdown, used for wineserver -k */
void shutdown_master_socket(void)
{
kill_all_processes( NULL, 1 );
master_socket_timeout = 0;
if (shutdown_timeout)
{
remove_timeout_user( shutdown_timeout );
shutdown_timeout = NULL;
}
if (!shutting_down) server_shutdown_timeout( NULL );
}
/* kill all processes being attached to a console renderer */
void kill_console_processes( struct thread *renderer, int exit_code )
{
@ -634,8 +664,11 @@ void add_process_thread( struct process *process, struct thread *thread )
running_processes++;
if (!process->is_system)
{
if (!user_processes++ && user_process_event)
reset_event( user_process_event );
if (!user_processes++ && shutdown_timeout)
{
remove_timeout_user( shutdown_timeout );
shutdown_timeout = NULL;
}
}
}
grab_object( thread );
@ -860,6 +893,12 @@ DECL_HANDLER(new_process)
close( socket_fd );
return;
}
if (shutting_down)
{
set_error( STATUS_SHUTDOWN_IN_PROGRESS );
close( socket_fd );
return;
}
/* build the startup info for a new process */
if (!(info = alloc_object( &startup_info_ops ))) return;
@ -1179,19 +1218,20 @@ DECL_HANDLER(make_process_system)
{
struct process *process = current->process;
if (!user_process_event)
if (!shutdown_event)
{
if (!(user_process_event = create_event( NULL, NULL, 0, 1, 0, NULL ))) return;
make_object_static( (struct object *)user_process_event );
if (!(shutdown_event = create_event( NULL, NULL, 0, 1, 0, NULL ))) return;
make_object_static( (struct object *)shutdown_event );
}
if (!(reply->event = alloc_handle( current->process, user_process_event, SYNCHRONIZE, 0 )))
if (!(reply->event = alloc_handle( current->process, shutdown_event, SYNCHRONIZE, 0 )))
return;
if (!process->is_system)
{
process->is_system = 1;
close_process_desktop( process );
if (!--user_processes) set_event( user_process_event );
if (!--user_processes && master_socket_timeout != TIMEOUT_INFINITE)
shutdown_timeout = add_timeout_user( master_socket_timeout, server_shutdown_timeout, NULL );
}
}

View File

@ -121,7 +121,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_all_processes( struct process *skip, int exit_code );
extern void kill_process( struct process *process, int violent_death );
extern void kill_console_processes( struct thread *renderer, int exit_code );
extern void kill_debugged_processes( struct thread *debugger, int exit_code );

View File

@ -78,7 +78,6 @@ struct master_socket
{
struct object obj; /* object header */
struct fd *fd; /* file descriptor of the master socket */
struct timeout_user *timeout; /* timeout on last process exit */
};
static void master_socket_dump( struct object *obj, int verbose );
@ -123,7 +122,7 @@ unsigned int global_error = 0; /* global error code for when no thread is curre
timeout_t server_start_time = 0; /* server startup time */
static struct master_socket *master_socket; /* the master socket object */
static int force_shutdown;
static struct timeout_user *master_timeout;
/* socket communication static structures */
static struct iovec myiovec;
@ -508,11 +507,6 @@ static void master_socket_poll_event( struct fd *fd, int event )
unsigned int len = sizeof(dummy);
int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
if (client == -1) return;
if (sock->timeout)
{
remove_timeout_user( sock->timeout );
sock->timeout = NULL;
}
fcntl( client, F_SETFL, O_NONBLOCK );
create_process( client, NULL, 0 );
}
@ -731,7 +725,6 @@ static void acquire_lock(void)
if (!(master_socket = alloc_object( &master_socket_ops )) ||
!(master_socket->fd = create_anonymous_fd( &master_socket_fd_ops, fd, &master_socket->obj, 0 )))
fatal_error( "out of memory\n" );
master_socket->timeout = NULL;
set_fd_events( master_socket->fd, POLLIN );
make_object_static( &master_socket->obj );
}
@ -810,40 +803,29 @@ void open_master_socket(void)
/* master socket timer expiration handler */
static void close_socket_timeout( void *arg )
{
master_socket->timeout = NULL;
master_timeout = NULL;
flush_registry();
/* if a new client is waiting, we keep on running */
if (!force_shutdown && check_fd_events( master_socket->fd, POLLIN )) return;
if (debug_level) fprintf( stderr, "wineserver: exiting (pid=%ld)\n", (long) getpid() );
#ifdef DEBUG_OBJECTS
close_objects(); /* shut down everything properly */
#endif
exit( force_shutdown );
exit( 0 );
}
/* close the master socket and stop waiting for new clients */
void close_master_socket(void)
void close_master_socket( timeout_t timeout )
{
if (master_socket_timeout == TIMEOUT_INFINITE) return; /* just keep running forever */
if (master_socket_timeout)
master_socket->timeout = add_timeout_user( master_socket_timeout, close_socket_timeout, NULL );
else
close_socket_timeout( NULL ); /* close it right away */
}
/* forced shutdown, used for wineserver -k */
void shutdown_master_socket(void)
{
force_shutdown = 1;
master_socket_timeout = 0;
if (master_socket->timeout)
if (master_socket)
{
remove_timeout_user( master_socket->timeout );
close_socket_timeout( NULL );
release_object( master_socket );
master_socket = NULL;
}
set_fd_events( master_socket->fd, -1 ); /* stop waiting for new clients */
if (master_timeout) /* cancel previous timeout */
remove_timeout_user( master_timeout );
if (timeout)
master_timeout = add_timeout_user( timeout, close_socket_timeout, NULL );
else /* close it right away */
close_socket_timeout( NULL );
}

View File

@ -57,7 +57,7 @@ extern void read_request( struct thread *thread );
extern void write_reply( struct thread *thread );
extern unsigned int get_tick_count(void);
extern void open_master_socket(void);
extern void close_master_socket(void);
extern void close_master_socket( timeout_t timeout );
extern void shutdown_master_socket(void);
extern int wait_for_lock(void);
extern int kill_lock_owner( int sig );

View File

@ -190,8 +190,6 @@ static void sigterm_callback(void)
/* SIGINT callback */
static void sigint_callback(void)
{
kill_all_processes( NULL, 1 );
flush_registry();
shutdown_master_socket();
}

View File

@ -4546,6 +4546,7 @@ static const struct
{ "SECTION_TOO_BIG", STATUS_SECTION_TOO_BIG },
{ "SEMAPHORE_LIMIT_EXCEEDED", STATUS_SEMAPHORE_LIMIT_EXCEEDED },
{ "SHARING_VIOLATION", STATUS_SHARING_VIOLATION },
{ "SHUTDOWN_IN_PROGRESS", STATUS_SHUTDOWN_IN_PROGRESS },
{ "SUSPEND_COUNT_EXCEEDED", STATUS_SUSPEND_COUNT_EXCEEDED },
{ "THREAD_IS_TERMINATING", STATUS_THREAD_IS_TERMINATING },
{ "TIMEOUT", STATUS_TIMEOUT },