Blame SOURCES/memcached-restart-shutdown-segfault.patch

6dacf3
commit e360e34b1fd2cd69c3a08bfb7fa4fe75281b942a
6dacf3
Author: Tomas Korbar <tkorbar@redhat.com>
6dacf3
Date:   Tue May 19 08:42:12 2020 +0200
6dacf3
6dacf3
    restart: fix rare segfault on shutdown
6dacf3
6dacf3
diff --git a/memcached.c b/memcached.c
6dacf3
index d769b4a..ac03b93 100644
6dacf3
--- a/memcached.c
6dacf3
+++ b/memcached.c
6dacf3
@@ -1009,6 +1009,18 @@ static void conn_shrink(conn *c) {
6dacf3
     }
6dacf3
 }
6dacf3
 
6dacf3
+// Since some connections might be off on side threads and some are managed as
6dacf3
+// listeners we need to walk through them all from a central point.
6dacf3
+// Must be called with all worker threads hung or in the process of closing.
6dacf3
+void conn_close_all(void) {
6dacf3
+    int i;
6dacf3
+    for (i = 0; i < max_fds; i++) {
6dacf3
+        if (conns[i] && conns[i]->state != conn_closed) {
6dacf3
+            conn_close(conns[i]);
6dacf3
+        }
6dacf3
+    }
6dacf3
+}
6dacf3
+
6dacf3
 /**
6dacf3
  * Convert a state name to a human readable form.
6dacf3
  */
6dacf3
@@ -9860,13 +9872,6 @@ int main (int argc, char **argv) {
6dacf3
     }
6dacf3
 
6dacf3
     stop_threads();
6dacf3
-    int i;
6dacf3
-    // FIXME: make a function callable from threads.c
6dacf3
-    for (i = 0; i < max_fds; i++) {
6dacf3
-        if (conns[i] && conns[i]->state != conn_closed) {
6dacf3
-            conn_close(conns[i]);
6dacf3
-        }
6dacf3
-    }
6dacf3
     if (memory_file != NULL && stop_main_loop == GRACE_STOP) {
6dacf3
         restart_mmap_close();
6dacf3
     }
6dacf3
diff --git a/memcached.h b/memcached.h
6dacf3
index 6b1fe4a..bc2b395 100644
6dacf3
--- a/memcached.h
6dacf3
+++ b/memcached.h
6dacf3
@@ -814,9 +814,8 @@ enum delta_result_type add_delta(conn *c, const char *key,
6dacf3
                                  const int64_t delta, char *buf,
6dacf3
                                  uint64_t *cas);
6dacf3
 void accept_new_conns(const bool do_accept);
6dacf3
-conn *conn_from_freelist(void);
6dacf3
-bool  conn_add_to_freelist(conn *c);
6dacf3
 void  conn_close_idle(conn *c);
6dacf3
+void  conn_close_all(void);
6dacf3
 item *item_alloc(char *key, size_t nkey, int flags, rel_time_t exptime, int nbytes);
6dacf3
 #define DO_UPDATE true
6dacf3
 #define DONT_UPDATE false
6dacf3
diff --git a/thread.c b/thread.c
6dacf3
index 7cba01e..6e19a2e 100644
6dacf3
--- a/thread.c
6dacf3
+++ b/thread.c
6dacf3
@@ -205,6 +205,7 @@ void stop_threads(void) {
6dacf3
     if (settings.verbose > 0)
6dacf3
         fprintf(stderr, "asking workers to stop\n");
6dacf3
     buf[0] = 's';
6dacf3
+    pthread_mutex_lock(&worker_hang_lock);
6dacf3
     pthread_mutex_lock(&init_lock);
6dacf3
     init_count = 0;
6dacf3
     for (i = 0; i < settings.num_threads; i++) {
6dacf3
@@ -216,6 +217,8 @@ void stop_threads(void) {
6dacf3
     wait_for_thread_registration(settings.num_threads);
6dacf3
     pthread_mutex_unlock(&init_lock);
6dacf3
 
6dacf3
+    // All of the workers are hung but haven't done cleanup yet.
6dacf3
+
6dacf3
     if (settings.verbose > 0)
6dacf3
         fprintf(stderr, "asking background threads to stop\n");
6dacf3
 
6dacf3
@@ -237,6 +240,17 @@ void stop_threads(void) {
6dacf3
     if (settings.verbose > 0)
6dacf3
         fprintf(stderr, "stopped idle timeout thread\n");
6dacf3
 
6dacf3
+    // Close all connections then let the workers finally exit.
6dacf3
+    if (settings.verbose > 0)
6dacf3
+        fprintf(stderr, "closing connections\n");
6dacf3
+    conn_close_all();
6dacf3
+    pthread_mutex_unlock(&worker_hang_lock);
6dacf3
+    if (settings.verbose > 0)
6dacf3
+        fprintf(stderr, "reaping worker threads\n");
6dacf3
+    for (i = 0; i < settings.num_threads; i++) {
6dacf3
+        pthread_join(threads[i].thread_id, NULL);
6dacf3
+    }
6dacf3
+
6dacf3
     if (settings.verbose > 0)
6dacf3
         fprintf(stderr, "all background threads stopped\n");
6dacf3