Added generic signal handling mechanism based on pipes to synchronize
signals with the main poll loop.

diff --git a/server/Makefile.in b/server/Makefile.in
index ca0bb2a..149e9ec 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -33,6 +33,7 @@
 	request.c \
 	semaphore.c \
 	serial.c \
+	signal.c \
 	smb.c \
 	snapshot.c \
 	sock.c \
diff --git a/server/fd.c b/server/fd.c
index 05347de..7417dee 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -309,57 +309,10 @@
 }
 
 
-/* SIGHUP handler */
-static void sighup_handler()
-{
-#ifdef DEBUG_OBJECTS
-    dump_objects();
-#endif
-}
-
-/* SIGTERM handler */
-static void sigterm_handler()
-{
-    flush_registry();
-    exit(1);
-}
-
-/* SIGINT handler */
-static void sigint_handler()
-{
-    kill_all_processes( NULL, 1 );
-    flush_registry();
-    exit(1);
-}
-
 /* server main poll() loop */
 void main_loop(void)
 {
     int ret;
-    sigset_t sigset;
-    struct sigaction action;
-
-    /* block the signals we use */
-    sigemptyset( &sigset );
-    sigaddset( &sigset, SIGCHLD );
-    sigaddset( &sigset, SIGHUP );
-    sigaddset( &sigset, SIGINT );
-    sigaddset( &sigset, SIGQUIT );
-    sigaddset( &sigset, SIGTERM );
-    sigprocmask( SIG_BLOCK, &sigset, NULL );
-
-    /* set the handlers */
-    action.sa_mask = sigset;
-    action.sa_flags = 0;
-    action.sa_handler = sigchld_handler;
-    sigaction( SIGCHLD, &action, NULL );
-    action.sa_handler = sighup_handler;
-    sigaction( SIGHUP, &action, NULL );
-    action.sa_handler = sigint_handler;
-    sigaction( SIGINT, &action, NULL );
-    action.sa_handler = sigterm_handler;
-    sigaction( SIGQUIT, &action, NULL );
-    sigaction( SIGTERM, &action, NULL );
 
     while (active_users)
     {
@@ -380,16 +333,7 @@
             }
             if (!active_users) break;  /* last user removed by a timeout */
         }
-
-        sigprocmask( SIG_UNBLOCK, &sigset, NULL );
-
-        /* Note: we assume that the signal handlers do not manipulate the pollfd array
-         *       or the timeout list, otherwise there is a race here.
-         */
         ret = poll( pollfd, nb_users, diff );
-
-        sigprocmask( SIG_BLOCK, &sigset, NULL );
-
         if (ret > 0)
         {
             int i;
diff --git a/server/main.c b/server/main.c
index b68268e..8515525 100644
--- a/server/main.c
+++ b/server/main.c
@@ -110,27 +110,25 @@
     exit(1);  /* make sure atexit functions get called */
 }
 
-/* initialize signal handling */
-static void signal_init(void)
+int main( int argc, char *argv[] )
 {
+    parse_args( argc, argv );
+
+    /* setup temporary handlers before the real signal initialization is done */
     signal( SIGPIPE, SIG_IGN );
     signal( SIGHUP, sigterm_handler );
     signal( SIGINT, sigterm_handler );
     signal( SIGQUIT, sigterm_handler );
     signal( SIGTERM, sigterm_handler );
     signal( SIGABRT, sigterm_handler );
-}
 
-int main( int argc, char *argv[] )
-{
-    parse_args( argc, argv );
-    signal_init();
     sock_init();
     open_master_socket();
     sync_namespace = create_namespace( 37, TRUE );
     setvbuf( stderr, NULL, _IOLBF, 0 );
 
     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
+    init_signals();
     init_registry();
     main_loop();
 
diff --git a/server/object.h b/server/object.h
index 256c99e..1815e24 100644
--- a/server/object.h
+++ b/server/object.h
@@ -145,6 +145,11 @@
 extern void close_registry(void);
 extern void registry_close_handle( struct object *obj, obj_handle_t hkey );
 
+/* signal functions */
+
+extern void init_signals(void);
+extern void close_signals(void);
+
 /* atom functions */
 
 extern void close_atom_table(void);
diff --git a/server/ptrace.c b/server/ptrace.c
index 002bc8f..5323007 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -109,7 +109,7 @@
 }
 
 /* handle a SIGCHLD signal */
-void sigchld_handler()
+void sigchld_callback(void)
 {
     int pid, status;
 
diff --git a/server/request.c b/server/request.c
index 6b3b4b6..d598486 100644
--- a/server/request.c
+++ b/server/request.c
@@ -784,6 +784,7 @@
 #ifdef DEBUG_OBJECTS
     /* shut down everything properly */
     release_object( master_socket );
+    close_signals();
     close_global_hooks();
     close_global_handles();
     close_registry();
diff --git a/server/signal.c b/server/signal.c
new file mode 100644
index 0000000..3388a66
--- /dev/null
+++ b/server/signal.c
@@ -0,0 +1,257 @@
+/*
+ * Server signal handling
+ *
+ * Copyright (C) 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <signal.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#include <unistd.h>
+
+#include "file.h"
+#include "object.h"
+#include "process.h"
+#include "thread.h"
+
+typedef void (*signal_callback)(void);
+
+struct handler
+{
+    struct object    obj;         /* object header */
+    struct fd       *fd;          /* file descriptor for the pipe side */
+    int              pipe_write;  /* unix fd for the pipe write side */
+    volatile int     pending;     /* is signal pending? */
+    signal_callback  callback;    /* callback function */
+};
+
+static void handler_dump( struct object *obj, int verbose );
+static void handler_destroy( struct object *obj );
+
+static const struct object_ops handler_ops =
+{
+    sizeof(struct handler),   /* size */
+    handler_dump,             /* dump */
+    no_add_queue,             /* add_queue */
+    NULL,                     /* remove_queue */
+    NULL,                     /* signaled */
+    NULL,                     /* satisfied */
+    no_get_fd,                /* get_fd */
+    handler_destroy           /* destroy */
+};
+
+static void handler_poll_event( struct fd *fd, int event );
+
+static const struct fd_ops handler_fd_ops =
+{
+    NULL,                     /* get_poll_events */
+    handler_poll_event,       /* poll_event */
+    no_flush,                 /* flush */
+    no_get_file_info,         /* get_file_info */
+    no_queue_async            /* queue_async */
+};
+
+static struct handler *handler_sighup;
+static struct handler *handler_sigterm;
+static struct handler *handler_sigint;
+static struct handler *handler_sigchld;
+static struct handler *handler_sigio;
+
+static sigset_t blocked_sigset;
+
+/* create a signal handler */
+static struct handler *create_handler( signal_callback callback )
+{
+    struct handler *handler;
+    int fd[2];
+
+    if (pipe( fd ) == -1) return NULL;
+    if (!(handler = alloc_object( &handler_ops )))
+    {
+        close( fd[0] );
+        close( fd[1] );
+        return NULL;
+    }
+    handler->pipe_write = fd[1];
+    handler->pending    = 0;
+    handler->callback   = callback;
+
+    if (!(handler->fd = create_anonymous_fd( &handler_fd_ops, fd[0], &handler->obj )))
+    {
+        release_object( handler );
+        return NULL;
+    }
+    set_fd_events( handler->fd, POLLIN );
+    return handler;
+}
+
+/* handle a signal received for a given handler */
+static void do_signal( struct handler *handler )
+{
+    if (!handler->pending)
+    {
+        char dummy;
+        handler->pending = 1;
+        write( handler->pipe_write, &dummy, 1 );
+    }
+}
+
+static void handler_dump( struct object *obj, int verbose )
+{
+    struct handler *handler = (struct handler *)obj;
+    fprintf( stderr, "Signal handler fd=%p\n", handler->fd );
+}
+
+static void handler_destroy( struct object *obj )
+{
+    struct handler *handler = (struct handler *)obj;
+    if (handler->fd) release_object( handler->fd );
+    close( handler->pipe_write );
+}
+
+static void handler_poll_event( struct fd *fd, int event )
+{
+    struct handler *handler = get_fd_user( fd );
+
+    if (event & (POLLERR | POLLHUP))
+    {
+        /* this is not supposed to happen */
+        fprintf( stderr, "wineserver: Error on signal handler pipe\n" );
+        release_object( handler );
+    }
+    else if (event & POLLIN)
+    {
+        char dummy;
+
+        handler->pending = 0;
+        read( get_unix_fd( handler->fd ), &dummy, 1 );
+        handler->callback();
+    }
+}
+
+/* SIGHUP callback */
+static void sighup_callback(void)
+{
+#ifdef DEBUG_OBJECTS
+    dump_objects();
+#endif
+}
+
+/* SIGTERM callback */
+static void sigterm_callback(void)
+{
+    flush_registry();
+    exit(1);
+}
+
+/* SIGINT callback */
+static void sigint_callback(void)
+{
+    kill_all_processes( NULL, 1 );
+    flush_registry();
+    exit(1);
+}
+
+/* SIGIO callback */
+static void sigio_callback(void)
+{
+    /* nothing here yet */
+}
+
+/* SIGHUP handler */
+static void do_sighup()
+{
+    do_signal( handler_sighup );
+}
+
+/* SIGTERM handler */
+static void do_sigterm()
+{
+    do_signal( handler_sigterm );
+}
+
+/* SIGINT handler */
+static void do_sigint()
+{
+    do_signal( handler_sigint );
+}
+
+/* SIGCHLD handler */
+static void do_sigchld()
+{
+    do_signal( handler_sigchld );
+}
+
+/* SIGIO handler */
+static void do_sigio( int signum, siginfo_t *si, void *x )
+{
+    /* do_change_notify( si->si_fd ); */
+    do_signal( handler_sigio );
+}
+
+void init_signals(void)
+{
+    struct sigaction action;
+
+    if (!(handler_sighup  = create_handler( sighup_callback ))) goto error;
+    if (!(handler_sigterm = create_handler( sigterm_callback ))) goto error;
+    if (!(handler_sigint  = create_handler( sigint_callback ))) goto error;
+    if (!(handler_sigchld = create_handler( sigchld_callback ))) goto error;
+    if (!(handler_sigio   = create_handler( sigio_callback ))) goto error;
+
+    sigemptyset( &blocked_sigset );
+    sigaddset( &blocked_sigset, SIGCHLD );
+    sigaddset( &blocked_sigset, SIGHUP );
+    sigaddset( &blocked_sigset, SIGINT );
+    sigaddset( &blocked_sigset, SIGIO );
+    sigaddset( &blocked_sigset, SIGQUIT );
+    sigaddset( &blocked_sigset, SIGTERM );
+
+    action.sa_mask = blocked_sigset;
+    action.sa_flags = 0;
+    action.sa_handler = do_sigchld;
+    sigaction( SIGCHLD, &action, NULL );
+    action.sa_handler = do_sighup;
+    sigaction( SIGHUP, &action, NULL );
+    action.sa_handler = do_sigint;
+    sigaction( SIGINT, &action, NULL );
+    action.sa_handler = do_sigterm;
+    sigaction( SIGQUIT, &action, NULL );
+    sigaction( SIGTERM, &action, NULL );
+    action.sa_sigaction = do_sigio;
+    action.sa_flags = SA_SIGINFO;
+    sigaction( SIGIO, &action, NULL );
+    return;
+
+error:
+    fprintf( stderr, "failed to initialize signal handlers\n" );
+    exit(1);
+}
+
+void close_signals(void)
+{
+    sigprocmask( SIG_BLOCK, &blocked_sigset, NULL );
+    release_object( handler_sighup );
+    release_object( handler_sigterm );
+    release_object( handler_sigint );
+    release_object( handler_sigchld );
+    release_object( handler_sigio );
+}
diff --git a/server/thread.h b/server/thread.h
index 21fcdcb..f30ef4c 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -126,7 +126,7 @@
 
 /* ptrace functions */
 
-extern void sigchld_handler();
+extern void sigchld_callback(void);
 extern int get_ptrace_pid( struct thread *thread );
 extern void detach_thread( struct thread *thread, int sig );
 extern int attach_process( struct process *process );