diff options
-rw-r--r-- | main.c | 74 | ||||
-rw-r--r-- | plugin.h | 1 | ||||
-rw-r--r-- | util.h | 3 |
3 files changed, 30 insertions, 48 deletions
@@ -1,10 +1,8 @@ -#define _GNU_SOURCE // sigaction #include <stdio.h> #include <stdbool.h> #include <string.h> -#include <signal.h> +#include <pthread.h> #include <sys/socket.h> -#include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> @@ -19,25 +17,8 @@ #define PORT 8080 -int num_threads=0; - - -static void signal_handler(int sig){ - if(sig==SIGCHLD){ - int saved_errno=errno; - while(true){ - int status; - pid_t pid=waitpid(-1,&status,WNOHANG); - if(pid<=0){ - break; - } - if(WIFEXITED(status)){ - num_threads--; - } - } - errno=saved_errno; - } -} +static int num_threads=0; +static pthread_mutex_t num_threads_mutex; typedef struct Plugin{ @@ -46,7 +27,8 @@ typedef struct Plugin{ struct Plugin *next; } Plugin; -Plugin *pluginlist=NULL,*pluginlist_last=NULL; +// Will only be read once threading starts, so no mutex needed +static Plugin *pluginlist=NULL,*pluginlist_last=NULL; static void plugin_register_callback(const char *name,Handler handler){ if(pluginlist==NULL){ @@ -82,10 +64,12 @@ static void load_plugin(const char *name){ } -static void connection_handler(int sock){ +static void* thread_entry_connection_handler(void *sock_){ + int sock=(int)sock_; + Headers *headers=http_get_headers(sock); if(headers==NULL){ - return; + goto cleanup_exit; } for(Plugin *pl=pluginlist;pl!=NULL;pl=pl->next){ @@ -103,6 +87,13 @@ static void connection_handler(int sock){ } break; } + +cleanup_exit: + close(sock); + PTHREAD_CHECK(pthread_mutex_lock,&num_threads_mutex); + num_threads--; + PTHREAD_CHECK(pthread_mutex_unlock,&num_threads_mutex); + return NULL; } @@ -143,17 +134,10 @@ int main(int argc,char **argv){ return 1; } - struct sigaction sa; - sa.sa_handler=signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags=SA_RESTART; - if(sigaction(SIGCHLD,&sa,NULL)<0){ - perror("sigaction"); - return 1; - } - printf("Listening on port %d\n",PORT); + PTHREAD_CHECK(pthread_mutex_init,&num_threads_mutex,NULL); + while(true){ struct sockaddr_storage client_addr; socklen_t client_addr_sz=sizeof(client_addr); @@ -167,20 +151,14 @@ int main(int argc,char **argv){ inet_ntop(client_addr.ss_family,&((struct sockaddr_in*)&client_addr)->sin_addr, str,sizeof(str)); - pid_t pid=fork(); - if(pid==0){ - close(sock); - connection_handler(clientsock); - close(clientsock); - exit(0); - } - if(pid<0){ - perror("fork"); - return 1; - } + printf("Accept from %s; %d thread%s still left\n",str,num_threads,num_threads==1?"":"s"); + + PTHREAD_CHECK(pthread_mutex_lock,&num_threads_mutex); num_threads++; - printf("Accept from %s; child pid %d, %d thread%s\n",str,pid,num_threads, - num_threads==1?"":"s"); - close(clientsock); + PTHREAD_CHECK(pthread_mutex_unlock,&num_threads_mutex); + + pthread_t th; + PTHREAD_CHECK(pthread_create,&th,NULL,thread_entry_connection_handler,(void*)(uintptr_t)clientsock); + PTHREAD_CHECK(pthread_detach,th); } } @@ -15,4 +15,5 @@ typedef void (*register_callback_t)(const char *name,Handler handler); // Override this in the plugin; it will be called from the main application. // It should call the callback with the plugin's handler. +// Note that the plugin's handler will be called from multiple threads, so ensure that it is thread-safe. void plugin_register_yourself(register_callback_t callback); @@ -3,6 +3,9 @@ #include <sys/socket.h> +#define PTHREAD_CHECK(func_,...) do { int ret=(func_)(__VA_ARGS__); if(ret!=0){ fprintf(stderr,#func_ ": %s\n",strerror(ret)); exit(1); } } while(0) + + char* copy_buf(const char *buf,int len); char* copy_str(const char *str); |