Commit af268c62 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent 307cb09a
......@@ -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 );
}
}
......@@ -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 );
......
......@@ -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)
{
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)
void close_master_socket( timeout_t timeout )
{
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 );
}
......@@ -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 );
......
......@@ -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();
}
......
......@@ -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 },
......
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