src/server/daemon/httplistener.c

changeset 449
a28a5ccc894b
parent 446
240ed6f945ca
child 453
4586d534f9b5
--- a/src/server/daemon/httplistener.c	Sat Dec 03 16:31:08 2022 +0100
+++ b/src/server/daemon/httplistener.c	Sat Dec 03 18:00:35 2022 +0100
@@ -420,6 +420,15 @@
     return listener;
 }
 
+void http_listener_destroy(HttpListener *listener) {
+    log_ereport(LOG_DEBUG, "destroy http listener: %s config: %p", listener->name.ptr, listener->cfg);
+    
+    if(listener->shutdown) {
+        pthread_mutex_destroy(&listener->shutdown_mutex);
+        pthread_cond_destroy(&listener->shutdown_cond);
+    }
+}
+
 int http_listener_start(HttpListener *listener) {
     if(listener->running) {
         return 0;
@@ -500,8 +509,24 @@
 
 
 void http_listener_shutdown_acceptors(HttpListener *listener) {
-    // 
+    if(pthread_mutex_init(&listener->shutdown_mutex, NULL)) {
+        log_ereport(LOG_FAILURE, "http_listener_shutdown_acceptors: pthread_mutex_init failed: %s", strerror(errno));
+        return;
+    }
+    if(pthread_cond_init(&listener->shutdown_cond, NULL)) {
+        log_ereport(LOG_FAILURE, "http_listener_shutdown_acceptors: pthread_cond_init failed: %s", strerror(errno));
+        return;
+    }
+    listener->shutdown = TRUE;
     
+    log_ereport(LOG_INFORM, "shutdown http listener %s", listener->name.ptr);
+    
+    pthread_mutex_lock(&listener->shutdown_mutex);
+    
+    // shut down acceptors by connecting to the server socket, to make sure
+    // accept() returns
+    // the acceptor will handle this as a normal connection, but this should
+    // not be a problem
     for(int i=0;i<listener->nacceptors;i++) {
         listener->acceptors[i]->exit = TRUE;
         int client4 = http_listener_connect(listener, FALSE);
@@ -519,6 +544,16 @@
             close(client6);
         }
     }
+    
+    // The last acceptor will notify listener_shutdown.cond
+    // It is not really necessary to wait for acceptors to shut down,
+    // we do it mostly for nicer log messages. The timeout is there
+    // for making sure, this function never blocks forever.
+    struct timespec ts;
+    ts.tv_sec = time(NULL) + 60;
+    pthread_cond_timedwait(&listener->shutdown_cond, &listener->shutdown_mutex, &ts);
+    
+    pthread_mutex_unlock(&listener->shutdown_mutex);
 }
 
 
@@ -540,6 +575,8 @@
     {
         log_ereport(LOG_FAILURE, "Listener %s: acceptor_start: %s acceptor", a->listener->name.ptr, strerror(errno));
         cfg_unref(a->listener->cfg);
+    } else {
+        (void)pthread_detach(a->tid);
     }
 }
 
@@ -554,6 +591,7 @@
     HttpListener *listener = acceptor->listener;
     
     int server_socket;
+    uint32_t *acceptors_running = &listener->nacceptors_running;
     
     ConnectionAddr ca;
     struct sockaddr *ca_ptr;
@@ -572,6 +610,7 @@
     }
     
     log_ereport(LOG_DEBUG, "acceptor: %p listener: %p start", acceptor, acceptor->listener);
+    ws_atomic_inc32(acceptors_running);
     
     for (;;) {
         // accept connections
@@ -662,6 +701,16 @@
         }
     }
     
+    if(ws_atomic_dec32(acceptors_running) == 0) {
+        // notify
+        if(listener->shutdown) {
+            log_ereport(LOG_DEBUG, "last acceptor shutdown: notify cfgmgr");
+            pthread_mutex_lock(&listener->shutdown_mutex);
+            pthread_cond_signal(&listener->shutdown_cond);
+            pthread_mutex_unlock(&listener->shutdown_mutex);
+        }
+    }
+    
     acceptor->running = FALSE;
     
     cfg_unref(acceptor->listener->cfg);

mercurial