Blame SOURCES/0022-Ticket-48882-server-can-hang-in-connection-list-proc.patch

7c7f29
From f993a9b5a1ac95728baae201543cad5993a28da1 Mon Sep 17 00:00:00 2001
7c7f29
From: Ludwig Krispenz <lkrispen@redhat.com>
7c7f29
Date: Mon, 1 Aug 2016 10:47:31 +0200
7c7f29
Subject: [PATCH 22/29] Ticket 48882 - server can hang in connection list
7c7f29
 processing
7c7f29
7c7f29
Bug Description: if a thread holding the connection monitor
7c7f29
		 is stuck in polling and the client doesn't
7c7f29
		 respond, the main thread can be blocked on
7c7f29
		 this connection when iterating the connection
7c7f29
		 table.
7c7f29
7c7f29
Fix Description: Implement a test and enter function for the connection
7c7f29
		 monitor, so the main thread will never wait for a
7c7f29
		 connection monitor already owned by an other thread
7c7f29
7c7f29
https://fedorahosted.org/389/ticket/48882
7c7f29
7c7f29
Reviewed by: Noriko, Thanks
7c7f29
7c7f29
(cherry picked from commit 7110db91e75f392f1c83643d9aa88895992d9c01)
7c7f29
---
7c7f29
 ldap/servers/slapd/daemon.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-
7c7f29
 1 file changed, 68 insertions(+), 1 deletion(-)
7c7f29
7c7f29
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
7c7f29
index 81a54cf..23c30c3 100644
7c7f29
--- a/ldap/servers/slapd/daemon.c
7c7f29
+++ b/ldap/servers/slapd/daemon.c
7c7f29
@@ -164,6 +164,67 @@ static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, PRFileDes
7c7f29
 static int write_pid_file();
7c7f29
 static int init_shutdown_detect();
7c7f29
 
7c7f29
+/*
7c7f29
+ * NSPR has different implementations for PRMonitor, depending
7c7f29
+ * on the availble threading model
7c7f29
+ * The PR_TestAndEnterMonitor is not available for pthreads
7c7f29
+ * so this is a implementation based on the code in
7c7f29
+ * prmon.c adapted to resemble the implementation in ptsynch.c
7c7f29
+ *
7c7f29
+ * The function needs access to the elements of the PRMonitor struct.
7c7f29
+ * Therfor the pthread variant of PRMonitor is copied here.
7c7f29
+ */
7c7f29
+typedef struct MY_PRMonitor {
7c7f29
+    const char* name;
7c7f29
+    pthread_mutex_t lock;
7c7f29
+    pthread_t owner;
7c7f29
+    pthread_cond_t entryCV;
7c7f29
+    pthread_cond_t waitCV;
7c7f29
+    PRInt32 refCount;
7c7f29
+    PRUint32 entryCount;
7c7f29
+    PRIntn notifyTimes;
7c7f29
+} MY_PRMonitor;
7c7f29
+
7c7f29
+static PRBool MY_TestAndEnterMonitor(MY_PRMonitor *mon)
7c7f29
+{
7c7f29
+    pthread_t self = pthread_self();
7c7f29
+    PRStatus rv;
7c7f29
+    PRBool rc = PR_FALSE;
7c7f29
+
7c7f29
+    PR_ASSERT(mon != NULL);
7c7f29
+    rv = pthread_mutex_lock(&mon->lock);
7c7f29
+    if (rv != 0) {
7c7f29
+	slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
7c7f29
+                        "Failed to acquire monitor mutex, error (%d)\n", rv);
7c7f29
+	return rc;
7c7f29
+    }
7c7f29
+    if (mon->entryCount != 0) {
7c7f29
+        if (pthread_equal(mon->owner, self))
7c7f29
+            goto done;
7c7f29
+        rv = pthread_mutex_unlock(&mon->lock);
7c7f29
+	if (rv != 0) {
7c7f29
+	    slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
7c7f29
+                        "Failed to release monitor mutex, error (%d)\n", rv);
7c7f29
+	}
7c7f29
+        return PR_FALSE;
7c7f29
+    }
7c7f29
+    /* and now I have the monitor */
7c7f29
+    PR_ASSERT(mon->notifyTimes == 0);
7c7f29
+    PR_ASSERT((mon->owner) == 0);
7c7f29
+    mon->owner = self;
7c7f29
+
7c7f29
+done:
7c7f29
+    mon->entryCount += 1;
7c7f29
+    rv = pthread_mutex_unlock(&mon->lock);
7c7f29
+    if (rv == PR_SUCCESS) {
7c7f29
+	rc = PR_TRUE;
7c7f29
+    } else {
7c7f29
+	slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
7c7f29
+                        "Failed to release monitor mutex, error (%d)\n", rv);
7c7f29
+	rc = PR_FALSE;
7c7f29
+    }
7c7f29
+    return rc;
7c7f29
+}
7c7f29
 /* Globals which are used to store the sockets between
7c7f29
  * calls to daemon_pre_setuid_init() and the daemon thread
7c7f29
  * creation. */
7c7f29
@@ -1552,7 +1613,13 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
7c7f29
 		}
7c7f29
 		else
7c7f29
 		{
7c7f29
-			PR_EnterMonitor(c->c_mutex);
7c7f29
+			/* we try to acquire the connection mutex, if it is already
7c7f29
+			 * acquired by another thread, don't wait
7c7f29
+			 */
7c7f29
+			if (PR_FALSE == MY_TestAndEnterMonitor((MY_PRMonitor *)c->c_mutex)) {
7c7f29
+				c = next;
7c7f29
+				continue;
7c7f29
+			}
7c7f29
 			if (c->c_flags & CONN_FLAG_CLOSING)
7c7f29
 			{
7c7f29
 				/* A worker thread has marked that this connection
7c7f29
-- 
7c7f29
2.4.11
7c7f29