Commit 40043ed2 authored by Alexandre Julliard's avatar Alexandre Julliard

Added -k option to kill an existing wineserver.

parent bbea20d6
...@@ -46,13 +46,14 @@ static void usage(void) ...@@ -46,13 +46,14 @@ static void usage(void)
fprintf(stderr, " -d<n> set debug level to <n>\n"); fprintf(stderr, " -d<n> set debug level to <n>\n");
fprintf(stderr, " -p[n] make server persistent, optionally for n seconds\n"); fprintf(stderr, " -p[n] make server persistent, optionally for n seconds\n");
fprintf(stderr, " -w wait until the current wineserver terminates\n"); fprintf(stderr, " -w wait until the current wineserver terminates\n");
fprintf(stderr, " -k[n] kill the current wineserver, optionally with signal n\n");
fprintf(stderr, " -h display this help message\n"); fprintf(stderr, " -h display this help message\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
static void parse_args( int argc, char *argv[] ) static void parse_args( int argc, char *argv[] )
{ {
int i; int i, ret;
server_argv0 = argv[0]; server_argv0 = argv[0];
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
...@@ -76,6 +77,10 @@ static void parse_args( int argc, char *argv[] ) ...@@ -76,6 +77,10 @@ static void parse_args( int argc, char *argv[] )
case 'w': case 'w':
wait_for_lock(); wait_for_lock();
exit(0); exit(0);
case 'k':
if (isdigit(argv[i][2])) ret = kill_lock_owner( atoi(argv[i] + 2) );
else ret = kill_lock_owner(-1);
exit( !ret );
default: default:
fprintf( stderr, "wineserver: unknown option '%s'\n", argv[i] ); fprintf( stderr, "wineserver: unknown option '%s'\n", argv[i] );
usage(); usage();
......
...@@ -466,6 +466,20 @@ static void process_unload_dll( struct process *process, void *base ) ...@@ -466,6 +466,20 @@ static void process_unload_dll( struct process *process, void *base )
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
} }
/* kill all processes */
void kill_all_processes( struct process *skip, int exit_code )
{
for (;;)
{
struct process *process = first_process;
while (process && (!process->running_threads || process == skip))
process = process->next;
if (!process) break;
kill_process( process, NULL, exit_code );
}
}
/* kill all processes being attached to a console renderer */ /* kill all processes being attached to a console renderer */
void kill_console_processes( struct thread *renderer, int exit_code ) void kill_console_processes( struct thread *renderer, int exit_code )
{ {
......
...@@ -105,6 +105,7 @@ extern void remove_process_thread( struct process *process, ...@@ -105,6 +105,7 @@ extern void remove_process_thread( struct process *process,
struct thread *thread ); struct thread *thread );
extern void suspend_process( struct process *process ); extern void suspend_process( struct process *process );
extern void resume_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, struct thread *skip, int exit_code ); extern void kill_process( struct process *process, struct thread *skip, int exit_code );
extern void kill_console_processes( struct thread *renderer, int exit_code ); extern void kill_console_processes( struct thread *renderer, int exit_code );
extern void kill_debugged_processes( struct thread *debugger, int exit_code ); extern void kill_debugged_processes( struct thread *debugger, int exit_code );
......
...@@ -513,6 +513,28 @@ static void create_server_dir(void) ...@@ -513,6 +513,28 @@ static void create_server_dir(void)
free( server_dir ); free( server_dir );
} }
/* create the lock file and return its file descriptor */
static int create_server_lock(void)
{
struct stat st;
int fd;
if (lstat( server_lock_name, &st ) == -1)
{
if (errno != ENOENT)
fatal_perror( "lstat %s/%s", wine_get_server_dir(), server_lock_name );
}
else
{
if (!S_ISREG(st.st_mode))
fatal_error( "%s/%s is not a regular file\n", wine_get_server_dir(), server_lock_name );
}
if ((fd = open( server_lock_name, O_CREAT|O_TRUNC|O_WRONLY, 0600 )) == -1)
fatal_perror( "error creating %s/%s", wine_get_server_dir(), server_lock_name );
return fd;
}
/* wait for the server lock */ /* wait for the server lock */
int wait_for_lock(void) int wait_for_lock(void)
{ {
...@@ -520,8 +542,7 @@ int wait_for_lock(void) ...@@ -520,8 +542,7 @@ int wait_for_lock(void)
struct flock fl; struct flock fl;
create_server_dir(); create_server_dir();
if ((fd = open( server_lock_name, O_TRUNC|O_WRONLY, 0600 )) == -1) fd = create_server_lock();
return -1;
fl.l_type = F_WRLCK; fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET; fl.l_whence = SEEK_SET;
...@@ -533,28 +554,59 @@ int wait_for_lock(void) ...@@ -533,28 +554,59 @@ int wait_for_lock(void)
return r; return r;
} }
/* kill the wine server holding the lock */
int kill_lock_owner( int sig )
{
int fd, i, ret = 0;
pid_t pid = 0;
struct flock fl;
create_server_dir();
fd = create_server_lock();
for (i = 0; i < 10; i++)
{
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl( fd, F_GETLK, &fl ) == -1) goto done;
if (fl.l_type != F_WRLCK) goto done; /* the file is not locked */
if (!pid) /* first time around */
{
if (!(pid = fl.l_pid)) goto done; /* shouldn't happen */
if (sig == -1)
{
if (kill( pid, SIGINT ) == -1) goto done;
kill( pid, SIGCONT );
ret = 1;
}
else /* just send the specified signal and return */
{
ret = (kill( pid, sig ) != -1);
goto done;
}
}
else if (fl.l_pid != pid) goto done; /* no longer the same process */
sleep( 1 );
}
/* waited long enough, now kill it */
kill( pid, SIGKILL );
done:
close( fd );
return ret;
}
/* acquire the main server lock */ /* acquire the main server lock */
static void acquire_lock(void) static void acquire_lock(void)
{ {
const char *server_dir_name = wine_get_server_dir();
struct sockaddr_un addr; struct sockaddr_un addr;
struct stat st; struct stat st;
struct flock fl; struct flock fl;
int fd, slen, got_lock = 0; int fd, slen, got_lock = 0;
if (lstat( server_lock_name, &st ) == -1) fd = create_server_lock();
{
if (errno != ENOENT)
fatal_perror( "lstat %s/%s", server_dir_name, server_lock_name );
}
else
{
if (!S_ISREG(st.st_mode))
fatal_error( "%s/%s is not a regular file\n", server_dir_name, server_lock_name );
}
if ((fd = open( server_lock_name, O_CREAT|O_TRUNC|O_WRONLY, 0600 )) == -1)
fatal_perror( "error creating %s/%s", server_dir_name, server_lock_name );
fl.l_type = F_WRLCK; fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET; fl.l_whence = SEEK_SET;
...@@ -570,7 +622,7 @@ static void acquire_lock(void) ...@@ -570,7 +622,7 @@ static void acquire_lock(void)
"Warning: a previous instance of the wine server seems to have crashed.\n" "Warning: a previous instance of the wine server seems to have crashed.\n"
"Please run 'gdb %s %s/core',\n" "Please run 'gdb %s %s/core',\n"
"type 'backtrace' at the gdb prompt and report the results. Thanks.\n\n", "type 'backtrace' at the gdb prompt and report the results. Thanks.\n\n",
server_argv0, server_dir_name ); server_argv0, wine_get_server_dir() );
} }
unlink( server_socket_name ); /* we got the lock, we can safely remove the socket */ unlink( server_socket_name ); /* we got the lock, we can safely remove the socket */
got_lock = 1; got_lock = 1;
...@@ -590,7 +642,7 @@ static void acquire_lock(void) ...@@ -590,7 +642,7 @@ static void acquire_lock(void)
case EAGAIN: case EAGAIN:
exit(2); /* we didn't get the lock, exit with special status */ exit(2); /* we didn't get the lock, exit with special status */
default: default:
fatal_perror( "fcntl %s/%s", server_dir_name, server_lock_name ); fatal_perror( "fcntl %s/%s", wine_get_server_dir(), server_lock_name );
} }
/* it seems we can't use locks on this fs, so we will use the socket existence as lock */ /* it seems we can't use locks on this fs, so we will use the socket existence as lock */
close( fd ); close( fd );
......
...@@ -60,6 +60,7 @@ extern void open_master_socket(void); ...@@ -60,6 +60,7 @@ extern void open_master_socket(void);
extern void close_master_socket(void); extern void close_master_socket(void);
extern void lock_master_socket( int locked ); extern void lock_master_socket( int locked );
extern int wait_for_lock(void); extern int wait_for_lock(void);
extern int kill_lock_owner( int sig );
extern void trace_request(void); extern void trace_request(void);
extern void trace_reply( enum request req, const union generic_reply *reply ); extern void trace_reply( enum request req, const union generic_reply *reply );
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "object.h" #include "object.h"
#include "thread.h" #include "thread.h"
#include "process.h"
struct timeout_user struct timeout_user
{ {
...@@ -229,6 +229,14 @@ static void sigterm_handler() ...@@ -229,6 +229,14 @@ static void sigterm_handler()
exit(1); exit(1);
} }
/* SIGINT handler */
static void sigint_handler()
{
kill_all_processes( NULL, 1 );
flush_registry();
exit(1);
}
/* server main loop */ /* server main loop */
void select_loop(void) void select_loop(void)
{ {
...@@ -252,8 +260,9 @@ void select_loop(void) ...@@ -252,8 +260,9 @@ void select_loop(void)
sigaction( SIGCHLD, &action, NULL ); sigaction( SIGCHLD, &action, NULL );
action.sa_handler = sighup_handler; action.sa_handler = sighup_handler;
sigaction( SIGHUP, &action, NULL ); sigaction( SIGHUP, &action, NULL );
action.sa_handler = sigterm_handler; action.sa_handler = sigint_handler;
sigaction( SIGINT, &action, NULL ); sigaction( SIGINT, &action, NULL );
action.sa_handler = sigterm_handler;
sigaction( SIGQUIT, &action, NULL ); sigaction( SIGQUIT, &action, NULL );
sigaction( SIGTERM, &action, NULL ); sigaction( SIGTERM, &action, NULL );
......
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