Tuesday, August 30, 2016

[389-commits] Branch '389-ds-base-1.3.4' - ldap/servers

ldap/servers/slapd/daemon.c | 69 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 68 insertions(+), 1 deletion(-)

New commits:
commit 19c4638f689e88ebc1eaec030039d2a4521aa7c4
Author: Ludwig Krispenz <lkrispen@redhat.com>
Date: Mon Aug 1 10:47:31 2016 +0200

Ticket 48882 - server can hang in connection list processing

Bug Description: if a thread holding the connection monitor
is stuck in polling and the client doesn't
respond, the main thread can be blocked on
this connection when iterating the connection
table.

Fix Description: Implement a test and enter function for the connection
monitor, so the main thread will never wait for a
connection monitor already owned by an other thread

https://fedorahosted.org/389/ticket/48882

Reviewed by: Noriko, Thanks

(cherry picked from commit 7110db91e75f392f1c83643d9aa88895992d9c01)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 20993d4..75904fa 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -164,6 +164,67 @@ static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, PRFileDes
static int write_pid_file();
static int init_shutdown_detect();

+/*
+ * NSPR has different implementations for PRMonitor, depending
+ * on the availble threading model
+ * The PR_TestAndEnterMonitor is not available for pthreads
+ * so this is a implementation based on the code in
+ * prmon.c adapted to resemble the implementation in ptsynch.c
+ *
+ * The function needs access to the elements of the PRMonitor struct.
+ * Therfor the pthread variant of PRMonitor is copied here.
+ */
+typedef struct MY_PRMonitor {
+ const char* name;
+ pthread_mutex_t lock;
+ pthread_t owner;
+ pthread_cond_t entryCV;
+ pthread_cond_t waitCV;
+ PRInt32 refCount;
+ PRUint32 entryCount;
+ PRIntn notifyTimes;
+} MY_PRMonitor;
+
+static PRBool MY_TestAndEnterMonitor(MY_PRMonitor *mon)
+{
+ pthread_t self = pthread_self();
+ PRStatus rv;
+ PRBool rc = PR_FALSE;
+
+ PR_ASSERT(mon != NULL);
+ rv = pthread_mutex_lock(&mon->lock);
+ if (rv != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
+ "Failed to acquire monitor mutex, error (%d)\n", rv);
+ return rc;
+ }
+ if (mon->entryCount != 0) {
+ if (pthread_equal(mon->owner, self))
+ goto done;
+ rv = pthread_mutex_unlock(&mon->lock);
+ if (rv != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
+ "Failed to release monitor mutex, error (%d)\n", rv);
+ }
+ return PR_FALSE;
+ }
+ /* and now I have the monitor */
+ PR_ASSERT(mon->notifyTimes == 0);
+ PR_ASSERT((mon->owner) == 0);
+ mon->owner = self;
+
+done:
+ mon->entryCount += 1;
+ rv = pthread_mutex_unlock(&mon->lock);
+ if (rv == PR_SUCCESS) {
+ rc = PR_TRUE;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL ,"TestAndEnterMonitor",
+ "Failed to release monitor mutex, error (%d)\n", rv);
+ rc = PR_FALSE;
+ }
+ return rc;
+}
/* Globals which are used to store the sockets between
* calls to daemon_pre_setuid_init() and the daemon thread
* creation. */
@@ -1528,7 +1589,13 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
}
else
{
- PR_EnterMonitor(c->c_mutex);
+ /* we try to acquire the connection mutex, if it is already
+ * acquired by another thread, don't wait
+ */
+ if (PR_FALSE == MY_TestAndEnterMonitor((MY_PRMonitor *)c->c_mutex)) {
+ c = next;
+ continue;
+ }
if (c->c_flags & CONN_FLAG_CLOSING)
{
/* A worker thread has marked that this connection

--
389-commits mailing list
389-commits@lists.fedoraproject.org
https://lists.fedoraproject.org/admin/lists/389-commits@lists.fedoraproject.org

No comments:

Post a Comment