|
|
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 |
|