@@ 47,12 47,7 @@ typedef struct {
char port[8];
} prefs_t;
-/* XXX: I hate global variables */
-static session_t session;
-static tpool_t tpool;
-
-static void signal_handler(int) __attribute__((noreturn));
-static int cleanup(session_t *, tpool_t *);
+static void signal_handler(int);
static int get_listener(prefs_t *);
static void set_defaults(prefs_t *);
static void print_usage(const char *program);
@@ 61,63 56,24 @@ static int parse_prefs(int argc, char **argv, prefs_t *);
static void
signal_handler(int signum)
{
- printf("\n"
- "INFO : Received signal %i.\n"
- " : Attempting a graceful shutdown...\n", signum);
- exit(cleanup(&session, &tpool));
-}
-
-static int
-cleanup(session_t *sessionp, tpool_t *tpoolp)
-{
- int exit_code=EXIT_SUCCESS;
- char err_str[STRERROR_BUFLEN];
-
- if ( pthread_rwlock_unlock(&sessionp->lock) ) {
- get_err_str(errno, err_str);
- fprintf(stderr, " ERR : %s:%i => `pthread_rwlock_unlock()`: %s\n",
- __FILE__, __LINE__ - 3, err_str);
- exit_code = EXIT_FAILURE;
- }
-
- printf("INFO : Destroying thread pool...\n");
- if ( tpool_destroy(tpoolp, 1) == -1 ) {
- fprintf(stderr, " ERR : %s:%i => `tpool_destroy()`: Failed to destroy"
- " thread pool!\n"
- " : Watch out for those memory leaks!\n",
- __FILE__, __LINE__ - 4);
- exit_code = EXIT_FAILURE;
- }
-
- printf("INFO : Destroying session...\n");
- if ( session_destroy(sessionp) == -1 ) {
- fprintf(stderr, " ERR : %s:%i => `session_destroy()`: Failed to"
- " destroy session!\n"
- " : Watch out for those memory leaks!\n",
- __FILE__, __LINE__ - 4);
- exit_code = EXIT_FAILURE;
- }
-
- return exit_code;
+ printf("\nINFO : Received signal %i.\n", signum);
}
static int
get_listener(prefs_t *prefs)
{
- struct addrinfo hints, *res, *p;
- int status, listener=-1, yes;
- char err_str[STRERROR_BUFLEN];
-
/*
* In order to set up a socket connection, we invoke the following
* functions in this order:
- *
- * 1. getaddrinfo()
- * 2. socket()
- * 3. bind()
- *
+ * 1. getaddrinfo()
+ * 2. socket()
+ * 3. bind()
*/
+ struct addrinfo hints, *res, *p;
+ int status, listener=-1, yes;
+ char err_str[STRERROR_BUFLEN];
+
/*
* `memset()` `hints` to zeroes, and set a few necessary fields.
* This way `getaddrinfo()` will be able to set the other necessary
@@ 137,13 93,10 @@ get_listener(prefs_t *prefs)
return -1; /* We'd like to exit */
}
- /*
- * `res` should now point to a linked list of addresses. In case
- * it's not:
- */
+ /* res should now point to a linked list of addresses. In case it's not: */
if ( !res ) {
- fprintf(stderr, " ERR : %s:%i => `getaddrinfo()` returned an empty"
- " list\n", __FILE__, __LINE__ - 10);
+ fprintf(stderr, " ERR : %s:%i => `getaddrinfo()` returned an empty "
+ "list\n", __FILE__, __LINE__ - 10);
return -1;
}
@@ 160,10 113,8 @@ get_listener(prefs_t *prefs)
/* Try to get a socket file descriptor */
if ( (listener = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1 )
- /*
- * We'll continue, perhaps the next address in the list
- * will succeed.
- */
+ /* We'll continue, perhaps the next address in the list will
+ * succeed */
continue;
/*
@@ 310,10 261,12 @@ print_usage_ret_error:
int
main(int argc, char **argv)
{
- int listener, args_parsed, num_events;
+ int listener, args_parsed, num_events, exit_code;
char err_str[STRERROR_BUFLEN];
struct sigaction sa;
prefs_t prefs;
+ session_t session;
+ tpool_t tpool;
/* Set up signal handler for ^C (SIGINT) TODO: and ^\ (SIGQUIT) */
memset(&sa, 0, sizeof(struct sigaction));
@@ 358,12 311,17 @@ main(int argc, char **argv)
MAX_QUEUE_SZ, 0) ) {
fprintf(stderr, " ERR : %s:%i => `tpool_init()`: Failed to initialize"
" thread pool!\n", __FILE__, __LINE__ - 3);
- goto destroy_session_and_exit_fail;
+ exit_code = EXIT_FAILURE;
+ goto destroy_session_and_exit;
}
printf("INFO : Initialized thread pool with %zu worker threads.\n",
tpool.num_threads);
+ printf("INFO : Listening for connections on port %s\n", prefs.port);
+
+ exit_code = EXIT_SUCCESS; /* Let's hope for the best */
+
/*
* Now we gotta keep `poll()`ing and take care of everything
* everytime `poll()` returns until the server receives a SIGINT.
@@ 373,17 331,25 @@ main(int argc, char **argv)
get_err_str(errno, err_str);
fprintf(stderr, " ERR : %s:%i => `pthread_rwlock_rdlock()`: %s\n",
__FILE__, __LINE__ - 3, err_str);
- goto destroy_tpool_session_and_exit_fail;
+ exit_code = EXIT_FAILURE;
+ goto destroy_tpool_and_exit;
}
- printf("INFO : Listening for connections on port %s\n", prefs.port);
-
while ( 1 ) {
if ( (num_events = poll(session.pfds,
(nfds_t) session.fd_count, -1)) == -1 ) {
- get_err_str(errno, err_str);
- fprintf(stderr, " ERR : %s:%i => `poll()`: %s\n",
- __FILE__, __LINE__ - 11, err_str);
+ if ( errno == EINTR ) {
+ /*
+ * We got Ctrl-C'ed, we need to gracefully release any
+ * allocated memory in heap and then exit.
+ */
+ printf("DBUG : `poll()` interrupted!\n");
+ } else {
+ get_err_str(errno, err_str);
+ fprintf(stderr, " ERR : %s:%i => `poll()`: %s\n",
+ __FILE__, __LINE__ - 11, err_str);
+ exit_code = EXIT_FAILURE;
+ }
break; /* bail out */
}
@@ 396,28 362,47 @@ main(int argc, char **argv)
printf(" ERR : %s:%i => `process_events()`:"
" Failed to handle events!\n",
__FILE__, __LINE__ - 3);
+ exit_code = EXIT_FAILURE;
break; /* bail out */
}
printf("DBUG : All events handled!\n");
}
- cleanup(&session, &tpool);
- goto exit_fail;
+ if ( pthread_rwlock_unlock(&session.lock) ) {
+ get_err_str(errno, err_str);
+ fprintf(stderr, " ERR : %s:%i => `pthread_rwlock_unlock()`: %s\n",
+ __FILE__, __LINE__ - 3, err_str);
+ exit_code = EXIT_FAILURE;
+ goto destroy_tpool_and_exit;
+ }
+
+ /*
+ * ^C breaks `poll()` with EINTR which then we use to break the
+ * outer infinite `while(1)` loop and hence we can finally reach
+ * this code, do the necessary cleanup and exit gracefully.
+ */
-destroy_tpool_session_and_exit_fail:
- if ( tpool_destroy(&tpool, 1) == -1 )
+ printf("INFO : Gracefully shutting down...\n");
+
+destroy_tpool_and_exit:
+ printf("INFO : Destroying thread pool...\n");
+ if ( tpool_destroy(&tpool, 1) == -1 ) {
fprintf(stderr, " ERR : %s:%i => `tpool_destroy()`: Failed to destroy"
" thread pool!\n"
" : Watch out for those memory leaks!\n",
__FILE__, __LINE__ - 4);
+ exit_code = EXIT_FAILURE;
+ }
-destroy_session_and_exit_fail:
- if ( session_destroy(&session) == -1 )
+destroy_session_and_exit:
+ printf("INFO : Destroying session...\n");
+ if ( session_destroy(&session) == -1 ) {
fprintf(stderr, " ERR : %s:%i => `session_destroy()`: Failed to"
" destroy session!\n"
" : Watch out for those memory leaks!\n",
__FILE__, __LINE__ - 4);
+ exit_code = EXIT_FAILURE;
+ }
-exit_fail:
- return EXIT_FAILURE;
+ return exit_code;
}