diff options
author | LAN-TW <lantw44@gmail.com> | 2014-01-14 04:46:07 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2014-01-14 04:48:21 +0800 |
commit | 549548a09953851531f5104c5f1334b0f036764d (patch) | |
tree | fa6267ff580bf716eeac52901ae1410a5482355b /hw4 | |
parent | 5873050be326f8b645b994d8c5e8b266573a6e40 (diff) | |
download | sp2013-549548a09953851531f5104c5f1334b0f036764d.tar sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.gz sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.bz2 sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.lz sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.xz sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.zst sp2013-549548a09953851531f5104c5f1334b0f036764d.zip |
HW4: 接收通知、結束程式、處理 main thread 的 signal
Diffstat (limited to 'hw4')
-rw-r--r-- | hw4/chttpd/chttpd-server.c | 168 | ||||
-rw-r--r-- | hw4/chttpd/chttpd-server.h | 10 |
2 files changed, 173 insertions, 5 deletions
diff --git a/hw4/chttpd/chttpd-server.c b/hw4/chttpd/chttpd-server.c index d5c0337..611a7a6 100644 --- a/hw4/chttpd/chttpd-server.c +++ b/hw4/chttpd/chttpd-server.c @@ -11,13 +11,17 @@ #include <l4str.h> #include <l4posix.h> +#include <arpa/inet.h> #include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <locale.h> #include <netdb.h> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -209,14 +213,148 @@ static LbsListMeta* chttpd_main_init (ChttpdLog* hlog, const char* service) { return slist; } -int chttpd_server_notify; -pthread_mutex_t chttpd_server_notify_mutex; +int chttpd_server_notify; +pthread_mutex_t chttpd_server_notify_mutex; +ChttpdServer chttpd_server_notify_data; + +unsigned long long chttpd_server_count; +pthread_rwlock_t chttpd_server_count_lock; + +static volatile sig_atomic_t server_shutdown; +static void server_shutdown_setter (int signo) { + server_shutdown = 1; +} + +static volatile sig_atomic_t server_notify; +static void server_notify_setter (int signo) { + server_notify = 1; +} + +static void dummy_handler (int signo) { } static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) { chttpd_server_notify = 1; + chttpd_server_notify_data.attr_close = true; pthread_mutex_init (&chttpd_server_notify_mutex, NULL); + chttpd_server_count = 0; + pthread_rwlock_init (&chttpd_server_count_lock, NULL); + + sigset_t crit_mask; + sigemptyset (&crit_mask); + sigaddset (&crit_mask, SIGINT); + sigaddset (&crit_mask, SIGTERM); + sigaddset (&crit_mask, SIGHUP); + sigaddset (&crit_mask, SIGUSR2); + + while (lbs_list_meta_get_len (slist) > 0) { + pthread_sigmask (SIG_BLOCK, &crit_mask, NULL); + + /* Check whether we are going to shutdown the server */ + if (server_shutdown) { + pthread_mutex_lock (&chttpd_server_notify_mutex); + chttpd_server_notify = 1; + pthread_mutex_unlock (&chttpd_server_notify_mutex); + for (LbsList* iter = slist->first; iter != NULL; iter = iter->next) { + ChttpdServer* server = iter->data; + pthread_rwlock_wrlock (&server->lock); + server->attr_close = true; + pthread_rwlock_unlock (&server->lock); + } + } + /* Check whether there are notifications */ + pthread_mutex_lock (&chttpd_server_notify_mutex); + if (chttpd_server_notify || server_notify) { + chttpd_server_notify = 0; + server_notify = 0; + if (chttpd_server_notify_data.attr_close == false) { + /* TODO: Add a server */ + ChttpdServer* new_server = xmalloc (sizeof (ChttpdServer)); + *new_server = chttpd_server_notify_data; + lbs_list_push_back (slist, new_server, NULL); + } + pthread_mutex_unlock (&chttpd_server_notify_mutex); + + /* Remove unused servers */ + LbsList* iter = slist->first; + LbsList* next = iter; + for (; iter != NULL; iter = next) { + ChttpdServer* server = iter->data; + next = iter->next; + if (pthread_rwlock_trywrlock (&server->lock) == 0) { + if (server->attr_close && server->conn->len <= 0) { + pthread_rwlock_unlock (&server->lock); + lbs_list_remove (slist, iter); + } else { + pthread_rwlock_unlock (&server->lock); + } + } + } + + /* Rebuild poll list */ + + /* Log current server info */ + chttpd_log_write_str (hlog, "[Server status change notification]"); + + unsigned long long count; + pthread_rwlock_rdlock (&chttpd_server_count_lock); + count = chttpd_server_count; + pthread_rwlock_unlock (&chttpd_server_count_lock); + + chttpd_log_write (hlog, "%lld connections has been accepted", count); + + unsigned c = 0; + for (iter = slist->first; iter != NULL; iter = iter->next, c++) { + ChttpdServer* server = iter->data; + struct sockaddr_storage addr; + char* type; + + pthread_rwlock_rdlock (&server->lock); + addr = server->addr; + type = server->attr_admin ? "ADMIN" : "HTTP"; + pthread_rwlock_unlock (&server->lock); + + char ipstr[INET6_ADDRSTRLEN]; + switch (addr.ss_family) { + case AF_UNIX: + CHTTPD_SOCKET_SOCKADDR_UN_SET_NULL (SOCKADDR_UN (&addr)); + chttpd_log_write (hlog, + "Server %u: type %s, UNIX socket, path %s", + c, type, SOCKADDR_UN (&addr)->sun_path); + break; + case AF_INET: + if (!inet_ntop (AF_INET, &(SOCKADDR_IN (&addr)->sin_addr), + ipstr, INET_ADDRSTRLEN)) { + strcpy (ipstr, "unknown"); + } + chttpd_log_write (hlog, "Server %u: type %s, " + "IPv4 socket, address %s, port %" PRIu16, c, type, + ipstr, ntohs (SOCKADDR_IN (&addr)->sin_port)); + break; + case AF_INET6: + if (!inet_ntop (AF_INET6, &(SOCKADDR_IN6 (&addr)->sin6_addr), + ipstr, INET6_ADDRSTRLEN)) { + strcpy (ipstr, "unknown"); + } + chttpd_log_write (hlog, "Server %u: type %s, " + "IPv6 socket, address %s, port %" PRIu16, c, type, + ipstr, ntohs (SOCKADDR_IN6 (&addr)->sin6_port)); + break; + default: + chttpd_log_write (hlog, + "Server %u: type %s, unknown socket", c, type); + break; + } + } + + } else { + pthread_mutex_unlock (&chttpd_server_notify_mutex); + } + + pthread_sigmask (SIG_UNBLOCK, &crit_mask, NULL); + /* */ + } } void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin) { @@ -237,6 +375,7 @@ void chttpd_server_dtor (void* server_generic) { close (server->sockfd); pthread_rwlock_destroy (&server->lock); lbs_list_meta_free (server->conn); + chttpd_log_unref (server->hlog); free (server); } @@ -256,6 +395,31 @@ int main (int argc, char* argv[]) { return 2; } + struct sigaction sa_pipe, sa_term, sa_usr1, sa_usr2; + sa_pipe.sa_handler = SIG_IGN; + sa_pipe.sa_flags = 0; + sigemptyset (&sa_pipe.sa_mask); + sigaction (SIGPIPE, &sa_pipe, NULL); /* Use errno, no SIGPIPE */ + sa_term.sa_handler = server_shutdown_setter; + sa_term.sa_flags = 0; + sigemptyset (&sa_term.sa_mask); + sigaction (SIGINT, &sa_term, NULL); /* Handled by main thread in loop */ + sigaction (SIGTERM, &sa_term, NULL); /* Handled by main thread in loop */ + sa_usr1.sa_handler = dummy_handler; + sa_usr1.sa_flags = 0; + sigemptyset (&sa_usr1.sa_mask); + sigaction (SIGUSR1, &sa_usr1, NULL); /* Handled by connection thread */ + sa_usr2.sa_handler = server_notify_setter; + sa_usr2.sa_flags = 0; + sigemptyset (&sa_usr2.sa_mask); + sigaction (SIGHUP, &sa_usr2, NULL); /* Handled by main thread to interrupt */ + sigaction (SIGUSR2, &sa_usr2, NULL); /* Handled by main thread to interrupt */ + + sigset_t main_mask; + sigemptyset (&main_mask); + sigaddset (&main_mask, SIGUSR1); + pthread_sigmask (SIG_BLOCK, &main_mask, NULL); + LbsListMeta* slist = chttpd_main_init (hlog, argv[1]); if (lbs_list_meta_get_len (slist) > 0) { chttpd_main_loop (hlog, slist); diff --git a/hw4/chttpd/chttpd-server.h b/hw4/chttpd/chttpd-server.h index 1fd6f7c..e85716b 100644 --- a/hw4/chttpd/chttpd-server.h +++ b/hw4/chttpd/chttpd-server.h @@ -12,16 +12,20 @@ typedef struct { struct sockaddr_storage addr; socklen_t addrlen; int attr_admin : 1; + ChttpdLog* hlog; /* read-write and lock */ pthread_rwlock_t lock; - ChttpdLog* hlog; LbsListMeta* conn; int attr_close : 1; } ChttpdServer; -extern int chttpd_server_notify; -extern pthread_mutex_t chttpd_server_notify_mutex; +extern int chttpd_server_notify; +extern pthread_mutex_t chttpd_server_notify_mutex; +extern ChttpdServer chttpd_server_notify_data; + +extern unsigned long long chttpd_server_count; +extern pthread_rwlock_t chttpd_server_count_lock; void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin); void chttpd_server_dtor (void* server_generic); |