Added timer on server exit to wait a bit for new clients.
Don't remove the socket until the registry is closed to avoid a race.
diff --git a/server/main.c b/server/main.c
index c6ecfd3..852c93c 100644
--- a/server/main.c
+++ b/server/main.c
@@ -33,7 +33,7 @@
/* command-line options */
int debug_level = 0;
-int persistent_server = 0;
+int master_socket_timeout = 3; /* master socket timeout in seconds, default is 3 s */
/* parse-line args */
/* FIXME: should probably use getopt, and add a (more complete?) help option */
@@ -43,7 +43,7 @@
fprintf(stderr, "\nusage: %s [options]\n\n", exeName);
fprintf(stderr, "options:\n");
fprintf(stderr, " -d<n> set debug level to <n>\n");
- fprintf(stderr, " -p make server persistent\n");
+ fprintf(stderr, " -p[n] make server persistent, optionally for n seconds\n");
fprintf(stderr, " -h display this help message\n");
fprintf(stderr, "\n");
}
@@ -66,7 +66,8 @@
exit(0);
break;
case 'p':
- persistent_server = 1;
+ if (isdigit(argv[i][2])) master_socket_timeout = atoi( argv[i] + 2 );
+ else master_socket_timeout = -1;
break;
default:
fprintf( stderr, "Unknown option '%s'\n", argv[i] );
diff --git a/server/object.h b/server/object.h
index 378a1ae..6ccbeaf 100644
--- a/server/object.h
+++ b/server/object.h
@@ -198,7 +198,7 @@
/* command-line options */
extern int debug_level;
-extern int persistent_server;
+extern int master_socket_timeout;
/* server start time used for GetTickCount() */
extern unsigned int server_start_ticks;
diff --git a/server/process.c b/server/process.c
index 8de97b0..2162be2 100644
--- a/server/process.c
+++ b/server/process.c
@@ -497,7 +497,7 @@
/* last process died, close global handles */
close_global_handles();
/* this will cause the select loop to terminate */
- if (!persistent_server) close_master_socket();
+ close_master_socket();
}
}
diff --git a/server/request.c b/server/request.c
index 623520d..7ed598f 100644
--- a/server/request.c
+++ b/server/request.c
@@ -60,12 +60,12 @@
struct master_socket
{
- struct object obj; /* object header */
+ struct object obj; /* object header */
+ struct timeout_user *timeout; /* timeout on last process exit */
};
static void master_socket_dump( struct object *obj, int verbose );
static void master_socket_poll_event( struct object *obj, int event );
-static void master_socket_destroy( struct object *obj );
static const struct object_ops master_socket_ops =
{
@@ -81,7 +81,7 @@
no_flush, /* flush */
no_get_file_info, /* get_file_info */
NULL, /* queue_async */
- master_socket_destroy /* destroy */
+ no_destroy /* destroy */
};
@@ -447,6 +447,11 @@
int len = sizeof(dummy);
int client = accept( master_socket->obj.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 );
}
@@ -459,11 +464,6 @@
if (!do_it_once++) unlink( SOCKETNAME );
}
-static void master_socket_destroy( struct object *obj )
-{
- socket_cleanup();
-}
-
/* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
const char *get_config_dir(void)
{
@@ -557,6 +557,7 @@
if (!(master_socket = alloc_object( &master_socket_ops, fd )))
fatal_error( "out of memory\n" );
+ master_socket->timeout = NULL;
set_select_events( &master_socket->obj, POLLIN );
/* setup msghdr structure constant fields */
@@ -581,14 +582,30 @@
}
}
-/* close the master socket and stop waiting for new clients */
-void close_master_socket(void)
+/* master socket timer expiration handler */
+static void close_socket_timeout( void *arg )
{
/* if a new client is waiting, we keep on running */
if (!check_select_events( master_socket->obj.fd, POLLIN ))
release_object( master_socket );
}
+/* close the master socket and stop waiting for new clients */
+void close_master_socket(void)
+{
+ struct timeval when;
+
+ if (master_socket_timeout == -1) return; /* just keep running forever */
+
+ if (master_socket_timeout)
+ {
+ gettimeofday( &when, 0 );
+ add_timeout( &when, master_socket_timeout * 1000 );
+ master_socket->timeout = add_timeout_user( &when, close_socket_timeout, NULL );
+ }
+ else close_socket_timeout( NULL ); /* close it right away */
+}
+
/* lock/unlock the master socket to stop accepting new clients */
void lock_master_socket( int locked )
{
diff --git a/server/select.c b/server/select.c
index 065c456..24cbdb6 100644
--- a/server/select.c
+++ b/server/select.c
@@ -274,6 +274,7 @@
break;
}
}
+ if (!active_users) break; /* last user removed by a timeout */
}
sigprocmask( SIG_UNBLOCK, &sigset, NULL );