summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2019-11-23 23:36:14 +0100
committertomsmeding <tom.smeding@gmail.com>2019-11-23 23:36:43 +0100
commit4381cca95136b0a8222378a41ac0ebb1bc62ea80 (patch)
treecb68b2c041c19c0f9d3deaeda64a6fafd71f5f18
parente2492535cf8ecff85595712e69774d94dd98a751 (diff)
Use threads, not processes, to handle requests
-rw-r--r--main.c74
-rw-r--r--plugin.h1
-rw-r--r--util.h3
3 files changed, 30 insertions, 48 deletions
diff --git a/main.c b/main.c
index 0b4886b..debaa3e 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
}
diff --git a/plugin.h b/plugin.h
index d3e8b36..756c45a 100644
--- a/plugin.h
+++ b/plugin.h
@@ -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);
diff --git a/util.h b/util.h
index 5457ffe..05cef22 100644
--- a/util.h
+++ b/util.h
@@ -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);