[389-commits] 14 commits - config.h.in configure configure.ac ldap/include ldap/servers m4/nunc-stans.m4 Makefile.am Makefile.in

Richard Allen Megginson rmeggins at fedoraproject.org
Fri May 1 15:09:59 UTC 2015


 Makefile.am                       |   10 
 Makefile.in                       |   29 +
 config.h.in                       |    3 
 configure                         |  154 ++++++++++
 configure.ac                      |   16 +
 ldap/include/ldaplog.h            |   43 +-
 ldap/servers/slapd/connection.c   |  113 ++++++-
 ldap/servers/slapd/conntable.c    |   20 +
 ldap/servers/slapd/daemon.c       |  582 ++++++++++++++++++++++++++++++++------
 ldap/servers/slapd/fe.h           |    3 
 ldap/servers/slapd/libglobs.c     |   41 ++
 ldap/servers/slapd/log.c          |    5 
 ldap/servers/slapd/proto-slap.h   |   11 
 ldap/servers/slapd/slap.h         |   17 -
 ldap/servers/slapd/slapi-plugin.h |    3 
 m4/nunc-stans.m4                  |   78 +++++
 16 files changed, 991 insertions(+), 137 deletions(-)

New commits:
commit a7caededb70b86f9bcd8503ea2099215504423a7
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Thu Apr 30 16:01:59 2015 -0600

    Ticket #48178 add config param to enable nunc-stans
    
    https://fedorahosted.org/389/ticket/48178
    Reviewed by: ???
    Branch: master
    Fix Description: If nsslapd-enable-nunc-stans: on, the server will use
    nunc-stans as the event framework.  NOTE: You still have to build the
    server with configure --enable-nunc-stans in order to be able to set
    nsslapd-enable-nunc-stans: on.  By default, the value is off.
    Platforms tested: Fedora 20
    Flag Day: no
    Doc impact: no

diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index 58668f0..6d719fd 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -282,6 +282,7 @@ connection_cleanup(Connection *conn)
 		ns_enable_listeners();
 	}
 #ifdef ENABLE_NUNC_STANS
+	/* even if !config_get_enable_nunc_stans, it is ok to set to 0 here */
 	conn->c_ns_close_jobs = 0;
 #endif
 }
@@ -2357,9 +2358,8 @@ connection_threadmain()
 	int replication_connection = 0; /* If this connection is from a replication supplier, we want to ensure that operation processing is serialized */
 	int doshutdown = 0;
 	int maxthreads = 0;
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
+	int enable_nunc_stans = config_get_enable_nunc_stans();
 	long bypasspollcnt = 0;
-#endif
 
 #if defined( OSF1 ) || defined( hpux )
 	/* Arrange to ignore SIGPIPE signals. */
@@ -2552,8 +2552,7 @@ connection_threadmain()
  * when using nunc-stans - it is supposed to be an optimization but turns out
  * to not be the opposite with nunc-stans
  */
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
-			} else { /* more data in conn - just put back on work_q - bypass poll */
+			} else if (!enable_nunc_stans) { /* more data in conn - just put back on work_q - bypass poll */
 				bypasspollcnt++;
 				PR_Lock(conn->c_mutex);
 				/* don't do this if it would put us over the max threads per conn */
@@ -2571,7 +2570,6 @@ connection_threadmain()
 					conn->c_maxthreadsblocked++;
 				}
 				PR_Unlock(conn->c_mutex);
-#endif
 			}
 		}
 
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index dc2e265..e7ce5e5 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -212,6 +212,7 @@ connection_table_get_connection(Connection_Table *ct, int sd)
 		 */
 		connection_cleanup(c);
 #ifdef ENABLE_NUNC_STANS
+		/* NOTE - ok to do this here even if enable_nunc_stans is off */
 		c->c_ct = ct; /* pointer to connection table that owns this connection */
 #endif
     }
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 29f0580..af378f5 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -119,12 +119,10 @@ short	slapd_housekeeping_timer = 10;
 /* Do we support timeout on socket send() ? */
 int have_send_timeouts = 0;
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 PRFileDesc*		signalpipe[2];
 static int writesignalpipe = SLAPD_INVALID_SOCKET;
 static int readsignalpipe = SLAPD_INVALID_SOCKET;
 #define FDS_SIGNAL_PIPE 0
-#endif
 
 static PRThread *disk_thread_p = NULL;
 static PRCondVar *diskmon_cvar = NULL;
@@ -148,6 +146,8 @@ typedef struct listener_info {
 static int listeners = 0; /* number of listener sockets */
 static listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
 
+static int enable_nunc_stans = 0; /* if nunc-stans is set to enabled, set to 1 in slapd_daemon */
+
 #define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
 
 static int get_configured_connection_table_size();
@@ -177,9 +177,7 @@ static void* catch_signals();
 HANDLE  hServDoneEvent = NULL;
 #endif
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static int createsignalpipe( void );
-#endif
 
 #if defined( _WIN32 )
 /* Set an event to hook the NT Service termination */
@@ -395,14 +393,13 @@ static void set_timeval_ms(struct timeval *t, int ms);
 static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn );
 #ifdef ENABLE_NUNC_STANS
 static void ns_handle_new_connection(struct ns_job_t *job);
-#else
+#endif
 static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
 #ifdef _WIN32
 static int clear_signal(fd_set *readfdset);
 #else
 static int clear_signal(struct POLL_STRUCT *fds);
 #endif
-#endif
 #ifdef _WIN32
 static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
 #else
@@ -934,7 +931,6 @@ disk_monitoring_thread(void *nothing)
     }
 }
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static void
 handle_listeners(Connection_Table *ct)
 {
@@ -958,7 +954,6 @@ handle_listeners(Connection_Table *ct)
 	}
 	return;
 }
-#endif /* !ENABLE_NUNC_STANS */
 
 /*
  * Convert any pre-existing DES passwords to AES.
@@ -1224,6 +1219,9 @@ void
 ns_enable_listeners()
 {
 #ifdef ENABLE_NUNC_STANS
+	if (!enable_nunc_stans) {
+		return;
+	}
 	int num_enabled = 0;
 	listener_info *listener;
 	while ((listener = (listener_info *)PR_StackPop(ns_disabled_listeners))) {
@@ -1282,7 +1280,7 @@ nunc_stans_free(void *ptr)
 {
 	slapi_ch_free((void **)&ptr);
 }
-#endif
+#endif /* ENABLE_NUNC_STANS */
 
 void slapd_daemon( daemon_ports_t *ports )
 {
@@ -1306,9 +1304,7 @@ void slapd_daemon( daemon_ports_t *ports )
 	PRFileDesc **fdesp = NULL; 
 #endif
 	PRIntn num_poll = 0;
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 	PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_wakeup_timer);
-#endif
 	PRThread *time_thread_p;
 	int threads;
 	int in_referral_mode = config_check_referral_mode();
@@ -1319,6 +1315,10 @@ void slapd_daemon( daemon_ports_t *ports )
 	int connection_table_size = get_configured_connection_table_size();
 	the_connection_table= connection_table_new(connection_table_size);
 
+#ifdef ENABLE_NUNC_STANS
+	enable_nunc_stans = config_get_enable_nunc_stans();
+#endif
+
 #ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
 	/*
 	 * Some DNS resolver implementations, such as the one built into
@@ -1342,10 +1342,10 @@ void slapd_daemon( daemon_ports_t *ports )
 	i_unix = ports->i_socket;
 #endif /* ENABLE_LDAPI */
 #endif
-	
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
-	createsignalpipe();
-#endif
+
+	if (!enable_nunc_stans) {
+		createsignalpipe();
+	}
 
 	init_shutdown_detect();
 
@@ -1494,7 +1494,9 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif
 	listener_idxs = (listener_info *)slapi_ch_calloc(listeners, sizeof(*listener_idxs));
 #ifdef ENABLE_NUNC_STANS
-	ns_disabled_listeners = PR_CreateStack("disabled_listeners");
+	if (enable_nunc_stans) {
+		ns_disabled_listeners = PR_CreateStack("disabled_listeners");
+	}
 #endif
 	/*
 	 * Convert old DES encoded passwords to AES
@@ -1502,7 +1504,7 @@ void slapd_daemon( daemon_ports_t *ports )
 	convert_pbe_des_to_aes();
 
 #ifdef ENABLE_NUNC_STANS
-	if (!g_get_shutdown()) {
+	if (enable_nunc_stans && !g_get_shutdown()) {
 		int ii;
 		PRInt32 maxthreads = 3;
 		if (getenv("MAX_THREADS")) {
@@ -1536,7 +1538,7 @@ void slapd_daemon( daemon_ports_t *ports )
 
 		}
 	}
-#endif
+#endif /* ENABLE_NUNC_STANS */
 	/* Now we write the pid file, indicating that the server is finally and listening for connections */
 	write_pid_file();
 
@@ -1544,14 +1546,14 @@ void slapd_daemon( daemon_ports_t *ports )
 	unfurl_banners(the_connection_table,ports,n_tcps,s_tcps,i_unix);
 
 #ifdef ENABLE_NUNC_STANS
-	if (ns_thrpool_wait(tp)) {
+	if (enable_nunc_stans && ns_thrpool_wait(tp)) {
 		LDAPDebug( LDAP_DEBUG_ANY,
 			   "ns_thrpool_wait failed errno %d (%s)\n", errno,
 			   slapd_system_strerror(errno), 0 );
 	}
-
-#else	/* The meat of the operation is in a loop on a call to select */
-	while(!g_get_shutdown())
+#endif
+	/* The meat of the operation is in a loop on a call to select */
+	while(!enable_nunc_stans && !g_get_shutdown())
 	{
 #ifdef _WIN32
 		fd_set			readfds;
@@ -1614,7 +1616,6 @@ void slapd_daemon( daemon_ports_t *ports )
 			break;
 		}
 	}
-#endif /* ENABLE_NUNC_STANS */
 	/* We get here when the server is shutting down */
 	/* Do what we have to do before death */
 
@@ -1688,36 +1689,36 @@ void slapd_daemon( daemon_ports_t *ports )
 
 	threads = g_get_active_threadcnt();
 	while ( threads > 0 ) {
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
-		PRPollDesc xpd;
-		char x;
-		int spe = 0;
-
-		/* try to read from the signal pipe, in case threads are
-		 * blocked on it. */
-		xpd.fd = signalpipe[0];
-		xpd.in_flags = PR_POLL_READ;
-		xpd.out_flags = 0;
-		spe = PR_Poll(&xpd, 1, PR_INTERVAL_NO_WAIT);
-		if (spe > 0) {
-		    spe = PR_Read(signalpipe[0], &x, 1);
-		    if (spe < 0) {
-		        PRErrorCode prerr = PR_GetError();
-				LDAPDebug( LDAP_DEBUG_ANY, "listener could not clear signal pipe, " 
+		if (!enable_nunc_stans) {
+			PRPollDesc xpd;
+			char x;
+			int spe = 0;
+
+			/* try to read from the signal pipe, in case threads are
+			 * blocked on it. */
+			xpd.fd = signalpipe[0];
+			xpd.in_flags = PR_POLL_READ;
+			xpd.out_flags = 0;
+			spe = PR_Poll(&xpd, 1, PR_INTERVAL_NO_WAIT);
+			if (spe > 0) {
+				spe = PR_Read(signalpipe[0], &x, 1);
+				if (spe < 0) {
+					PRErrorCode prerr = PR_GetError();
+					LDAPDebug( LDAP_DEBUG_ANY, "listener could not clear signal pipe, "
+							SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+							prerr, slapd_system_strerror(prerr), 0 );
+					break;
+				}
+			} else if (spe == -1) {
+				PRErrorCode prerr = PR_GetError();
+				LDAPDebug( LDAP_DEBUG_ANY, "PR_Poll() failed, "
 						SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
 						prerr, slapd_system_strerror(prerr), 0 );
-			break;
-		    }
-		} else if (spe == -1) {
-		    PRErrorCode prerr = PR_GetError();
-		    LDAPDebug( LDAP_DEBUG_ANY, "PR_Poll() failed, "
-					SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
-					prerr, slapd_system_strerror(prerr), 0 );
-		    break;
-		} else {
-		    /* no data */
+				break;
+			} else {
+				/* no data */
+			}
 		}
-#endif
 		DS_Sleep(PR_INTERVAL_NO_WAIT);
 		if ( threads != g_get_active_threadcnt() )  {
 			LDAPDebug( LDAP_DEBUG_TRACE,
@@ -1762,7 +1763,9 @@ void slapd_daemon( daemon_ports_t *ports )
 	connection_table_free(the_connection_table);
 	the_connection_table= NULL;
 #ifdef ENABLE_NUNC_STANS
-	ns_thrpool_destroy(tp);
+	if (enable_nunc_stans) {
+		ns_thrpool_destroy(tp);
+	}
 #endif
 	be_cleanupall ();
 	connection_post_shutdown_cleanup();
@@ -1789,7 +1792,9 @@ void slapd_daemon( daemon_ports_t *ports )
 
 int signal_listner()
 {
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
+	if (enable_nunc_stans) {
+		return( 0 );
+	}
 	/* Replaces previous macro---called to bump the thread out of select */
 #if defined( _WIN32 )
 	if ( PR_Write( signalpipe[1], "", 1) != 1 ) {
@@ -1811,17 +1816,18 @@ int signal_listner()
 				errno, 0, 0 );
 	}
 #endif
-#endif
 	return( 0 );
 }
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 #ifdef _WIN32
 static int clear_signal(fd_set *readfdset)
 #else
 static int clear_signal(struct POLL_STRUCT *fds)
 #endif
 {
+	if (enable_nunc_stans) {
+		return 0;
+	}
 #ifdef _WIN32
 	if ( FD_ISSET(readsignalpipe, readfdset)) {
 #else
@@ -1844,7 +1850,6 @@ static int clear_signal(struct POLL_STRUCT *fds)
 	} 
 	return 0;
 }
-#endif /* !ENABLE_NUNC_STANS */
 
 #ifdef _WIN32
 static void set_timeval_ms(struct timeval *t, int ms)
@@ -1989,18 +1994,18 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
 			ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;
 		}
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
-		/* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE (== 0) */
-		count = FDS_SIGNAL_PIPE;
+		if (!enable_nunc_stans) {
+			/* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE (== 0) */
+			count = FDS_SIGNAL_PIPE;
 #if !defined(_WIN32)
-		ct->fd[count].fd = signalpipe[0];
-		ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
-		ct->fd[count].out_flags = 0;
+			ct->fd[count].fd = signalpipe[0];
+			ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
+			ct->fd[count].out_flags = 0;
 #else
-		ct->fd[count].fd = NULL;
-#endif
-		count++;
+			ct->fd[count].fd = NULL;
 #endif
+			count++;
+		}
 		/* The fds entry for n_tcps starts with n_tcps and less than n_tcpe */
 		ct->n_tcps = count;
 		if (n_tcps != NULL && accept_new_connections)
@@ -2262,7 +2267,6 @@ handle_read_ready(Connection_Table *ct, fd_set *readfds)
 #endif   /* _WIN32 */
 
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static void
 handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 {
@@ -2418,7 +2422,6 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 	}
 #endif
 }
-#endif /* !ENABLE_NUNC_STANS */
 
 #ifdef ENABLE_NUNC_STANS
 #define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
@@ -2478,6 +2481,10 @@ ns_connection_post_io_or_closing(Connection *conn)
 #ifdef ENABLE_NUNC_STANS
 	struct timeval tv;
 
+	if (!enable_nunc_stans) {
+		return;
+	}
+
 	if (CONN_NEEDS_CLOSING(conn)) {
 		/* there should only ever be 0 or 1 active closure jobs */
 		PR_ASSERT((conn->c_ns_close_jobs == 0) || (conn->c_ns_close_jobs == 1));
@@ -3386,10 +3393,10 @@ static int init_shutdown_detect()
 	(void) SIGNAL( SIGUSR1, slapd_do_nothing );
 	(void) SIGNAL( SIGUSR2, set_shutdown );
 #endif
-#ifndef ENABLE_NUNC_STANS
-	(void) SIGNAL( SIGTERM, set_shutdown );
-	(void) SIGNAL( SIGHUP,  set_shutdown );
-#endif
+	if (!enable_nunc_stans) {
+		(void) SIGNAL( SIGTERM, set_shutdown );
+		(void) SIGNAL( SIGHUP,  set_shutdown );
+	}
 #endif /* _WIN32 */
 	return 0;
 }
@@ -3984,10 +3991,12 @@ netaddr2string(const PRNetAddr *addr, char *addrbuf, size_t addrbuflen)
 }
 
 
-#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static int
 createsignalpipe( void )
 {
+	if (enable_nunc_stans) {
+		return( 0 );
+	}
 #if defined( _WIN32 )
 	if ( PR_NewTCPSocketPair(&signalpipe[0])) {
 		PRErrorCode prerr = PR_GetError();
@@ -4019,7 +4028,6 @@ createsignalpipe( void )
 #endif
 	return( 0 );
 } 
-#endif
 
 
 #ifdef HPUX10
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index d03d39b..5aee1c4 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -274,6 +274,9 @@ slapi_onoff_t init_ignore_time_skew;
 slapi_onoff_t init_dynamic_plugins;
 slapi_onoff_t init_cn_uses_dn_syntax_in_dns;
 slapi_onoff_t init_global_backend_local;
+#ifdef ENABLE_NUNC_STANS
+slapi_onoff_t init_enable_nunc_stans;
+#endif
 #if defined (LINUX)
 slapi_int_t init_malloc_mxfast;
 slapi_int_t init_malloc_trim_threshold;
@@ -1127,7 +1130,13 @@ static struct config_get_and_set {
 	{CONFIG_GLOBAL_BACKEND_LOCK, config_set_global_backend_lock,
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.global_backend_lock,
-		CONFIG_ON_OFF, (ConfigGetFunc)config_get_global_backend_lock, &init_global_backend_local}	
+		CONFIG_ON_OFF, (ConfigGetFunc)config_get_global_backend_lock, &init_global_backend_local}
+#ifdef ENABLE_NUNC_STANS
+	,{CONFIG_ENABLE_NUNC_STANS, config_set_enable_nunc_stans,
+		NULL, 0,
+		(void**)&global_slapdFrontendConfig.enable_nunc_stans,
+		CONFIG_ON_OFF, (ConfigGetFunc)config_get_enable_nunc_stans, &init_enable_nunc_stans}
+#endif
 #ifdef MEMPOOL_EXPERIMENTAL
 	,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
 		NULL, 0,
@@ -1576,6 +1585,9 @@ FrontendConfig_init () {
   init_dynamic_plugins = cfg->dynamic_plugins = LDAP_OFF;
   init_cn_uses_dn_syntax_in_dns = cfg->cn_uses_dn_syntax_in_dns = LDAP_OFF;
   init_global_backend_local = LDAP_OFF;
+#ifdef ENABLE_NUNC_STANS
+  init_enable_nunc_stans = cfg->enable_nunc_stans = LDAP_OFF;
+#endif
 #if defined(LINUX)
   init_malloc_mxfast = cfg->malloc_mxfast = DEFAULT_MALLOC_UNSET;
   init_malloc_trim_threshold = cfg->malloc_trim_threshold = DEFAULT_MALLOC_UNSET;
@@ -7400,6 +7412,33 @@ config_get_listen_backlog_size()
   return retVal; 
 }
 
+#ifdef ENABLE_NUNC_STANS
+int
+config_get_enable_nunc_stans()
+{
+    int retVal;
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+    CFG_LOCK_READ(slapdFrontendConfig);
+    retVal = slapdFrontendConfig->enable_nunc_stans;
+    CFG_UNLOCK_READ(slapdFrontendConfig);
+
+    return retVal;
+}
+
+int
+config_set_enable_nunc_stans( const char *attrname, char *value,
+                              char *errorbuf, int apply )
+{
+    int retVal = LDAP_SUCCESS;
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+    retVal = config_set_onoff(attrname, value,
+                              &(slapdFrontendConfig->enable_nunc_stans),
+                              errorbuf, apply);
+    return retVal;
+}
+#endif
+
 static char *
 config_initvalue_to_onoff(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize)
 {
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 353024d..408543e 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -597,6 +597,10 @@ int config_set_dynamic_plugins(const char *attrname, char *value, char *errorbuf
 int config_get_dynamic_plugins();
 int config_set_cn_uses_dn_syntax_in_dns(const char *attrname, char *value, char *errorbuf, int apply);
 int config_get_cn_uses_dn_syntax_in_dns();
+#ifdef ENABLE_NUNC_STANS
+int config_get_enable_nunc_stans(void);
+int config_set_enable_nunc_stans(const char *attrname, char *value, char *errorbuf, int apply);
+#endif
 
 PLHashNumber hashNocaseString(const void *key);
 PRIntn hashNocaseCompare(const void *v1, const void *v2);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 6447ee5..b7c6e80 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2126,7 +2126,9 @@ typedef struct _slapdEntryPoints {
 #define CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE "nsslapd-plugin-binddn-tracking"
 #define CONFIG_MODDN_ACI_ATTRIBUTE "nsslapd-moddn-aci"
 #define CONFIG_GLOBAL_BACKEND_LOCK "nsslapd-global-backend-lock"
-
+#ifdef ENABLE_NUNC_STANS
+#define CONFIG_ENABLE_NUNC_STANS "nsslapd-enable-nunc-stans"
+#endif
 #define CONFIG_CONFIG_ATTRIBUTE "nsslapd-config"
 #define CONFIG_INSTDIR_ATTRIBUTE "nsslapd-instancedir"
 #define CONFIG_SCHEMADIR_ATTRIBUTE "nsslapd-schemadir"
@@ -2433,6 +2435,9 @@ typedef struct _slapdFrontendConfig {
   slapi_onoff_t dynamic_plugins; /* allow plugins to be dynamically enabled/disabled */
   slapi_onoff_t cn_uses_dn_syntax_in_dns; /* indicates the cn value in dns has dn syntax */
   slapi_onoff_t global_backend_lock;
+#ifdef ENABLE_NUNC_STANS
+  slapi_onoff_t enable_nunc_stans;
+#endif
 #if defined(LINUX)
   int malloc_mxfast;            /* mallopt M_MXFAST */
   int malloc_trim_threshold;    /* mallopt M_TRIM_THRESHOLD */


commit ecd83708f4fccad7d890034ccea5fc62664261b1
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Mon Apr 27 14:41:30 2015 -0600

    fix compiler warnings when using nunc-stans
    
    Reviewed by: mreynolds (Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index a26dd20..29f0580 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -119,17 +119,18 @@ short	slapd_housekeeping_timer = 10;
 /* Do we support timeout on socket send() ? */
 int have_send_timeouts = 0;
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 PRFileDesc*		signalpipe[2];
 static int writesignalpipe = SLAPD_INVALID_SOCKET;
 static int readsignalpipe = SLAPD_INVALID_SOCKET;
+#define FDS_SIGNAL_PIPE 0
+#endif
 
 static PRThread *disk_thread_p = NULL;
 static PRCondVar *diskmon_cvar = NULL;
 static PRLock *diskmon_mutex = NULL;
 void disk_monitoring_stop();
 
-#define FDS_SIGNAL_PIPE 0
-
 typedef struct listener_info {
 #ifdef ENABLE_NUNC_STANS
 	PRStackElem stackelem; /* must be first in struct for PRStack to work */
@@ -176,7 +177,9 @@ static void* catch_signals();
 HANDLE  hServDoneEvent = NULL;
 #endif
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static int createsignalpipe( void );
+#endif
 
 #if defined( _WIN32 )
 /* Set an event to hook the NT Service termination */
@@ -389,10 +392,16 @@ static void handle_read_ready(Connection_Table *ct, fd_set *readfds);
 static void set_timeval_ms(struct timeval *t, int ms);
 #endif
 /* GGOODREPL static void handle_timeout( void ); */
-static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
 static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn );
 #ifdef ENABLE_NUNC_STANS
 static void ns_handle_new_connection(struct ns_job_t *job);
+#else
+static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
+#ifdef _WIN32
+static int clear_signal(fd_set *readfdset);
+#else
+static int clear_signal(struct POLL_STRUCT *fds);
+#endif
 #endif
 #ifdef _WIN32
 static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
@@ -401,11 +410,6 @@ static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, PRFileDes
 #endif
 static int write_pid_file();
 static int init_shutdown_detect();
-#ifdef _WIN32
-static int clear_signal(fd_set *readfdset);
-#else
-static int clear_signal(struct POLL_STRUCT *fds);
-#endif
 
 /* Globals which are used to store the sockets between
  * calls to daemon_pre_setuid_init() and the daemon thread
@@ -930,6 +934,7 @@ disk_monitoring_thread(void *nothing)
     }
 }
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static void
 handle_listeners(Connection_Table *ct)
 {
@@ -953,6 +958,7 @@ handle_listeners(Connection_Table *ct)
 	}
 	return;
 }
+#endif /* !ENABLE_NUNC_STANS */
 
 /*
  * Convert any pre-existing DES passwords to AES.
@@ -1300,7 +1306,9 @@ void slapd_daemon( daemon_ports_t *ports )
 	PRFileDesc **fdesp = NULL; 
 #endif
 	PRIntn num_poll = 0;
-	PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_wakeup_timer);	
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
+	PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_wakeup_timer);
+#endif
 	PRThread *time_thread_p;
 	int threads;
 	int in_referral_mode = config_check_referral_mode();
@@ -1335,7 +1343,9 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif /* ENABLE_LDAPI */
 #endif
 	
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 	createsignalpipe();
+#endif
 
 	init_shutdown_detect();
 
@@ -1533,12 +1543,16 @@ void slapd_daemon( daemon_ports_t *ports )
 	/* The server is ready and listening for connections. Logging "slapd started" message. */
 	unfurl_banners(the_connection_table,ports,n_tcps,s_tcps,i_unix);
 
-	/* The meat of the operation is in a loop on a call to select */
+#ifdef ENABLE_NUNC_STANS
+	if (ns_thrpool_wait(tp)) {
+		LDAPDebug( LDAP_DEBUG_ANY,
+			   "ns_thrpool_wait failed errno %d (%s)\n", errno,
+			   slapd_system_strerror(errno), 0 );
+	}
+
+#else	/* The meat of the operation is in a loop on a call to select */
 	while(!g_get_shutdown())
 	{
-#ifdef ENABLE_NUNC_STANS
-		DS_Sleep(1);
-#else
 #ifdef _WIN32
 		fd_set			readfds;
 		struct timeval	wakeup_timer;
@@ -1599,8 +1613,8 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif
 			break;
 		}
-#endif
 	}
+#endif /* ENABLE_NUNC_STANS */
 	/* We get here when the server is shutting down */
 	/* Do what we have to do before death */
 
@@ -1674,6 +1688,7 @@ void slapd_daemon( daemon_ports_t *ports )
 
 	threads = g_get_active_threadcnt();
 	while ( threads > 0 ) {
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 		PRPollDesc xpd;
 		char x;
 		int spe = 0;
@@ -1702,6 +1717,7 @@ void slapd_daemon( daemon_ports_t *ports )
 		} else {
 		    /* no data */
 		}
+#endif
 		DS_Sleep(PR_INTERVAL_NO_WAIT);
 		if ( threads != g_get_active_threadcnt() )  {
 			LDAPDebug( LDAP_DEBUG_TRACE,
@@ -1746,10 +1762,6 @@ void slapd_daemon( daemon_ports_t *ports )
 	connection_table_free(the_connection_table);
 	the_connection_table= NULL;
 #ifdef ENABLE_NUNC_STANS
-	if (ns_thrpool_wait(tp)) {
-		/* error */
-	}
-
 	ns_thrpool_destroy(tp);
 #endif
 	be_cleanupall ();
@@ -1777,6 +1789,7 @@ void slapd_daemon( daemon_ports_t *ports )
 
 int signal_listner()
 {
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 	/* Replaces previous macro---called to bump the thread out of select */
 #if defined( _WIN32 )
 	if ( PR_Write( signalpipe[1], "", 1) != 1 ) {
@@ -1798,9 +1811,11 @@ int signal_listner()
 				errno, 0, 0 );
 	}
 #endif
+#endif
 	return( 0 );
 }
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 #ifdef _WIN32
 static int clear_signal(fd_set *readfdset)
 #else
@@ -1829,6 +1844,7 @@ static int clear_signal(struct POLL_STRUCT *fds)
 	} 
 	return 0;
 }
+#endif /* !ENABLE_NUNC_STANS */
 
 #ifdef _WIN32
 static void set_timeval_ms(struct timeval *t, int ms)
@@ -1973,6 +1989,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
 			ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;
 		}
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 		/* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE (== 0) */
 		count = FDS_SIGNAL_PIPE;
 #if !defined(_WIN32)
@@ -1983,7 +2000,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
 		ct->fd[count].fd = NULL;
 #endif
 		count++;
-
+#endif
 		/* The fds entry for n_tcps starts with n_tcps and less than n_tcpe */
 		ct->n_tcps = count;
 		if (n_tcps != NULL && accept_new_connections)
@@ -2245,6 +2262,7 @@ handle_read_ready(Connection_Table *ct, fd_set *readfds)
 #endif   /* _WIN32 */
 
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static void
 handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 {
@@ -2400,6 +2418,7 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 	}
 #endif
 }
+#endif /* !ENABLE_NUNC_STANS */
 
 #ifdef ENABLE_NUNC_STANS
 #define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
@@ -3965,6 +3984,7 @@ netaddr2string(const PRNetAddr *addr, char *addrbuf, size_t addrbuflen)
 }
 
 
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 static int
 createsignalpipe( void )
 {
@@ -3997,9 +4017,9 @@ createsignalpipe( void )
 				errno, 0, 0);
 	}
 #endif
-
 	return( 0 );
 } 
+#endif
 
 
 #ifdef HPUX10


commit ba4948f7e6b98439e1d5a07760a95a13d040f5e9
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Thu Mar 12 14:15:51 2015 -0600

    Ticket #48122 nunc-stans FD leak
    
    https://fedorahosted.org/389/ticket/48122
    Reviewed by: mreynolds (Thanks!)
    Branch: master
    Fix Description: Added a lot of debugging when using CONNS level.  Note
    that it alters the timing considerably, so it should only be used when
    trying to get a general trace of the code, not when performance is an
    issue at all.
    Instead of scheduling a closure job when the connection is made
    readable, wait until the refcnt drops to 1 and the connection is in
    the CLOSING state to avoid having dueling closure jobs.
    The timeout interval for closure jobs is now the same as the old
    slapi_wakeup_timer to avoid tight loops.
    Instead of relying on more_data to still be true at the end of
    connection_threadmain, check the buffer directly to see if there
    is any buffered data, because another thread may have drained the
    buffer out from under this thread.   Added a new convenience
    function conn_buffered_data_avail_nolock() because the buffer size
    is checked in multiple places.
    Do not bypass poll in connection_threadmain when using nunc-stans
    because it kills performance, spending a lot of time doing the
    poll() in connection_read_operation().  Similarly in
    ns_handle_new_connection - do not call ns_handle_pr_read_ready, but
    instead put the new connection back into nunc-stans and only notify
    ns_handle_pr_read_ready when the new connection is ready for read.
    In some cases, the new connection is not ready for read right away,
    and would end up in the poll() in connection_read_operation().
    Platforms tested: Fedora 20, EL7
    Flag Day: no
    Doc impact: no

diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index 4f5c676..58668f0 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -731,7 +731,7 @@ connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb)
 }
 
 /* this function should be called under c_mutex */
-int connection_release_nolock (Connection *conn)
+int connection_release_nolock_ext (Connection *conn, int release_only)
 {
     if (conn->c_refcnt <= 0)
     {
@@ -745,10 +745,21 @@ int connection_release_nolock (Connection *conn)
     {
         conn->c_refcnt--;
 
+        if (!release_only && (conn->c_refcnt == 1) && (conn->c_flags & CONN_FLAG_CLOSING)) {
+        	/* if refcnt == 1 usually means only the active connection list has a ref */
+        	/* refcnt == 0 means conntable just dropped the last ref */
+        	ns_connection_post_io_or_closing(conn);
+        }
+
         return 0;
     }
 }
 
+int connection_release_nolock (Connection *conn)
+{
+	return connection_release_nolock_ext(conn, 0);
+}
+
 /* this function should be called under c_mutex */
 int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing)
 {
@@ -1961,6 +1972,12 @@ connection_read_ldap_data(Connection *conn, PRInt32 *err)
 	return ret;
 }
 
+static size_t
+conn_buffered_data_avail_nolock(Connection *conn)
+{
+	return conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset;
+}
+
 /* Upon returning from this function, we have either: 
    1. Read a PDU successfully.
    2. Detected some error condition with the connection which requires closing it.
@@ -1980,6 +1997,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 	char *buffer = conn->c_private->c_buffer;
 	PRErrorCode err = 0;
 	PRInt32 syserr = 0;
+	size_t buffer_data_avail;
 
 	PR_Lock(conn->c_mutex);
 	/*
@@ -1995,12 +2013,11 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 	
 	*tag = LBER_DEFAULT;
 	/* First check to see if we have buffered data from "before" */
-	if (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) {
+	if ((buffer_data_avail = conn_buffered_data_avail_nolock(conn))) {
 		/* If so, use that data first */
 		if ( 0 != get_next_from_buffer( buffer
 				+ conn->c_private->c_buffer_offset,
-				conn->c_private->c_buffer_bytes
-				- conn->c_private->c_buffer_offset,
+				buffer_data_avail,
 				&len, tag, op->o_ber, conn )) {
 			ret = CONN_DONE;
 			goto done;
@@ -2011,7 +2028,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 	while (*tag == LBER_DEFAULT) {
 		int ioblocktimeout_waits = config_get_ioblocktimeout() / CONN_TURBO_TIMEOUT_INTERVAL;
 		/* We should never get here with data remaining in the buffer */
-		PR_ASSERT( !new_operation || 0 == (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) );
+		PR_ASSERT( !new_operation || 0 == conn_buffered_data_avail_nolock(conn) );
 		/* We make a non-blocking read call */
 		if (CONNECTION_BUFFER_OFF != conn->c_private->use_buffer) {
 			ret = connection_read_ldap_data(conn,&err);
@@ -2088,6 +2105,8 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 					ret = CONN_DONE;
 					goto done;
 				}
+				LDAPDebug( LDAP_DEBUG_CONNS,
+					   "connection %" NSPRIu64 " waited %d times for read to be ready\n", conn->c_connid, waits_done, 0 );
 			} else {
 				/* Some other error, typically meaning bad stuff */
 					syserr = PR_GetOSError();
@@ -2112,6 +2131,8 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 					goto done;
 				}
 			}
+			LDAPDebug( LDAP_DEBUG_CONNS,
+				   "connection %" NSPRIu64 " read %d bytes\n", conn->c_connid, ret, 0 );
 
 			new_operation = 0;
 			ret = CONN_FOUND_WORK_TO_DO;
@@ -2119,7 +2140,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
 		}
 	}
 	/* If there is remaining buffered data, set the flag to tell the caller */
-	if (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) {
+	if (conn_buffered_data_avail_nolock(conn)) {
 		*remaining_data = 1;
 	}
 
@@ -2184,7 +2205,10 @@ void connection_make_readable_nolock(Connection *conn)
 	conn->c_gettingber = 0;
 	LDAPDebug2Args(LDAP_DEBUG_CONNS, "making readable conn %" NSPRIu64 " fd=%d\n",
 		       conn->c_connid, conn->c_sd);
-	ns_connection_post_io_or_closing(conn);
+	if (!(conn->c_flags & CONN_FLAG_CLOSING)) {
+		/* if the connection is closing, try the close in connection_release_nolock */
+		ns_connection_post_io_or_closing(conn);
+	}
 }
 
 /*
@@ -2333,7 +2357,9 @@ connection_threadmain()
 	int replication_connection = 0; /* If this connection is from a replication supplier, we want to ensure that operation processing is serialized */
 	int doshutdown = 0;
 	int maxthreads = 0;
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 	long bypasspollcnt = 0;
+#endif
 
 #if defined( OSF1 ) || defined( hpux )
 	/* Arrange to ignore SIGPIPE signals. */
@@ -2425,6 +2451,17 @@ connection_threadmain()
 		maxthreads = config_get_maxthreadsperconn();
 		more_data = 0;
 		ret = connection_read_operation(conn,op,&tag,&more_data);
+		if ((ret == CONN_DONE) || (ret == CONN_TIMEDOUT)) {
+			slapi_log_error(SLAPI_LOG_CONNS, "connection_threadmain",
+					"conn %" NSPRIu64 " read not ready due to %d - thread_turbo_flag %d more_data %d "
+					"ops_initiated %d refcnt %d flags %d\n", conn->c_connid, ret, thread_turbo_flag, more_data,
+					conn->c_opsinitiated, conn->c_refcnt, conn->c_flags);
+		} else if (ret == CONN_FOUND_WORK_TO_DO) {
+			slapi_log_error(SLAPI_LOG_CONNS, "connection_threadmain",
+					"conn %" NSPRIu64 " read operation successfully - thread_turbo_flag %d more_data %d "
+					"ops_initiated %d refcnt %d flags %d\n", conn->c_connid, thread_turbo_flag, more_data,
+					conn->c_opsinitiated, conn->c_refcnt, conn->c_flags);
+		}
 
 		curtime = current_time();
 #define DB_PERF_TURBO 1		
@@ -2457,11 +2494,21 @@ connection_threadmain()
 			case CONN_TIMEDOUT:
 				thread_turbo_flag = 0;
 				is_timedout = 1;
+				/* In the case of CONN_DONE, more_data could have been set to 1
+				 * in connection_read_operation before an error was encountered.
+				 * In that case, we need to set more_data to 0 - even if there is
+				 * more data available, we're not going to use it anyway.
+				 * In the case of CONN_TIMEDOUT, it is only used in one place, and
+				 * more_data will never be set to 1, so it is safe to set it to 0 here.
+				 * We need more_data to be 0 so the connection will be processed
+				 * correctly at the end of this function.
+				 */
+				more_data = 0;
 				/* note: 
 				 * should call connection_make_readable after the op is removed
 				 * connection_make_readable(conn);
 				 */
-				LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",conn->c_connid,ret,0); 
+				LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",conn->c_connid,ret,0);
 				goto done;
 			case CONN_SHUTDOWN:
 				LDAPDebug( LDAP_DEBUG_TRACE, 
@@ -2499,6 +2546,13 @@ connection_threadmain()
 				/* once the connection is readable, another thread may access conn,
 				 * so need locking from here on */
 				signal_listner();
+/* with nunc-stans, I see an enormous amount of time spent in the poll() in
+ * connection_read_operation() when the below code is enabled - not sure why
+ * nunc-stans makes such a huge difference - for now, just disable this code
+ * when using nunc-stans - it is supposed to be an optimization but turns out
+ * to not be the opposite with nunc-stans
+ */
+#if !defined(ENABLE_NUNC_STANS) || ENABLE_NUNC_STANS == 0
 			} else { /* more data in conn - just put back on work_q - bypass poll */
 				bypasspollcnt++;
 				PR_Lock(conn->c_mutex);
@@ -2511,11 +2565,13 @@ connection_threadmain()
 					 */
 					conn->c_idlesince = curtime;
 					connection_activity(conn, maxthreads);
+					LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " queued because more_data\n",conn->c_connid,0,0);
 				} else {
 					/* keep count of how many times maxthreads has blocked an operation */
 					conn->c_maxthreadsblocked++;
 				}
 				PR_Unlock(conn->c_mutex);
+#endif
 			}
 		}
 
@@ -2589,6 +2645,9 @@ done:
 			connection_remove_operation_ext( pb, conn, op );
 
 			/* If we're in turbo mode, we keep our reference to the connection alive */
+			/* can't use the more_data var because connection could have changed in another thread */
+			more_data = conn_buffered_data_avail_nolock(conn) ? 1 : 0;
+			LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " check more_data %d thread_turbo_flag %d\n",conn->c_connid,more_data,thread_turbo_flag);
 			if (!more_data) {
 				if (!thread_turbo_flag) {
 					/*
@@ -3011,7 +3070,7 @@ static ps_wakeup_all_fn_ptr ps_wakeup_all_fn = NULL;
  */
 
 void
-disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErrorCode reason, PRInt32 error )
+disconnect_server_nomutex_ext( Connection *conn, PRUint64 opconnid, int opid, PRErrorCode reason, PRInt32 error, int schedule_closure_job )
 {
     if ( ( conn->c_sd != SLAPD_INVALID_SOCKET &&
 	    conn->c_connid == opconnid ) && !(conn->c_flags & CONN_FLAG_CLOSING) )
@@ -3088,7 +3147,9 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
 				}
 			}
 		}
-		ns_connection_post_io_or_closing(conn); /* make sure event loop wakes up and closes this conn */
+		if (schedule_closure_job) {
+			ns_connection_post_io_or_closing(conn); /* make sure event loop wakes up and closes this conn */
+		}
 
     } else {
 	    LDAPDebug2Args(LDAP_DEBUG_CONNS, "not setting conn %d to be disconnected: %s\n",
@@ -3100,6 +3161,12 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
 }
 
 void
+disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErrorCode reason, PRInt32 error )
+{
+	disconnect_server_nomutex_ext(conn, opconnid, opid, reason, error, 1);
+}
+
+void
 connection_abandon_operations( Connection *c )
 {
 	Operation *op;
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index 3726bd6..dc2e265 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -354,7 +354,7 @@ connection_table_move_connection_on_to_active_list(Connection_Table *ct,Connecti
 
 	PR_Lock(ct->table_mutex);
 
-	connection_acquire_nolock (c);
+	PR_ASSERT(0 == connection_acquire_nolock (c));
 
 #ifdef FOR_DEBUGGING
     slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection into active list\n");
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index b37ca6d..a26dd20 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -2402,6 +2402,25 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 }
 
 #ifdef ENABLE_NUNC_STANS
+#define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
+/* Used internally by ns_handle_closure and ns_handle_pr_read_ready.
+ * Returns 0 if the connection was successfully closed, or 1 otherwise.
+ * Must be called with the c->c_mutex locked.
+ */
+static int
+ns_handle_closure_nomutex(Connection *c)
+{
+	int rc = 0;
+	PR_ASSERT(c->c_refcnt > 0); /* one for the conn active list, plus possible other threads */
+	PR_ASSERT(CONN_NEEDS_CLOSING(c));
+	if (connection_table_move_connection_out_of_active_list(c->c_ct, c)) {
+		/* not closed - another thread still has a ref */
+		rc = 1;
+		/* reschedule closure job */
+		ns_connection_post_io_or_closing(c);
+	}
+	return rc;
+}
 /* This function is called when the connection has been marked
  * as closing and needs to be cleaned up.  It will keep trying
  * and re-arming itself until there are no references.
@@ -2415,22 +2434,20 @@ ns_handle_closure(struct ns_job_t *job)
 	/* this function must be called from the event loop thread */
 	PR_ASSERT(0 == NS_JOB_IS_THREAD(ns_job_get_type(job)));
 	PR_Lock(c->c_mutex);
-	c->c_ns_close_jobs--;
-	connection_release_nolock(c); /* release ref acquired when job was added */
-	if (connection_table_move_connection_out_of_active_list(c->c_ct, c)) {
-		do_yield = 1;
-		ns_connection_post_io_or_closing(c);
-	}
+	connection_release_nolock_ext(c, 1); /* release ref acquired for event framework */
+	PR_ASSERT(c->c_ns_close_jobs == 1); /* should be exactly 1 active close job - this one */
+	c->c_ns_close_jobs--; /* this job is processing closure */
+	do_yield = ns_handle_closure_nomutex(c);
 	PR_Unlock(c->c_mutex);
 	ns_job_done(job);
 	if (do_yield) {
+		/* closure not done - another reference still outstanding */
 		/* yield thread after unlocking conn mutex */
 		PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield to allow other thread to release conn */
 	}
 	return;
 }
 #endif
-#define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
 
 /**
  * Schedule more I/O for this connection, or make sure that it
@@ -2441,19 +2458,22 @@ ns_connection_post_io_or_closing(Connection *conn)
 {
 #ifdef ENABLE_NUNC_STANS
 	struct timeval tv;
-	ns_job_func_t job_func;
 
 	if (CONN_NEEDS_CLOSING(conn)) {
+		/* there should only ever be 0 or 1 active closure jobs */
+		PR_ASSERT((conn->c_ns_close_jobs == 0) || (conn->c_ns_close_jobs == 1));
 		if (conn->c_ns_close_jobs) {
 			LDAPDebug2Args(LDAP_DEBUG_CONNS, "already a close job in progress on conn %" NSPRIu64 " for fd=%d\n",
 				       conn->c_connid, conn->c_sd);
 			return;
 		} else {
-			/* just make sure the event is processed at the next possible event loop run */
+			/* just make sure we schedule the event to be closed in a timely manner */
 			tv.tv_sec = 0;
-			tv.tv_usec = 1000;
-			job_func = ns_handle_closure;
-			conn->c_ns_close_jobs++;
+			tv.tv_usec = slapd_wakeup_timer * 1000;
+			conn->c_ns_close_jobs++; /* now 1 active closure job */
+			connection_acquire_nolock_ext(conn, 1 /* allow acquire even when closing */); /* event framework now has a reference */
+			ns_add_timeout_job(conn->c_tp, &tv, NS_JOB_TIMER,
+					   ns_handle_closure, conn, NULL);
 			LDAPDebug2Args(LDAP_DEBUG_CONNS, "post closure job for conn %" NSPRIu64 " for fd=%d\n",
 				       conn->c_connid, conn->c_sd);
 		}
@@ -2461,14 +2481,13 @@ ns_connection_post_io_or_closing(Connection *conn)
 		/* process event normally - wait for I/O until idletimeout */
 		tv.tv_sec = conn->c_idletimeout;
 		tv.tv_usec = 0;
-		job_func = ns_handle_pr_read_ready;
+		PR_ASSERT(0 == connection_acquire_nolock(conn)); /* event framework now has a reference */
+		ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,
+				      NS_JOB_READ|NS_JOB_PRESERVE_FD,
+				      ns_handle_pr_read_ready, conn, NULL);
 		LDAPDebug2Args(LDAP_DEBUG_CONNS, "post I/O job for conn %" NSPRIu64 " for fd=%d\n",
 			       conn->c_connid, conn->c_sd);
 	}
-	connection_acquire_nolock_ext(conn, 1 /* allow acquire even when closing */); /* event framework will have reference */
-	ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,
-			      NS_JOB_READ|NS_JOB_PRESERVE_FD,
-			      job_func, conn, NULL);
 #endif
 }
 
@@ -2480,7 +2499,6 @@ ns_connection_post_io_or_closing(Connection *conn)
 void
 ns_handle_pr_read_ready(struct ns_job_t *job)
 {
-	int need_closure = 0;
 	int maxthreads = config_get_maxthreadsperconn();
 	Connection *c = (Connection *)ns_job_get_data(job);
 
@@ -2492,14 +2510,14 @@ ns_handle_pr_read_ready(struct ns_job_t *job)
 		       c->c_connid, c->c_sd);
 	/* if we were called due to some i/o event, see what the state of the socket is */
 	if (slapi_is_loglevel_set(SLAPI_LOG_CONNS) && !NS_JOB_IS_TIMER(ns_job_get_output_type(job)) && c && c->c_sd) {
-		/* see if socket is closed */
+		/* check socket state */
 		char buf[1];
 		ssize_t rc = recv(c->c_sd, buf, sizeof(buf), MSG_PEEK);
 		if (!rc) {
 			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket is closed conn %" NSPRIu64 " for fd=%d\n",
 				       c->c_connid, c->c_sd);
 		} else if (rc > 0) {
-			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has data available for conn %" NSPRIu64 " for fd=%d\n",
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket read data available for conn %" NSPRIu64 " for fd=%d\n",
 				       c->c_connid, c->c_sd);
 		} else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
 			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has no data available conn %" NSPRIu64 " for fd=%d\n",
@@ -2509,14 +2527,15 @@ ns_handle_pr_read_ready(struct ns_job_t *job)
 				  errno, c->c_connid, c->c_sd);
 		}
 	}
-	connection_release_nolock(c); /* release ref acquired when job was added */
+	connection_release_nolock_ext(c, 1); /* release ref acquired when job was added */
 	if (CONN_NEEDS_CLOSING(c)) {
-		need_closure = 1;
+		ns_handle_closure_nomutex(c);
 	} else if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {
 		/* idle timeout */
-		disconnect_server_nomutex(c, c->c_connid, -1,
-				          SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN);
-		need_closure = 1;
+		disconnect_server_nomutex_ext(c, c->c_connid, -1,
+					      SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN,
+				              0 /* do not schedule closure, do it next */);
+		ns_handle_closure_nomutex(c);
 	} else if ((connection_activity(c, maxthreads)) == -1) {
 		/* This might happen as a result of
 		 * trying to acquire a closing connection
@@ -2525,16 +2544,14 @@ ns_handle_pr_read_ready(struct ns_job_t *job)
 			       " as fd=%d is already closing\n", c->c_connid, c->c_sd);
 		/* The call disconnect_server should do nothing,
 		 * as the connection c should be already set to CLOSING */
-		disconnect_server_nomutex(c, c->c_connid, -1,
-				          SLAPD_DISCONNECT_POLL, EPIPE);
-		need_closure = 1;
+		disconnect_server_nomutex_ext(c, c->c_connid, -1,
+				              SLAPD_DISCONNECT_POLL, EPIPE,
+				              0 /* do not schedule closure, do it next */);
+		ns_handle_closure_nomutex(c);
 	} else {
 		LDAPDebug2Args(LDAP_DEBUG_CONNS, "queued conn %" NSPRIu64 " for fd=%d\n",
 			       c->c_connid, c->c_sd);
 	}
-	if (need_closure) {
-		ns_connection_post_io_or_closing(c);
-	}
 	PR_Unlock(c->c_mutex);
 	ns_job_done(job);
 	return;
@@ -3273,12 +3290,15 @@ ns_handle_new_connection(struct ns_job_t *job)
 		}
 		return;
 	}
-	/* now, set up the conn for reading - no thread - ns_handle_pr_read_ready
-	 * must be run in the event loop thread
-	 */
 	c->c_tp = ns_job_get_tp(job);
-	connection_acquire_nolock(c); /* event framework now has ref */
-	ns_add_job(ns_job_get_tp(job), NS_JOB_NONE, ns_handle_pr_read_ready, c, NULL);
+	/* This originally just called ns_handle_pr_read_ready directly - however, there
+	 * are certain cases where accept() will return a file descriptor that is not
+	 * immediately available for reading - this would cause the poll() in
+	 * connection_read_operation() to be hit - it seemed to perform better when
+	 * that poll() was avoided, even at the expense of putting this new fd back
+	 * in nunc-stans to poll for read ready.
+	 */
+	ns_connection_post_io_or_closing(c);
 	return;
 }
 #endif
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 40f5f9e..353024d 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1003,6 +1003,7 @@ int send_ldap_referral( Slapi_PBlock *pb, Slapi_Entry *e, struct berval **refs,
 int send_ldapv3_referral( Slapi_PBlock *pb, struct berval **urls );
 int set_db_default_result_handlers(Slapi_PBlock *pb);
 void disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErrorCode reason, PRInt32 error );
+void disconnect_server_nomutex_ext( Connection *conn, PRUint64 opconnid, int opid, PRErrorCode reason, PRInt32 error, int schedule_closure_job );
 long g_get_current_conn_count();
 void g_increment_current_conn_count();
 void g_decrement_current_conn_count();
@@ -1423,6 +1424,7 @@ int mapping_tree_get_extension_type ();
 int connection_acquire_nolock (Connection *conn);
 int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing);
 int connection_release_nolock (Connection *conn);
+int connection_release_nolock_ext (Connection *conn, int release_only);
 int connection_is_free (Connection *conn);
 int connection_is_active_nolock (Connection *conn);
 #if defined(USE_OPENLDAP)


commit 34635fbff3f82edca50fbb0582d62b170722addf
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Fri Mar 6 11:32:00 2015 -0500

    Ticket 48103 - update DS for new nunc-stans header file
    
    Description:  Remove references to ns_thrpool.h, and replace it with nunc-stans.h
    
                  Also the function params for ns_add_job needed to be updated.
    
    https://fedorahosted.org/389/ticket/48103
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/configure b/configure
index e1e0525..8d8ca08 100755
--- a/configure
+++ b/configure
@@ -21325,7 +21325,7 @@ $as_echo "using $withval" >&6; }
         nunc_stans_lib="-L$withval/lib"
     nunc_stans_libdir="$withval/lib"
     nunc_stans_incdir="$withval/include"
-    if ! test -e "$nunc_stans_incdir/nunc-stans/ns_thrpool.h" ; then
+    if ! test -e "$nunc_stans_incdir/nunc-stans/nunc-stans.h" ; then
       as_fn_error $? "$withval include dir not found" "$LINENO" 5
     fi
     nunc_stans_inc="-I$nunc_stans_incdir"
@@ -21347,7 +21347,7 @@ $as_echo_n "checking for --with-nunc-stans-inc... " >&6; }
 # Check whether --with-nunc-stans-inc was given.
 if test "${with_nunc_stans_inc+set}" = set; then :
   withval=$with_nunc_stans_inc;
-  if test -e "$withval"/nunc-stans/ns_thrpool.h
+  if test -e "$withval"/nunc-stans/nunc-stans.h
   then
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
 $as_echo "using $withval" >&6; }
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 07d57b8..b37ca6d 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -3278,7 +3278,7 @@ ns_handle_new_connection(struct ns_job_t *job)
 	 */
 	c->c_tp = ns_job_get_tp(job);
 	connection_acquire_nolock(c); /* event framework now has ref */
-	ns_add_job(ns_job_get_tp(job), NULL, NS_JOB_NONE, ns_handle_pr_read_ready, c);
+	ns_add_job(ns_job_get_tp(job), NS_JOB_NONE, ns_handle_pr_read_ready, c, NULL);
 	return;
 }
 #endif
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 8a0d11a..6447ee5 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -173,7 +173,7 @@ typedef struct symbol_t {
 #include "uuid.h"
 
 #ifdef ENABLE_NUNC_STANS
-#include <nunc-stans/ns_thrpool.h>
+#include <nunc-stans/nunc-stans.h>
 #endif
 
 #if defined(OS_solaris)
diff --git a/m4/nunc-stans.m4 b/m4/nunc-stans.m4
index 91ba72e..a2137d3 100644
--- a/m4/nunc-stans.m4
+++ b/m4/nunc-stans.m4
@@ -34,7 +34,7 @@ AC_ARG_WITH(nunc-stans, AS_HELP_STRING([--with-nunc-stans@<:@=PATH@:>@],[nunc-st
     nunc_stans_lib="-L$withval/lib"
     nunc_stans_libdir="$withval/lib"
     nunc_stans_incdir="$withval/include"
-    if ! test -e "$nunc_stans_incdir/nunc-stans/ns_thrpool.h" ; then
+    if ! test -e "$nunc_stans_incdir/nunc-stans/nunc-stans.h" ; then
       AC_MSG_ERROR([$withval include dir not found])
     fi
     nunc_stans_inc="-I$nunc_stans_incdir"
@@ -49,7 +49,7 @@ AC_MSG_RESULT(no))
 AC_MSG_CHECKING(for --with-nunc-stans-inc)
 AC_ARG_WITH(nunc-stans-inc, AS_HELP_STRING([--with-nunc-stans-inc=PATH],[nunc-stans include file directory]),
 [
-  if test -e "$withval"/nunc-stans/ns_thrpool.h
+  if test -e "$withval"/nunc-stans/nunc-stans.h
   then
     AC_MSG_RESULT([using $withval])
     nunc_stans_incdir="$withval"


commit 1bf59dcb662944d14c0ed1f9d924bf8ef8278292
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Fri Feb 27 18:31:16 2015 -0500

    Ticket 48110 - Free all the nunc-stans signal jobs when shutdown is detected
    
    Description:  Need to free all the nunc-stans signal jobs when shutdown is detected.
    
    https://fedorahosted.org/389/ticket/48110
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 9ddd780..07d57b8 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -163,6 +163,7 @@ static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
 	size_t addrbuflen);
 static void	set_shutdown (int);
 #ifdef ENABLE_NUNC_STANS
+struct ns_job_t *ns_signal_job[3];
 static void	ns_set_shutdown (struct ns_job_t *job);
 #endif
 static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
@@ -1514,9 +1515,9 @@ void slapd_daemon( daemon_ports_t *ports )
 		tp_config.free_fct = nunc_stans_free;
 
 		tp = ns_thrpool_new(&tp_config);
-		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
-		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
-		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, &ns_signal_job[0]);
+		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, &ns_signal_job[1]);
+		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, &ns_signal_job[2]);
 		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
 		for (ii = 0; ii < listeners; ++ii) {
 			listener_idxs[ii].ct = the_connection_table; /* to pass to handle_new_connection */
@@ -3554,7 +3555,11 @@ ns_set_shutdown(struct ns_job_t *job)
 
 	/* Signal all the worker threads to stop */
 	ns_thrpool_shutdown(ns_job_get_tp(job));
-	ns_job_done(job);
+
+	/* Free all the signal jobs */
+	ns_job_done(ns_signal_job[0]);
+	ns_job_done(ns_signal_job[1]);
+	ns_job_done(ns_signal_job[2]);
 }
 #endif
 


commit 4fc526e6274262bf022bb330d396d8f50ab02871
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Thu Feb 26 19:00:58 2015 -0700

    get rid of lfds - use nunc-stans/ subdir for nunc-stans headers

diff --git a/Makefile.am b/Makefile.am
index 4ecdaf1..39fc2ee 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,8 +15,8 @@ DEBUG_DEFINES = @debug_defs@
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 if enable_nunc_stans
-NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
-NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+NUNC_STANS_INCLUDES = $(nunc_stans_inc)
+NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans
 endif
 DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
 
diff --git a/Makefile.in b/Makefile.in
index 06e6511..218bc8d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -108,8 +108,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/sasl.m4 $(top_srcdir)/m4/svrcore.m4 \
 	$(top_srcdir)/m4/icu.m4 $(top_srcdir)/m4/netsnmp.m4 \
 	$(top_srcdir)/m4/kerberos.m4 $(top_srcdir)/m4/pcre.m4 \
-	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/m4/lfds.m4 \
-	$(top_srcdir)/m4/nunc-stans.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/m4/nunc-stans.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -706,8 +706,7 @@ libschemareload_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(libschemareload_plugin_la_LDFLAGS) \
 	$(LDFLAGS) -o $@
- at enable_nunc_stans_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \
- at enable_nunc_stans_TRUE@	$(am__DEPENDENCIES_1)
+ at enable_nunc_stans_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
 libslapd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
@@ -1423,9 +1422,6 @@ ldapsdk_lib = @ldapsdk_lib@
 ldapsdk_libdir = @ldapsdk_libdir@
 ldaptool_bindir = @ldaptool_bindir@
 ldaptool_opts = @ldaptool_opts@
-lfds_inc = @lfds_inc@
-lfds_lib = @lfds_lib@
-lfds_libdir = @lfds_libdir@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -1512,8 +1508,8 @@ DEBUG_DEFINES = @debug_defs@
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 
- at enable_nunc_stans_TRUE@NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
- at enable_nunc_stans_TRUE@NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+ at enable_nunc_stans_TRUE@NUNC_STANS_INCLUDES = $(nunc_stans_inc)
+ at enable_nunc_stans_TRUE@NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans
 DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
 
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
diff --git a/configure b/configure
index ec30ecd..e1e0525 100755
--- a/configure
+++ b/configure
@@ -643,9 +643,6 @@ localrundir
 nunc_stans_libdir
 nunc_stans_lib
 nunc_stans_inc
-lfds_libdir
-lfds_lib
-lfds_inc
 pcre_libdir
 pcre_lib
 pcre_inc
@@ -965,9 +962,6 @@ with_kerberos_inc
 with_kerberos_lib
 with_pcre
 with_selinux
-with_lfds
-with_lfds_inc
-with_lfds_lib
 with_nunc_stans
 with_nunc_stans_inc
 with_nunc_stans_lib
@@ -1734,9 +1728,6 @@ Optional Packages:
                           kerberos
   --with-pcre[=PATH]      Perl Compatible Regular Expression directory
   --with-selinux          Support SELinux policy
-  --with-lfds[=PATH]      LFDS directory
-  --with-lfds-inc=PATH    LFDS include file directory
-  --with-lfds-lib=PATH    LFDS library directory
   --with-nunc-stans[=PATH]
                           nunc-stans directory
   --with-nunc-stans-inc=PATH
@@ -21313,110 +21304,6 @@ fi
 #
 # END COPYRIGHT BLOCK
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lfds..." >&5
-$as_echo "$as_me: checking for lfds..." >&6;}
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds" >&5
-$as_echo_n "checking for --with-lfds... " >&6; }
-
-# Check whether --with-lfds was given.
-if test "${with_lfds+set}" = set; then :
-  withval=$with_lfds;
-  if test "$withval" = "yes"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  elif test "$withval" = "no"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  elif test -d "$withval"/inc -a -d "$withval"/bin; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
-$as_echo "using $withval" >&6; }
-        lfds_lib="-L$withval/bin"
-    lfds_libdir="$withval/lib"
-    lfds_incdir="$withval/inc"
-    if ! test -e "$lfds_incdir/liblfds.h" ; then
-      as_fn_error $? "$withval include dir not found" "$LINENO" 5
-    fi
-    lfds_inc="-I$lfds_incdir"
-  else
-    echo
-    as_fn_error $? "$withval not found" "$LINENO" 5
-  fi
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-# check for --with-lfds-inc
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-inc" >&5
-$as_echo_n "checking for --with-lfds-inc... " >&6; }
-
-# Check whether --with-lfds-inc was given.
-if test "${with_lfds_inc+set}" = set; then :
-  withval=$with_lfds_inc;
-  if test -e "$withval"/liblfds.h
-  then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
-$as_echo "using $withval" >&6; }
-    lfds_incdir="$withval"
-    lfds_inc="-I$withval"
-  else
-    echo
-    as_fn_error $? "$withval not found" "$LINENO" 5
-  fi
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-# check for --with-lfds-lib
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-lib" >&5
-$as_echo_n "checking for --with-lfds-lib... " >&6; }
-
-# Check whether --with-lfds-lib was given.
-if test "${with_lfds_lib+set}" = set; then :
-  withval=$with_lfds_lib;
-  if test -d "$withval"
-  then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
-$as_echo "using $withval" >&6; }
-    lfds_lib="-L$withval"
-    lfds_libdir="$withval"
-  else
-    echo
-    as_fn_error $? "$withval not found" "$LINENO" 5
-  fi
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-# BEGIN COPYRIGHT BLOCK
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#
-# END COPYRIGHT BLOCK
-
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nunc-stans..." >&5
 $as_echo "$as_me: checking for nunc-stans..." >&6;}
 
@@ -21435,10 +21322,10 @@ $as_echo "no" >&6; }
   elif test -d "$withval"; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
 $as_echo "using $withval" >&6; }
-        nunc_stans_lib="-L$withval"
-    nunc_stans_libdir="$withval"
-    nunc_stans_incdir="$withval"
-    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+        nunc_stans_lib="-L$withval/lib"
+    nunc_stans_libdir="$withval/lib"
+    nunc_stans_incdir="$withval/include"
+    if ! test -e "$nunc_stans_incdir/nunc-stans/ns_thrpool.h" ; then
       as_fn_error $? "$withval include dir not found" "$LINENO" 5
     fi
     nunc_stans_inc="-I$nunc_stans_incdir"
@@ -21460,7 +21347,7 @@ $as_echo_n "checking for --with-nunc-stans-inc... " >&6; }
 # Check whether --with-nunc-stans-inc was given.
 if test "${with_nunc_stans_inc+set}" = set; then :
   withval=$with_nunc_stans_inc;
-  if test -e "$withval"/ns_thrpool.h
+  if test -e "$withval"/nunc-stans/ns_thrpool.h
   then
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
 $as_echo "using $withval" >&6; }
@@ -21595,9 +21482,6 @@ fi
 
 
 
-
-
-
 # AC_DEFINE([USE_OLD_UNHASHED], [], [Use old unhashed code])
 
 $as_echo "#define LDAP_DEBUG 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index 96a7179..c151870 100644
--- a/configure.ac
+++ b/configure.ac
@@ -690,7 +690,6 @@ m4_include(m4/netsnmp.m4)
 m4_include(m4/kerberos.m4)
 m4_include(m4/pcre.m4)
 m4_include(m4/selinux.m4)
-m4_include(m4/lfds.m4)
 m4_include(m4/nunc-stans.m4)
 
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
@@ -749,9 +748,6 @@ AC_SUBST(netsnmp_link)
 AC_SUBST(pcre_inc)
 AC_SUBST(pcre_lib)
 AC_SUBST(pcre_libdir)
-AC_SUBST(lfds_inc)
-AC_SUBST(lfds_lib)
-AC_SUBST(lfds_libdir)
 AC_SUBST(nunc_stans_inc)
 AC_SUBST(nunc_stans_lib)
 AC_SUBST(nunc_stans_libdir)
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index b856afe..8a0d11a 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -173,7 +173,7 @@ typedef struct symbol_t {
 #include "uuid.h"
 
 #ifdef ENABLE_NUNC_STANS
-#include <ns_thrpool.h>
+#include <nunc-stans/ns_thrpool.h>
 #endif
 
 #if defined(OS_solaris)
diff --git a/m4/lfds.m4 b/m4/lfds.m4
deleted file mode 100644
index d5dcbb7..0000000
--- a/m4/lfds.m4
+++ /dev/null
@@ -1,78 +0,0 @@
-# BEGIN COPYRIGHT BLOCK
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#
-# END COPYRIGHT BLOCK
-
-AC_CHECKING(for lfds)
-
-dnl  - check for --with-lfds
-AC_MSG_CHECKING(for --with-lfds)
-AC_ARG_WITH(lfds, AS_HELP_STRING([--with-lfds@<:@=PATH@:>@],[LFDS directory]),
-[
-  if test "$withval" = "yes"; then
-    AC_MSG_RESULT(yes)
-  elif test "$withval" = "no"; then
-    AC_MSG_RESULT(no)
-  elif test -d "$withval"/inc -a -d "$withval"/bin; then
-    AC_MSG_RESULT([using $withval])
-    dnl - check the user provided location
-    lfds_lib="-L$withval/bin"
-    lfds_libdir="$withval/lib"
-    lfds_incdir="$withval/inc"
-    if ! test -e "$lfds_incdir/liblfds.h" ; then
-      AC_MSG_ERROR([$withval include dir not found])
-    fi
-    lfds_inc="-I$lfds_incdir"
-  else
-    echo
-    AC_MSG_ERROR([$withval not found])
-  fi
-],
-AC_MSG_RESULT(no))
-
-# check for --with-lfds-inc
-AC_MSG_CHECKING(for --with-lfds-inc)
-AC_ARG_WITH(lfds-inc, AS_HELP_STRING([--with-lfds-inc=PATH],[LFDS include file directory]),
-[
-  if test -e "$withval"/liblfds.h
-  then
-    AC_MSG_RESULT([using $withval])
-    lfds_incdir="$withval"
-    lfds_inc="-I$withval"
-  else
-    echo
-    AC_MSG_ERROR([$withval not found])
-  fi
-],
-AC_MSG_RESULT(no))
-
-# check for --with-lfds-lib
-AC_MSG_CHECKING(for --with-lfds-lib)
-AC_ARG_WITH(lfds-lib, AS_HELP_STRING([--with-lfds-lib=PATH],[LFDS library directory]),
-[
-  if test -d "$withval"
-  then
-    AC_MSG_RESULT([using $withval])
-    lfds_lib="-L$withval"
-    lfds_libdir="$withval"
-  else
-    echo
-    AC_MSG_ERROR([$withval not found])
-  fi
-],
-AC_MSG_RESULT(no))
diff --git a/m4/nunc-stans.m4 b/m4/nunc-stans.m4
index e68f651..91ba72e 100644
--- a/m4/nunc-stans.m4
+++ b/m4/nunc-stans.m4
@@ -31,10 +31,10 @@ AC_ARG_WITH(nunc-stans, AS_HELP_STRING([--with-nunc-stans@<:@=PATH@:>@],[nunc-st
   elif test -d "$withval"; then
     AC_MSG_RESULT([using $withval])
     dnl - check the user provided location
-    nunc_stans_lib="-L$withval"
-    nunc_stans_libdir="$withval"
-    nunc_stans_incdir="$withval"
-    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+    nunc_stans_lib="-L$withval/lib"
+    nunc_stans_libdir="$withval/lib"
+    nunc_stans_incdir="$withval/include"
+    if ! test -e "$nunc_stans_incdir/nunc-stans/ns_thrpool.h" ; then
       AC_MSG_ERROR([$withval include dir not found])
     fi
     nunc_stans_inc="-I$nunc_stans_incdir"
@@ -49,7 +49,7 @@ AC_MSG_RESULT(no))
 AC_MSG_CHECKING(for --with-nunc-stans-inc)
 AC_ARG_WITH(nunc-stans-inc, AS_HELP_STRING([--with-nunc-stans-inc=PATH],[nunc-stans include file directory]),
 [
-  if test -e "$withval"/ns_thrpool.h
+  if test -e "$withval"/nunc-stans/ns_thrpool.h
   then
     AC_MSG_RESULT([using $withval])
     nunc_stans_incdir="$withval"


commit efe42b474049e790401179a75e8574ec2029cc8f
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Thu Feb 26 15:33:33 2015 -0500

    Ticket 48043 - use nunc-stans config initializer
    
    Description:  Use the nunc-stans thread pool config initializer before
                  creating a new thread pool.
    
    https://fedorahosted.org/389/ticket/48043
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index dc69bc4..9ddd780 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -1498,6 +1498,8 @@ void slapd_daemon( daemon_ports_t *ports )
 			maxthreads = atoi(getenv("MAX_THREADS"));
 		}
 		/* Set the nunc-stans thread pool config */
+		ns_thrpool_config_init(&tp_config);
+
 		tp_config.initial_threads = maxthreads;
 		tp_config.max_threads = maxthreads;
 		tp_config.stacksize = 0;


commit 98b57d142af6c4a42d9a69922eccc73067e07b70
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Thu Feb 26 15:07:45 2015 -0500

    Ticket 48039 - nunc-stans malloc should be pluggable
    
    Description:  Allow malloc, calloc, realloc, and free to be
                  pluggable in nunc-stans.  Created wrapper functions
                  for slapi_ch_malloc, etc, to comply with C signatures.
    
    https://fedorahosted.org/389/ticket/48039
    
    Reviewed by: ?

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index e4ed0df..dc69bc4 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -1251,6 +1251,30 @@ nunc_stans_logging(int priority, const char *format, va_list varg)
 	slapi_log_error_ext(severity, "nunc-stans", (char *)format, varg, varg_copy);
 	va_end(varg_copy);
 }
+
+static void*
+nunc_stans_malloc(size_t size)
+{
+	return (void*)slapi_ch_malloc((unsigned long)size);
+}
+
+static void*
+nunc_stans_calloc(size_t count, size_t size)
+{
+	return (void*)slapi_ch_calloc((unsigned long)count, (unsigned long)size);
+}
+
+static void*
+nunc_stans_realloc(void *block, size_t size)
+{
+	return (void*)slapi_ch_realloc((char *)block, (unsigned long)size);
+}
+
+static void
+nunc_stans_free(void *ptr)
+{
+	slapi_ch_free((void **)&ptr);
+}
 #endif
 
 void slapd_daemon( daemon_ports_t *ports )
@@ -1480,6 +1504,12 @@ void slapd_daemon( daemon_ports_t *ports )
 		tp_config.event_queue_size = config_get_maxdescriptors();
 		tp_config.work_queue_size = config_get_maxdescriptors();
 		tp_config.log_fct = nunc_stans_logging;
+		tp_config.log_start_fct = NULL;
+		tp_config.log_close_fct = NULL;
+		tp_config.malloc_fct = nunc_stans_malloc;
+		tp_config.calloc_fct = nunc_stans_calloc;
+		tp_config.realloc_fct = nunc_stans_realloc;
+		tp_config.free_fct = nunc_stans_free;
 
 		tp = ns_thrpool_new(&tp_config);
 		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);


commit 3b7c2bb0c7e18f3d011e09d2c792ea69fa3f7121
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed Feb 25 16:42:24 2015 -0500

    Ticket 48038 - logging should be pluggable
    
    Description:  We need to pass in a logging function to nunc-stans,
                  so we can log nunc-stan information in the DS errors
                  log.  There are also "log start" and "log_close"
                  functions that can be passed in as well.
    
                  If a log function is not set in the thrpool config, then
                  the logging will be sent to syslog.
    
    https://fedorahosted.org/389/ticket/48038/
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/include/ldaplog.h b/ldap/include/ldaplog.h
index f9f73cc..6ced113 100644
--- a/ldap/include/ldaplog.h
+++ b/ldap/include/ldaplog.h
@@ -47,28 +47,29 @@
 extern "C" {
 #endif
 
-#define LDAP_DEBUG_TRACE	0x00001		/*     1 */
-#define LDAP_DEBUG_PACKETS	0x00002		/*     2 */
-#define LDAP_DEBUG_ARGS		0x00004		/*     4 */
-#define LDAP_DEBUG_CONNS	0x00008		/*     8 */
-#define LDAP_DEBUG_BER		0x00010		/*    16 */
-#define LDAP_DEBUG_FILTER	0x00020		/*    32 */
-#define LDAP_DEBUG_CONFIG	0x00040		/*    64 */
-#define LDAP_DEBUG_ACL		0x00080		/*   128 */
-#define LDAP_DEBUG_STATS	0x00100		/*   256 */
-#define LDAP_DEBUG_STATS2	0x00200		/*   512 */
-#define LDAP_DEBUG_SHELL	0x00400		/*  1024 */
-#define LDAP_DEBUG_PARSE	0x00800		/*  2048 */
-#define LDAP_DEBUG_HOUSE        0x01000		/*  4096 */
-#define LDAP_DEBUG_REPL         0x02000		/*  8192 */
-#define LDAP_DEBUG_ANY          0x04000		/* 16384 */
-#define LDAP_DEBUG_CACHE        0x08000		/* 32768 */
-#define LDAP_DEBUG_PLUGIN	0x10000		/* 65536 */
-#define LDAP_DEBUG_TIMING	0x20000		/*131072 */
-#define LDAP_DEBUG_ACLSUMMARY	0x40000		/*262144 */
-#define LDAP_DEBUG_BACKLDBM		0x80000		/*524288 */
+#define LDAP_DEBUG_TRACE      0x000001  /*       1 */
+#define LDAP_DEBUG_PACKETS    0x000002  /*       2 */
+#define LDAP_DEBUG_ARGS       0x000004  /*       4 */
+#define LDAP_DEBUG_CONNS      0x000008  /*       8 */
+#define LDAP_DEBUG_BER        0x000010  /*      16 */
+#define LDAP_DEBUG_FILTER     0x000020  /*      32 */
+#define LDAP_DEBUG_CONFIG     0x000040  /*      64 */
+#define LDAP_DEBUG_ACL        0x000080  /*     128 */
+#define LDAP_DEBUG_STATS      0x000100  /*     256 */
+#define LDAP_DEBUG_STATS2     0x000200  /*     512 */
+#define LDAP_DEBUG_SHELL      0x000400  /*    1024 */
+#define LDAP_DEBUG_PARSE      0x000800  /*    2048 */
+#define LDAP_DEBUG_HOUSE      0x001000  /*    4096 */
+#define LDAP_DEBUG_REPL       0x002000  /*    8192 */
+#define LDAP_DEBUG_ANY        0x004000  /*   16384 */
+#define LDAP_DEBUG_CACHE      0x008000  /*   32768 */
+#define LDAP_DEBUG_PLUGIN     0x010000  /*   65536 */
+#define LDAP_DEBUG_TIMING     0x020000  /*  131072 */
+#define LDAP_DEBUG_ACLSUMMARY 0x040000  /*  262144 */
+#define LDAP_DEBUG_BACKLDBM   0x080000  /*  524288 */
+#define LDAP_DEBUG_NUNCSTANS  0x100000  /* 1048576 */
 
-#define LDAP_DEBUG_ALL_LEVELS	0xFFFFF
+#define LDAP_DEBUG_ALL_LEVELS	0xFFFFFF
 
 /* debugging stuff */
 /* Disable by default */
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 65a254b..e4ed0df 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -1232,6 +1232,27 @@ ns_enable_listeners()
 #endif
 }
 
+#ifdef ENABLE_NUNC_STANS
+/*
+ * Nunc stans logging function.
+ */
+static void
+nunc_stans_logging(int priority, const char *format, va_list varg)
+{
+	va_list varg_copy;
+	int severity = SLAPI_LOG_FATAL;
+
+	if (priority == LOG_DEBUG){
+		severity = SLAPI_LOG_NUNCSTANS;
+	} else if(priority == LOG_INFO){
+		severity = SLAPI_LOG_CONNS;
+	}
+	va_copy(varg_copy, varg);
+	slapi_log_error_ext(severity, "nunc-stans", (char *)format, varg, varg_copy);
+	va_end(varg_copy);
+}
+#endif
+
 void slapd_daemon( daemon_ports_t *ports )
 {
 	/* We are passed some ports---one for regular connections, one
@@ -1458,6 +1479,7 @@ void slapd_daemon( daemon_ports_t *ports )
 		tp_config.stacksize = 0;
 		tp_config.event_queue_size = config_get_maxdescriptors();
 		tp_config.work_queue_size = config_get_maxdescriptors();
+		tp_config.log_fct = nunc_stans_logging;
 
 		tp = ns_thrpool_new(&tp_config);
 		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 1014a03..f41e319 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -103,11 +103,12 @@ static int slapi_log_map[] = {
     LDAP_DEBUG_PLUGIN,		/* SLAPI_LOG_PLUGIN */
     LDAP_DEBUG_TIMING,		/* SLAPI_LOG_TIMING */
     LDAP_DEBUG_BACKLDBM,	/* SLAPI_LOG_BACKLDBM */
-    LDAP_DEBUG_ACLSUMMARY	/* SLAPI_LOG_ACLSUMMARY */
+    LDAP_DEBUG_ACLSUMMARY,	/* SLAPI_LOG_ACLSUMMARY */
+    LDAP_DEBUG_NUNCSTANS	/* SLAPI_LOG_NUNCSTANS */
 };
 
 #define SLAPI_LOG_MIN	SLAPI_LOG_FATAL		/* from slapi-plugin.h */
-#define SLAPI_LOG_MAX	SLAPI_LOG_ACLSUMMARY	/* from slapi-plugin.h */
+#define SLAPI_LOG_MAX	SLAPI_LOG_NUNCSTANS	/* from slapi-plugin.h */
 #define	TBUFSIZE 50				/* size for time buffers */
 #define SLAPI_LOG_BUFSIZ 2048			/* size for data buffers */
 /**************************************************************************
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index c420cce..f003af3 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6096,7 +6096,8 @@ int slapi_log_error_ext( int severity, char *subsystem, char *fmt, va_list varg1
 #define SLAPI_LOG_PLUGIN		14
 #define SLAPI_LOG_TIMING		15
 #define SLAPI_LOG_BACKLDBM		16
-#define SLAPI_LOG_ACLSUMMARY		17 /* ACLSUMMARY must be the last (log.c) */
+#define SLAPI_LOG_ACLSUMMARY		17
+#define SLAPI_LOG_NUNCSTANS		18 /* The last level must be set in log.c: SLAPI_LOG_MAX */
 
 int slapi_is_loglevel_set( const int loglevel );
 


commit 97aff2af96ab8d3563d7da2fac033340cee9052d
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Tue Feb 24 11:17:01 2015 -0500

    Ticket 48037 - ns_thrpool_new should take a config struct rather than many parameters
    
    Description:  Use a config struct for all the thread pool configuration
    
                  Also, fixed a shutdown crash when the the nunc-stans listener is disabled.
    
    https://fedorahosted.org/389/ticket/48037
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index d76c5bf..4f5c676 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -278,7 +278,7 @@ connection_cleanup(Connection *conn)
 
 	/* free the connection socket buffer */
 	connection_free_private_buffer(conn);
-	if (enable_listeners) {
+	if (enable_listeners && !g_get_shutdown()) {
 		ns_enable_listeners();
 	}
 #ifdef ENABLE_NUNC_STANS
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index b0b83b2..65a254b 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -1260,6 +1260,7 @@ void slapd_daemon( daemon_ports_t *ports )
 	int in_referral_mode = config_check_referral_mode();
 #ifdef ENABLE_NUNC_STANS
 	ns_thrpool_t *tp;
+	struct ns_thrpool_config tp_config;
 #endif
 	int connection_table_size = get_configured_connection_table_size();
 	the_connection_table= connection_table_new(connection_table_size);
@@ -1451,7 +1452,14 @@ void slapd_daemon( daemon_ports_t *ports )
 		if (getenv("MAX_THREADS")) {
 			maxthreads = atoi(getenv("MAX_THREADS"));
 		}
-		tp = ns_thrpool_new(maxthreads, maxthreads, 0, 1024);
+		/* Set the nunc-stans thread pool config */
+		tp_config.initial_threads = maxthreads;
+		tp_config.max_threads = maxthreads;
+		tp_config.stacksize = 0;
+		tp_config.event_queue_size = config_get_maxdescriptors();
+		tp_config.work_queue_size = config_get_maxdescriptors();
+
+		tp = ns_thrpool_new(&tp_config);
 		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
 		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
 		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);


commit c52b2d2b629ea6ae5c1dde3c8fafe49d935d80eb
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Mon Feb 23 17:52:15 2015 -0500

    Ticket 48040 - preserve the FD when disabling a listener
    
    Bug Description:  Stopping the server when the listener is disabled
                      crashes the serveri becuase we close the listener
                      FD twice.
    
    Fix Description:  When disabling a listener, pass the "preserve fd"
                      flag to ns_job_modify().  This prevents nunc-stans
                      from closing the FD out from underneath us.
    
    https://fedorahosted.org/389/ticket/48040
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 221b7bb..b0b83b2 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -1202,7 +1202,7 @@ static void
 ns_disable_listener(listener_info *listener)
 {
 	/* tell the event framework not to listen for new connections on this listener */
-	ns_job_modify(listener->ns_job, NS_JOB_DISABLE_ONLY);
+	ns_job_modify(listener->ns_job, NS_JOB_DISABLE_ONLY|NS_JOB_PRESERVE_FD);
 	/* add the listener to our list of disabled listeners */
 	PR_StackPush(ns_disabled_listeners, (PRStackElem *)listener);
 	PR_AtomicIncrement(&num_disabled_listeners);
@@ -3492,7 +3492,7 @@ ns_set_shutdown(struct ns_job_t *job)
 
 	/* Signal all the worker threads to stop */
 	ns_thrpool_shutdown(ns_job_get_tp(job));
-	ns_job_done(job)
+	ns_job_done(job);
 }
 #endif
 


commit fd15603a12392fa861892e47ff0532eac78e1c03
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Mon Feb 23 14:44:30 2015 -0500

    Ticket 48036 - ns_set_shutdown should call ns_job_done
    
    Description:  We should free the job that calls ns_set_shutdown()
    
    https://fedorahosted.org/389/ticket/48036
    
    Reviwed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index cfee61f..221b7bb 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -3492,6 +3492,7 @@ ns_set_shutdown(struct ns_job_t *job)
 
 	/* Signal all the worker threads to stop */
 	ns_thrpool_shutdown(ns_job_get_tp(job));
+	ns_job_done(job)
 }
 #endif
 


commit 9779283a3c6b77fc53bd4e0a70fad81e98f12510
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Mon Feb 23 14:23:06 2015 -0500

    Ticket 48035 - nunc-stans - Revise shutdown sequence
    
    Description:  When we notify nunc-stans to stop (ns_set_shutdown),
                  we should first stop the listeners to prevent new connections
                  from being accepted.  To do this we need to move the
                  listener counter and indexes to globals so we can easily
                  clean things up in ns_set_shutdown().
    
    https://fedorahosted.org/389/ticket/48035
    
    Reviewed by: rmeggins(Thanks!)

diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index d2fa687..cfee61f 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -144,6 +144,9 @@ typedef struct listener_info {
 #endif
 } listener_info;
 
+static int listeners = 0; /* number of listener sockets */
+static listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
+
 #define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
 
 static int get_configured_connection_table_size();
@@ -162,7 +165,7 @@ static void	set_shutdown (int);
 #ifdef ENABLE_NUNC_STANS
 static void	ns_set_shutdown (struct ns_job_t *job);
 #endif
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
 
 #ifdef HPUX10
 static void* catch_signals();
@@ -927,10 +930,10 @@ disk_monitoring_thread(void *nothing)
 }
 
 static void
-handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
+handle_listeners(Connection_Table *ct)
 {
 	int idx;
-	for (idx = 0; idx < n_listeners; ++idx) {
+	for (idx = 0; idx < listeners; ++idx) {
 		int fdidx = listener_idxs[idx].idx;
 		PRFileDesc *listenfd = listener_idxs[idx].listenfd;
 		int secure = listener_idxs[idx].secure;
@@ -1203,10 +1206,10 @@ ns_disable_listener(listener_info *listener)
 	/* add the listener to our list of disabled listeners */
 	PR_StackPush(ns_disabled_listeners, (PRStackElem *)listener);
 	PR_AtomicIncrement(&num_disabled_listeners);
-        LDAPDebug2Args(LDAP_DEBUG_ANY, "ns_disable_listener: "
-        	       "disabling listener for fd [%d]: [%d] now disabled\n",
-        	       PR_FileDesc2NativeHandle(listener->listenfd),
-        	       num_disabled_listeners);
+	LDAPDebug2Args(LDAP_DEBUG_ANY, "ns_disable_listener: "
+	               "disabling listener for fd [%d]: [%d] now disabled\n",
+	               PR_FileDesc2NativeHandle(listener->listenfd),
+	               num_disabled_listeners);
 }
 #endif
 
@@ -1224,7 +1227,7 @@ ns_enable_listeners()
 	}
 	if (num_enabled) {
 		LDAPDebug1Arg(LDAP_DEBUG_ANY, "ns_enable_listeners: "
-			      "enabled [%d] listeners\n", num_enabled);
+		              "enabled [%d] listeners\n", num_enabled);
 	}
 #endif
 }
@@ -1255,8 +1258,6 @@ void slapd_daemon( daemon_ports_t *ports )
 	PRThread *time_thread_p;
 	int threads;
 	int in_referral_mode = config_check_referral_mode();
-	int n_listeners = 0; /* number of listener sockets */
-	listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
 #ifdef ENABLE_NUNC_STANS
 	ns_thrpool_t *tp;
 #endif
@@ -1372,7 +1373,7 @@ void slapd_daemon( daemon_ports_t *ports )
 			netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
 			ports->n_port, oserr, slapd_system_strerror( oserr ) );
 		g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
-		n_listeners++;
+		listeners++;
 	}
 #else
 	if ( n_tcps != NULL ) {
@@ -1390,7 +1391,7 @@ void slapd_daemon( daemon_ports_t *ports )
 					slapd_pr_strerror( prerr ));
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
 			}
-			n_listeners++;
+			listeners++;
 		}
 	}
 #endif
@@ -1410,7 +1411,7 @@ void slapd_daemon( daemon_ports_t *ports )
 					slapd_pr_strerror( prerr ));
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
 			}
-			n_listeners++;
+			listeners++;
 		}
 	}
 
@@ -1429,12 +1430,12 @@ void slapd_daemon( daemon_ports_t *ports )
 					slapd_pr_strerror( prerr ));
 				g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
 			}
-			n_listeners++;
+			listeners++;
 		}
 	}
 #endif /* ENABLE_LDAPI */
 #endif
-	listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
+	listener_idxs = (listener_info *)slapi_ch_calloc(listeners, sizeof(*listener_idxs));
 #ifdef ENABLE_NUNC_STANS
 	ns_disabled_listeners = PR_CreateStack("disabled_listeners");
 #endif
@@ -1454,8 +1455,8 @@ void slapd_daemon( daemon_ports_t *ports )
 		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
 		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
 		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
-		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
-		for (ii = 0; ii < n_listeners; ++ii) {
+		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
+		for (ii = 0; ii < listeners; ++ii) {
 			listener_idxs[ii].ct = the_connection_table; /* to pass to handle_new_connection */
 			ns_add_io_job(tp, listener_idxs[ii].listenfd, ns_listen_job_flags,
 				      ns_handle_new_connection, &listener_idxs[ii], &listener_idxs[ii].ns_job);
@@ -1492,7 +1493,7 @@ void slapd_daemon( daemon_ports_t *ports )
 		/* This select needs to timeout to give the server a chance to test for shutdown */
 		select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
 #else
-		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
+		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
 		select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
 #endif
 		switch (select_return) {
@@ -1528,7 +1529,7 @@ void slapd_daemon( daemon_ports_t *ports )
 			clear_signal(&readfds);
 #else
 			/* handle new connections from the listeners */
-			handle_listeners(the_connection_table, listener_idxs, n_listeners);
+			handle_listeners(the_connection_table);
 			/* handle new data ready */
 			handle_pr_read_ready(the_connection_table, connection_table_size);
 			clear_signal(the_connection_table->fd);
@@ -1554,14 +1555,9 @@ void slapd_daemon( daemon_ports_t *ports )
  		PR_Close( s_tcps );
 	}
 #else
-	/* shutdown the listeners - no more client ops */
-#ifdef ENABLE_NUNC_STANS
-	int ii;
-	for (ii = 0; ii < n_listeners; ++ii) {
-		ns_job_done(listener_idxs[ii].ns_job);
-	}
-#endif
+	/* free the listener indexes */
 	slapi_ch_free((void **)&listener_idxs);
+
 	for (fdesp = n_tcps; fdesp && *fdesp; fdesp++) {
 		PR_Close( *fdesp );
 	}
@@ -1667,7 +1663,7 @@ void slapd_daemon( daemon_ports_t *ports )
 		uniqueIDGenCleanup ();   
 	}
 
-	plugin_closeall( 1 /* Close Backends */, 1 /* Close Gloabls */); 
+	plugin_closeall( 1 /* Close Backends */, 1 /* Close Globals */);
 
 	if ( ! in_referral_mode ) {
 		/* Close SNMP collator after the plugins closed... 
@@ -1872,7 +1868,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
 static int first_time_setup_pr_read_pds = 1;
 static int listen_addr_count = 0;
 static void
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners)
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
 {
 	Connection *c= NULL;
 	Connection *next= NULL;
@@ -1998,7 +1994,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
 		first_time_setup_pr_read_pds = 0;
 		listen_addr_count = count;
 
-		if (n_listeners < max_listeners) {
+		if (n_listeners < listeners) {
 			listener_idxs[n_listeners].idx = 0;
 			listener_idxs[n_listeners].listenfd = NULL;
 		}
@@ -3484,7 +3480,17 @@ set_shutdown (int sig)
 static void
 ns_set_shutdown(struct ns_job_t *job)
 {
+	int i;
+
 	set_shutdown(0);
+
+	/* Stop all the long running jobs */
+	for (i = 0; i < listeners; ++i) {
+		ns_job_done(listener_idxs[i].ns_job);
+		listener_idxs[i].ns_job = NULL;
+	}
+
+	/* Signal all the worker threads to stop */
 	ns_thrpool_shutdown(ns_job_get_tp(job));
 }
 #endif


commit ffb41430ebe82fc5ad016dac254ef40026ddc65d
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Wed Jan 28 20:44:52 2015 -0700

    support nunc-stans for basic accept and read events
    
    NOTE: shutdown is not working.  You will have to kill -9 ns-slapd
    in order to shut it down.
    To build:
    First, checkout and build liblfds.
    Next, checkout and build nunc-stans.
    Next, checkout a branch of 389 and apply this patch.
    Next, configure ds with the following arguments:
    --enable-nunc-stans --with-lfds=/path/to/liblfds --with-nunc-stans=/path/to/nunc-stans
    Make and install ds.
    Edit the ds etc/sysconfig/dirsrv - add export LD_LIBRARY_PATH=/path/to/liblfds/bin:/path/to/nunc-stans
    Run setup-ds
    Edit etc/sysconfig/dirsrv-instance - add export LD_LIBRARY_PATH=/path/to/liblfds/bin:/path/to/nunc-stans
    might be ~/.dirsrv/dirsrv-instance instead

diff --git a/Makefile.am b/Makefile.am
index 0d383c2..4ecdaf1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,7 +14,12 @@ DEBUG_DEFINES = @debug_defs@
 # the -U undefines these symbols - should use the corresponding DS_ ones instead - see configure.ac
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
-DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I.
+if enable_nunc_stans
+NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
+NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+endif
+DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
+
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # values prior to their being defined.  Defining them here ensures that they are properly
@@ -793,8 +798,7 @@ libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @ker
 if SPARC
 libslapd_la_SOURCES += ldap/servers/slapd/slapi_counter_sunos_sparcv9.S
 endif
-
-libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
+libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NUNC_STANS_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
 
 
 #////////////////////////////////////////////////////////////////
diff --git a/Makefile.in b/Makefile.in
index f1e36d1..06e6511 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -108,7 +108,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/sasl.m4 $(top_srcdir)/m4/svrcore.m4 \
 	$(top_srcdir)/m4/icu.m4 $(top_srcdir)/m4/netsnmp.m4 \
 	$(top_srcdir)/m4/kerberos.m4 $(top_srcdir)/m4/pcre.m4 \
-	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/selinux.m4 $(top_srcdir)/m4/lfds.m4 \
+	$(top_srcdir)/m4/nunc-stans.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -705,11 +706,14 @@ libschemareload_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(libschemareload_plugin_la_LDFLAGS) \
 	$(LDFLAGS) -o $@
-am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+ at enable_nunc_stans_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \
+ at enable_nunc_stans_TRUE@	$(am__DEPENDENCIES_1)
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
 libslapd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
 am__libslapd_la_SOURCES_DIST = ldap/servers/slapd/add.c \
 	ldap/servers/slapd/agtmmap.c ldap/servers/slapd/apibroker.c \
 	ldap/servers/slapd/attr.c ldap/servers/slapd/attrlist.c \
@@ -951,8 +955,8 @@ am_ldap_agent_bin_OBJECTS =  \
 	ldap/servers/snmp/ldap_agent_bin-ldap-agent.$(OBJEXT) \
 	ldap/servers/slapd/ldap_agent_bin-agtmmap.$(OBJEXT)
 ldap_agent_bin_OBJECTS = $(am_ldap_agent_bin_OBJECTS)
- at OPENLDAP_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
-ldap_agent_bin_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ at OPENLDAP_FALSE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+ldap_agent_bin_DEPENDENCIES = $(am__DEPENDENCIES_4) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -993,7 +997,7 @@ am_ldif_bin_OBJECTS =  \
 	ldap/servers/slapd/tools/ldif_bin-ldif.$(OBJEXT)
 ldif_bin_OBJECTS = $(am_ldif_bin_OBJECTS)
 ldif_bin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
 am_makstrdb_OBJECTS = lib/libsi18n/makstrdb-makstrdb.$(OBJEXT)
 makstrdb_OBJECTS = $(am_makstrdb_OBJECTS)
 makstrdb_LDADD = $(LDADD)
@@ -1007,7 +1011,7 @@ am_mmldif_bin_OBJECTS =  \
 mmldif_bin_OBJECTS = $(am_mmldif_bin_OBJECTS)
 mmldif_bin_DEPENDENCIES = libslapd.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
 am__ns_slapd_SOURCES_DIST = ldap/servers/slapd/abandon.c \
 	ldap/servers/slapd/auth.c ldap/servers/slapd/bind.c \
 	ldap/servers/slapd/compare.c ldap/servers/slapd/config.c \
@@ -1419,6 +1423,9 @@ ldapsdk_lib = @ldapsdk_lib@
 ldapsdk_libdir = @ldapsdk_libdir@
 ldaptool_bindir = @ldaptool_bindir@
 ldaptool_opts = @ldaptool_opts@
+lfds_inc = @lfds_inc@
+lfds_lib = @lfds_lib@
+lfds_libdir = @lfds_libdir@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -1437,6 +1444,9 @@ nspr_libdir = @nspr_libdir@
 nss_inc = @nss_inc@
 nss_lib = @nss_lib@
 nss_libdir = @nss_libdir@
+nunc_stans_inc = @nunc_stans_inc@
+nunc_stans_lib = @nunc_stans_lib@
+nunc_stans_libdir = @nunc_stans_libdir@
 ol_libver = @ol_libver@
 oldincludedir = @oldincludedir@
 openldap_bindir = @openldap_bindir@
@@ -1502,7 +1512,10 @@ DEBUG_DEFINES = @debug_defs@
 DS_DEFINES = -DBUILD_NUM=$(BUILDNUM) -DVENDOR="\"$(vendor)\"" -DBRAND="\"$(brand)\"" -DCAPBRAND="\"$(capbrand)\"" \
 	-UPACKAGE_VERSION -UPACKAGE_TARNAME -UPACKAGE_STRING -UPACKAGE_BUGREPORT
 
-DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I.
+ at enable_nunc_stans_TRUE@NUNC_STANS_INCLUDES = $(nunc_stans_inc) $(lfds_inc)
+ at enable_nunc_stans_TRUE@NUNC_STANS_LINK = $(nunc_stans_lib) -lnunc-stans $(lfds_lib) -llfds
+DS_INCLUDES = -I$(srcdir)/ldap/include -I$(srcdir)/ldap/servers/slapd -I$(srcdir)/include -I. $(NUNC_STANS_INCLUDES)
+
 # these paths are dependent on the settings of prefix and exec_prefix which may be specified
 # at make time.  So we cannot use AC_DEFINE in the configure.ac because that would set the
 # values prior to their being defined.  Defining them here ensures that they are properly
@@ -2146,7 +2159,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \
 	ldap/servers/slapd/value.c ldap/servers/slapd/valueset.c \
 	ldap/servers/slapd/vattr.c $(libavl_a_SOURCES) $(am__append_1)
 libslapd_la_CPPFLAGS = $(PLUGIN_CPPFLAGS) @sasl_inc@ @db_inc@ @svrcore_inc@ @kerberos_inc@ @pcre_inc@
-libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
+libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NUNC_STANS_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB)
 
 #////////////////////////////////////////////////////////////////
 #
diff --git a/config.h.in b/config.h.in
index 52379ea..762cbf7 100644
--- a/config.h.in
+++ b/config.h.in
@@ -54,6 +54,9 @@
 /* enable ldapi support in the server */
 #undef ENABLE_LDAPI
 
+/* enable support for nunc-stans event framework */
+#undef ENABLE_NUNC_STANS
+
 /* enable the pam passthru auth plugin */
 #undef ENABLE_PAM_PASSTHRU
 
diff --git a/configure b/configure
index a6b5689..ec30ecd 100755
--- a/configure
+++ b/configure
@@ -640,6 +640,12 @@ vendor
 capbrand
 brand
 localrundir
+nunc_stans_libdir
+nunc_stans_lib
+nunc_stans_inc
+lfds_libdir
+lfds_lib
+lfds_inc
 pcre_libdir
 pcre_lib
 pcre_inc
@@ -738,6 +744,8 @@ PKG_CONFIG_PATH
 PKG_CONFIG
 with_tmpfiles_d
 with_fhs_opt
+enable_nunc_stans_FALSE
+enable_nunc_stans_TRUE
 enable_posix_winsync_FALSE
 enable_posix_winsync_TRUE
 enable_acctpolicy_FALSE
@@ -911,6 +919,7 @@ enable_bitwise
 enable_presence
 enable_acctpolicy
 enable_posix_winsync
+enable_nunc_stans
 with_fhs
 with_fhs_opt
 with_tmpfiles_d
@@ -956,6 +965,12 @@ with_kerberos_inc
 with_kerberos_lib
 with_pcre
 with_selinux
+with_lfds
+with_lfds_inc
+with_lfds_lib
+with_nunc_stans
+with_nunc_stans_inc
+with_nunc_stans_lib
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1625,6 +1640,8 @@ Optional Features:
   --enable-acctpolicy     enable the account policy plugin (default: yes)
   --enable-posix-winsync  enable support for POSIX user/group attributes in
                           winsync (default: yes)
+  --enable-nunc-stans     enable support for nunc-stans event framework
+                          (default: no)
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1717,6 +1734,15 @@ Optional Packages:
                           kerberos
   --with-pcre[=PATH]      Perl Compatible Regular Expression directory
   --with-selinux          Support SELinux policy
+  --with-lfds[=PATH]      LFDS directory
+  --with-lfds-inc=PATH    LFDS include file directory
+  --with-lfds-lib=PATH    LFDS library directory
+  --with-nunc-stans[=PATH]
+                          nunc-stans directory
+  --with-nunc-stans-inc=PATH
+                          nunc-stans include file directory
+  --with-nunc-stans-lib=PATH
+                          nunc-stans library directory
 
 Some influential environment variables:
   CXX         C++ compiler command
@@ -17887,6 +17913,32 @@ else
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-nunc-stans" >&5
+$as_echo_n "checking for --enable-nunc-stans... " >&6; }
+# Check whether --enable-nunc_stans was given.
+if test "${enable_nunc_stans+set}" = set; then :
+  enableval=$enable_nunc_stans;
+fi
+
+if test "$enable_nunc_stans" = yes ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define ENABLE_NUNC_STANS 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+ if test "$enable_nunc_stans" = "yes"; then
+  enable_nunc_stans_TRUE=
+  enable_nunc_stans_FALSE='#'
+else
+  enable_nunc_stans_TRUE='#'
+  enable_nunc_stans_FALSE=
+fi
+
+
 # the default prefix - override with --prefix or --with-fhs
 
 
@@ -21241,6 +21293,214 @@ $as_echo "no" >&6; }
 fi
 
 
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lfds..." >&5
+$as_echo "$as_me: checking for lfds..." >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds" >&5
+$as_echo_n "checking for --with-lfds... " >&6; }
+
+# Check whether --with-lfds was given.
+if test "${with_lfds+set}" = set; then :
+  withval=$with_lfds;
+  if test "$withval" = "yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  elif test "$withval" = "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  elif test -d "$withval"/inc -a -d "$withval"/bin; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+        lfds_lib="-L$withval/bin"
+    lfds_libdir="$withval/lib"
+    lfds_incdir="$withval/inc"
+    if ! test -e "$lfds_incdir/liblfds.h" ; then
+      as_fn_error $? "$withval include dir not found" "$LINENO" 5
+    fi
+    lfds_inc="-I$lfds_incdir"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-lfds-inc
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-inc" >&5
+$as_echo_n "checking for --with-lfds-inc... " >&6; }
+
+# Check whether --with-lfds-inc was given.
+if test "${with_lfds_inc+set}" = set; then :
+  withval=$with_lfds_inc;
+  if test -e "$withval"/liblfds.h
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    lfds_incdir="$withval"
+    lfds_inc="-I$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-lfds-lib
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lfds-lib" >&5
+$as_echo_n "checking for --with-lfds-lib... " >&6; }
+
+# Check whether --with-lfds-lib was given.
+if test "${with_lfds_lib+set}" = set; then :
+  withval=$with_lfds_lib;
+  if test -d "$withval"
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    lfds_lib="-L$withval"
+    lfds_libdir="$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nunc-stans..." >&5
+$as_echo "$as_me: checking for nunc-stans..." >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans" >&5
+$as_echo_n "checking for --with-nunc-stans... " >&6; }
+
+# Check whether --with-nunc-stans was given.
+if test "${with_nunc_stans+set}" = set; then :
+  withval=$with_nunc_stans;
+  if test "$withval" = "yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  elif test "$withval" = "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  elif test -d "$withval"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+        nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+    nunc_stans_incdir="$withval"
+    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+      as_fn_error $? "$withval include dir not found" "$LINENO" 5
+    fi
+    nunc_stans_inc="-I$nunc_stans_incdir"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-nunc-stans-inc
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans-inc" >&5
+$as_echo_n "checking for --with-nunc-stans-inc... " >&6; }
+
+# Check whether --with-nunc-stans-inc was given.
+if test "${with_nunc_stans_inc+set}" = set; then :
+  withval=$with_nunc_stans_inc;
+  if test -e "$withval"/ns_thrpool.h
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    nunc_stans_incdir="$withval"
+    nunc_stans_inc="-I$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# check for --with-nunc-stans-lib
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-nunc-stans-lib" >&5
+$as_echo_n "checking for --with-nunc-stans-lib... " >&6; }
+
+# Check whether --with-nunc-stans-lib was given.
+if test "${with_nunc_stans_lib+set}" = set; then :
+  withval=$with_nunc_stans_lib;
+  if test -d "$withval"
+  then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $withval" >&5
+$as_echo "using $withval" >&6; }
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+  else
+    echo
+    as_fn_error $? "$withval not found" "$LINENO" 5
+  fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 
@@ -21332,6 +21592,12 @@ fi
 
 
 
+
+
+
+
+
+
 # AC_DEFINE([USE_OLD_UNHASHED], [], [Use old unhashed code])
 
 $as_echo "#define LDAP_DEBUG 1" >>confdefs.h
@@ -21550,6 +21816,10 @@ if test -z "${enable_posix_winsync_TRUE}" && test -z "${enable_posix_winsync_FAL
   as_fn_error $? "conditional \"enable_posix_winsync\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${enable_nunc_stans_TRUE}" && test -z "${enable_nunc_stans_FALSE}"; then
+  as_fn_error $? "conditional \"enable_nunc_stans\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${WINNT_TRUE}" && test -z "${WINNT_FALSE}"; then
   as_fn_error $? "conditional \"WINNT\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/configure.ac b/configure.ac
index 16ab6a9..96a7179 100644
--- a/configure.ac
+++ b/configure.ac
@@ -226,6 +226,18 @@ else
 fi
 AM_CONDITIONAL(enable_posix_winsync,test "$enable_posix_winsync" = "yes")
 
+AC_MSG_CHECKING(for --enable-nunc-stans)
+AC_ARG_ENABLE(nunc_stans,
+        AS_HELP_STRING([--enable-nunc-stans],
+                       [enable support for nunc-stans event framework (default: no)]))
+if test "$enable_nunc_stans" = yes ; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE([ENABLE_NUNC_STANS], [1], [enable support for nunc-stans event framework])
+else
+  AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(enable_nunc_stans,test "$enable_nunc_stans" = "yes")
+
 # the default prefix - override with --prefix or --with-fhs
 AC_PREFIX_DEFAULT([/opt/$PACKAGE_NAME])
 
@@ -678,6 +690,8 @@ m4_include(m4/netsnmp.m4)
 m4_include(m4/kerberos.m4)
 m4_include(m4/pcre.m4)
 m4_include(m4/selinux.m4)
+m4_include(m4/lfds.m4)
+m4_include(m4/nunc-stans.m4)
 
 PACKAGE_BASE_VERSION=`echo $PACKAGE_VERSION | awk -F\. '{print $1"."$2}'`
 AC_SUBST(PACKAGE_BASE_VERSION)
@@ -735,6 +749,12 @@ AC_SUBST(netsnmp_link)
 AC_SUBST(pcre_inc)
 AC_SUBST(pcre_lib)
 AC_SUBST(pcre_libdir)
+AC_SUBST(lfds_inc)
+AC_SUBST(lfds_lib)
+AC_SUBST(lfds_libdir)
+AC_SUBST(nunc_stans_inc)
+AC_SUBST(nunc_stans_lib)
+AC_SUBST(nunc_stans_libdir)
 AC_SUBST(localrundir)
 
 AC_SUBST(brand)
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index 9f0d9dc..d76c5bf 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -199,6 +199,8 @@ connection_done(Connection *conn)
 void
 connection_cleanup(Connection *conn)
 {
+	int enable_listeners = 0;
+
 	bind_credentials_clear( conn, PR_FALSE /* do not lock conn */,
 							PR_TRUE /* clear external creds. */ );
 	slapi_ch_free((void**)&conn->c_authtype);
@@ -232,6 +234,7 @@ connection_cleanup(Connection *conn)
 	if (conn->c_prfd)
 	{
 		PR_Close(conn->c_prfd);
+		enable_listeners = 1; /* re-enable listeners disabled due to no fds */
 	}
 #endif
 
@@ -275,6 +278,12 @@ connection_cleanup(Connection *conn)
 
 	/* free the connection socket buffer */
 	connection_free_private_buffer(conn);
+	if (enable_listeners) {
+		ns_enable_listeners();
+	}
+#ifdef ENABLE_NUNC_STANS
+	conn->c_ns_close_jobs = 0;
+#endif
 }
 
 /*
@@ -741,10 +750,10 @@ int connection_release_nolock (Connection *conn)
 }
 
 /* this function should be called under c_mutex */
-int connection_acquire_nolock (Connection *conn)
+int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing)
 {
     /* connection in the closing state can't be acquired */
-    if (conn->c_flags & CONN_FLAG_CLOSING)
+    if (!allow_when_closing && (conn->c_flags & CONN_FLAG_CLOSING))
     {
 	/* This may happen while other threads are still working on this connection */
         slapi_log_error(SLAPI_LOG_FATAL, "connection",
@@ -759,6 +768,10 @@ int connection_acquire_nolock (Connection *conn)
     }
 }
 
+int connection_acquire_nolock (Connection *conn) {
+	return connection_acquire_nolock_ext(conn, 0);
+}
+
 /* returns non-0 if connection can be reused and 0 otherwise */
 int connection_is_free (Connection *conn)
 {
@@ -2169,6 +2182,9 @@ void connection_make_readable(Connection *conn)
 void connection_make_readable_nolock(Connection *conn)
 {
 	conn->c_gettingber = 0;
+	LDAPDebug2Args(LDAP_DEBUG_CONNS, "making readable conn %" NSPRIu64 " fd=%d\n",
+		       conn->c_connid, conn->c_sd);
+	ns_connection_post_io_or_closing(conn);
 }
 
 /*
@@ -3000,6 +3016,8 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
     if ( ( conn->c_sd != SLAPD_INVALID_SOCKET &&
 	    conn->c_connid == opconnid ) && !(conn->c_flags & CONN_FLAG_CLOSING) )
 	{
+		LDAPDebug(LDAP_DEBUG_CONNS, "setting conn %" NSPRIu64 " fd=%d "
+			  "to be disconnected: reason %d\n", conn->c_connid, conn->c_sd, reason);
 		/*
 		 * PR_Close must be called before anything else is done because
 		 * of NSPR problem on NT which requires that the socket on which
@@ -3070,6 +3088,14 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
 				}
 			}
 		}
+		ns_connection_post_io_or_closing(conn); /* make sure event loop wakes up and closes this conn */
+
+    } else {
+	    LDAPDebug2Args(LDAP_DEBUG_CONNS, "not setting conn %d to be disconnected: %s\n",
+			   conn->c_sd,
+			   (conn->c_sd == SLAPD_INVALID_SOCKET) ? "socket is invalid" :
+			    ((conn->c_connid != opconnid) ? "conn id does not match op conn id" :
+			     ((conn->c_flags & CONN_FLAG_CLOSING) ? "conn is closing" : "unknown")));
     }
 }
 
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index 5225e11..3726bd6 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -211,6 +211,9 @@ connection_table_get_connection(Connection_Table *ct, int sd)
 		 * far then `c' is not being used by any operation threads, etc.
 		 */
 		connection_cleanup(c);
+#ifdef ENABLE_NUNC_STANS
+		c->c_ct = ct; /* pointer to connection table that owns this connection */
+#endif
     }
     else
     {
@@ -289,9 +292,10 @@ connection_table_dump_active_connections (Connection_Table *ct)
  * list. This list is used to find the connections that should be used in the
  * poll call. 
  */
-void
+int
 connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c)
 {
+    int c_sd; /* for logging */
     /* we always have previous element because list contains a dummy header */;
     PR_ASSERT (c->c_prev);
 
@@ -300,11 +304,17 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connect
     connection_table_dump_active_connection (c);
 #endif
 
+    c_sd = c->c_sd;
     /*
      * Note: the connection will NOT be moved off the active list if any other threads still hold
      * a reference to the connection (that is, its reference count must be 1 or less).
      */
-    if(c->c_refcnt > 1) return;
+    if(c->c_refcnt > 1) {
+	    LDAPDebug2Args(LDAP_DEBUG_CONNS,
+		           "not moving conn %d out of active list because refcnt is %d\n",
+		           c_sd, c->c_refcnt);
+	    return 1; /* failed */
+    }
 	
     /* We need to lock here because we're modifying the linked list */
     PR_Lock(ct->table_mutex);
@@ -321,10 +331,13 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connect
     connection_cleanup (c);
 
     PR_Unlock(ct->table_mutex);
+
+    LDAPDebug1Arg(LDAP_DEBUG_CONNS, "moved conn %d out of active list and freed\n", c_sd);
 	
 #ifdef FOR_DEBUGGING
     connection_table_dump_active_connections (ct);
 #endif
+    return 0; /* success */
 }
 
 /*
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 1230abc..d2fa687 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -131,10 +131,17 @@ void disk_monitoring_stop();
 #define FDS_SIGNAL_PIPE 0
 
 typedef struct listener_info {
+#ifdef ENABLE_NUNC_STANS
+	PRStackElem stackelem; /* must be first in struct for PRStack to work */
+#endif
 	int idx; /* index of this listener in the ct->fd array */
 	PRFileDesc *listenfd; /* the listener fd */
 	int secure;
 	int local;
+#ifdef ENABLE_NUNC_STANS
+	Connection_Table *ct; /* for listen job callback */
+	struct ns_job_t *ns_job; /* the ns accept job */
+#endif
 } listener_info;
 
 #define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
@@ -152,6 +159,9 @@ static PRFileDesc **createprlistensockets(unsigned short port,
 static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
 	size_t addrbuflen);
 static void	set_shutdown (int);
+#ifdef ENABLE_NUNC_STANS
+static void	ns_set_shutdown (struct ns_job_t *job);
+#endif
 static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
 
 #ifdef HPUX10
@@ -376,7 +386,10 @@ static void set_timeval_ms(struct timeval *t, int ms);
 #endif
 /* GGOODREPL static void handle_timeout( void ); */
 static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
-static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local );
+static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn );
+#ifdef ENABLE_NUNC_STANS
+static void ns_handle_new_connection(struct ns_job_t *job);
+#endif
 #ifdef _WIN32
 static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
 #else
@@ -925,7 +938,7 @@ handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_liste
 		if (fdidx && listenfd) {
 			if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
 				/* accept() the new connection, put it on the active list for handle_pr_read_ready */
-				int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+				int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local, NULL);
 				if (rc) {
 					LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
 					              PR_FileDesc2NativeHandle(listenfd));
@@ -1175,6 +1188,47 @@ done:
     }
 }
 
+#ifdef ENABLE_NUNC_STANS
+static ns_job_type_t ns_listen_job_flags = NS_JOB_ACCEPT|NS_JOB_PERSIST|NS_JOB_PRESERVE_FD;
+static PRStack *ns_disabled_listeners; /* holds the disabled listeners, if any */
+static PRInt32 num_disabled_listeners;
+#endif
+
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_disable_listener(listener_info *listener)
+{
+	/* tell the event framework not to listen for new connections on this listener */
+	ns_job_modify(listener->ns_job, NS_JOB_DISABLE_ONLY);
+	/* add the listener to our list of disabled listeners */
+	PR_StackPush(ns_disabled_listeners, (PRStackElem *)listener);
+	PR_AtomicIncrement(&num_disabled_listeners);
+        LDAPDebug2Args(LDAP_DEBUG_ANY, "ns_disable_listener: "
+        	       "disabling listener for fd [%d]: [%d] now disabled\n",
+        	       PR_FileDesc2NativeHandle(listener->listenfd),
+        	       num_disabled_listeners);
+}
+#endif
+
+void
+ns_enable_listeners()
+{
+#ifdef ENABLE_NUNC_STANS
+	int num_enabled = 0;
+	listener_info *listener;
+	while ((listener = (listener_info *)PR_StackPop(ns_disabled_listeners))) {
+		/* there was a disabled listener - re-enable it to listen for new connections */
+		ns_job_modify(listener->ns_job, ns_listen_job_flags);
+		PR_AtomicDecrement(&num_disabled_listeners);
+		num_enabled++;
+	}
+	if (num_enabled) {
+		LDAPDebug1Arg(LDAP_DEBUG_ANY, "ns_enable_listeners: "
+			      "enabled [%d] listeners\n", num_enabled);
+	}
+#endif
+}
+
 void slapd_daemon( daemon_ports_t *ports )
 {
 	/* We are passed some ports---one for regular connections, one
@@ -1203,7 +1257,9 @@ void slapd_daemon( daemon_ports_t *ports )
 	int in_referral_mode = config_check_referral_mode();
 	int n_listeners = 0; /* number of listener sockets */
 	listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
-
+#ifdef ENABLE_NUNC_STANS
+	ns_thrpool_t *tp;
+#endif
 	int connection_table_size = get_configured_connection_table_size();
 	the_connection_table= connection_table_new(connection_table_size);
 
@@ -1379,20 +1435,46 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif /* ENABLE_LDAPI */
 #endif
 	listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
+#ifdef ENABLE_NUNC_STANS
+	ns_disabled_listeners = PR_CreateStack("disabled_listeners");
+#endif
+	/*
+	 * Convert old DES encoded passwords to AES
+	 */
+	convert_pbe_des_to_aes();
+
+#ifdef ENABLE_NUNC_STANS
+	if (!g_get_shutdown()) {
+		int ii;
+		PRInt32 maxthreads = 3;
+		if (getenv("MAX_THREADS")) {
+			maxthreads = atoi(getenv("MAX_THREADS"));
+		}
+		tp = ns_thrpool_new(maxthreads, maxthreads, 0, 1024);
+		ns_add_signal_job(tp, SIGINT, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		ns_add_signal_job(tp, SIGTERM, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		ns_add_signal_job(tp, SIGHUP, NS_JOB_SIGNAL, ns_set_shutdown, NULL, NULL);
+		setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
+		for (ii = 0; ii < n_listeners; ++ii) {
+			listener_idxs[ii].ct = the_connection_table; /* to pass to handle_new_connection */
+			ns_add_io_job(tp, listener_idxs[ii].listenfd, ns_listen_job_flags,
+				      ns_handle_new_connection, &listener_idxs[ii], &listener_idxs[ii].ns_job);
+
+		}
+	}
+#endif
 	/* Now we write the pid file, indicating that the server is finally and listening for connections */
 	write_pid_file();
 
 	/* The server is ready and listening for connections. Logging "slapd started" message. */
 	unfurl_banners(the_connection_table,ports,n_tcps,s_tcps,i_unix);
 
-	/*
-	 * Convert old DES encoded passwords to AES
-	 */
-	convert_pbe_des_to_aes();
-
 	/* The meat of the operation is in a loop on a call to select */
 	while(!g_get_shutdown())
 	{
+#ifdef ENABLE_NUNC_STANS
+		DS_Sleep(1);
+#else
 #ifdef _WIN32
 		fd_set			readfds;
 		struct timeval	wakeup_timer;
@@ -1420,28 +1502,27 @@ void slapd_daemon( daemon_ports_t *ports )
 		case -1: /* Error */
 #ifdef _WIN32
 			oserr = errno;
-
 			LDAPDebug( LDAP_DEBUG_TRACE,
-			    "select failed errno %d (%s)\n", oserr,
-			    slapd_system_strerror(oserr), 0 );
+				   "select failed errno %d (%s)\n", oserr,
+				   slapd_system_strerror(oserr), 0 );
 #else
 			prerr = PR_GetError();
 			LDAPDebug( LDAP_DEBUG_TRACE, "PR_Poll() failed, "
-					SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
-					prerr, slapd_system_strerror(prerr), 0 );
+				   SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+				   prerr, slapd_system_strerror(prerr), 0 );
 #endif
 			break;
 		default: /* either a new connection or some new data ready */
 			/* Figure out if we are dealing with one of the listen sockets */
 #ifdef _WIN32
 			/* If so, then handle a new connection */
-			if ( n_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( n_tcps,&readfds ) ) {
+			if ( n_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( n_tcps, &readfds ) ) {
 				handle_new_connection(the_connection_table,n_tcps,NULL,0,0);
-			} 
+			}
 			/* If so, then handle a new connection */
 			if ( s_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( s_tcps_native,&readfds ) ) {
 				handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,s_tcps,1,0);
-			} 
+			}
 			/* handle new data ready */
 			handle_read_ready(the_connection_table,&readfds);
 			clear_signal(&readfds);
@@ -1454,9 +1535,8 @@ void slapd_daemon( daemon_ports_t *ports )
 #endif
 			break;
 		}
-
+#endif
 	}
-	slapi_ch_free((void **)&listener_idxs);
 	/* We get here when the server is shutting down */
 	/* Do what we have to do before death */
 
@@ -1474,6 +1554,14 @@ void slapd_daemon( daemon_ports_t *ports )
  		PR_Close( s_tcps );
 	}
 #else
+	/* shutdown the listeners - no more client ops */
+#ifdef ENABLE_NUNC_STANS
+	int ii;
+	for (ii = 0; ii < n_listeners; ++ii) {
+		ns_job_done(listener_idxs[ii].ns_job);
+	}
+#endif
+	slapi_ch_free((void **)&listener_idxs);
 	for (fdesp = n_tcps; fdesp && *fdesp; fdesp++) {
 		PR_Close( *fdesp );
 	}
@@ -1598,7 +1686,13 @@ void slapd_daemon( daemon_ports_t *ports )
 	 */
 	connection_table_free(the_connection_table);
 	the_connection_table= NULL;
+#ifdef ENABLE_NUNC_STANS
+	if (ns_thrpool_wait(tp)) {
+		/* error */
+	}
 
+	ns_thrpool_destroy(tp);
+#endif
 	be_cleanupall ();
 	connection_post_shutdown_cleanup();
 	LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
@@ -2248,6 +2342,146 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
 #endif
 }
 
+#ifdef ENABLE_NUNC_STANS
+/* This function is called when the connection has been marked
+ * as closing and needs to be cleaned up.  It will keep trying
+ * and re-arming itself until there are no references.
+ */
+static void
+ns_handle_closure(struct ns_job_t *job)
+{
+	Connection *c = (Connection *)ns_job_get_data(job);
+	int do_yield = 0;
+
+	/* this function must be called from the event loop thread */
+	PR_ASSERT(0 == NS_JOB_IS_THREAD(ns_job_get_type(job)));
+	PR_Lock(c->c_mutex);
+	c->c_ns_close_jobs--;
+	connection_release_nolock(c); /* release ref acquired when job was added */
+	if (connection_table_move_connection_out_of_active_list(c->c_ct, c)) {
+		do_yield = 1;
+		ns_connection_post_io_or_closing(c);
+	}
+	PR_Unlock(c->c_mutex);
+	ns_job_done(job);
+	if (do_yield) {
+		/* yield thread after unlocking conn mutex */
+		PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield to allow other thread to release conn */
+	}
+	return;
+}
+#endif
+#define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET)
+
+/**
+ * Schedule more I/O for this connection, or make sure that it
+ * is closed in the event loop.
+ */
+void
+ns_connection_post_io_or_closing(Connection *conn)
+{
+#ifdef ENABLE_NUNC_STANS
+	struct timeval tv;
+	ns_job_func_t job_func;
+
+	if (CONN_NEEDS_CLOSING(conn)) {
+		if (conn->c_ns_close_jobs) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "already a close job in progress on conn %" NSPRIu64 " for fd=%d\n",
+				       conn->c_connid, conn->c_sd);
+			return;
+		} else {
+			/* just make sure the event is processed at the next possible event loop run */
+			tv.tv_sec = 0;
+			tv.tv_usec = 1000;
+			job_func = ns_handle_closure;
+			conn->c_ns_close_jobs++;
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "post closure job for conn %" NSPRIu64 " for fd=%d\n",
+				       conn->c_connid, conn->c_sd);
+		}
+	} else {
+		/* process event normally - wait for I/O until idletimeout */
+		tv.tv_sec = conn->c_idletimeout;
+		tv.tv_usec = 0;
+		job_func = ns_handle_pr_read_ready;
+		LDAPDebug2Args(LDAP_DEBUG_CONNS, "post I/O job for conn %" NSPRIu64 " for fd=%d\n",
+			       conn->c_connid, conn->c_sd);
+	}
+	connection_acquire_nolock_ext(conn, 1 /* allow acquire even when closing */); /* event framework will have reference */
+	ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,
+			      NS_JOB_READ|NS_JOB_PRESERVE_FD,
+			      job_func, conn, NULL);
+#endif
+}
+
+#ifdef ENABLE_NUNC_STANS
+/* This function must be called without the thread flag, in the
+ * event loop.  This function may free the connection.  This can
+ * only be done in the event loop thread.
+ */
+void
+ns_handle_pr_read_ready(struct ns_job_t *job)
+{
+	int need_closure = 0;
+	int maxthreads = config_get_maxthreadsperconn();
+	Connection *c = (Connection *)ns_job_get_data(job);
+
+	/* this function must be called from the event loop thread */
+	PR_ASSERT(0 == NS_JOB_IS_THREAD(ns_job_get_type(job)));
+
+	PR_Lock(c->c_mutex);
+	LDAPDebug2Args(LDAP_DEBUG_CONNS, "activity on conn %" NSPRIu64 " for fd=%d\n",
+		       c->c_connid, c->c_sd);
+	/* if we were called due to some i/o event, see what the state of the socket is */
+	if (slapi_is_loglevel_set(SLAPI_LOG_CONNS) && !NS_JOB_IS_TIMER(ns_job_get_output_type(job)) && c && c->c_sd) {
+		/* see if socket is closed */
+		char buf[1];
+		ssize_t rc = recv(c->c_sd, buf, sizeof(buf), MSG_PEEK);
+		if (!rc) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket is closed conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else if (rc > 0) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has data available for conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+			LDAPDebug2Args(LDAP_DEBUG_CONNS, "socket has no data available conn %" NSPRIu64 " for fd=%d\n",
+				       c->c_connid, c->c_sd);
+		} else {
+			LDAPDebug(LDAP_DEBUG_CONNS, "socket has error [%d] conn %" NSPRIu64 " for fd=%d\n",
+				  errno, c->c_connid, c->c_sd);
+		}
+	}
+	connection_release_nolock(c); /* release ref acquired when job was added */
+	if (CONN_NEEDS_CLOSING(c)) {
+		need_closure = 1;
+	} else if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {
+		/* idle timeout */
+		disconnect_server_nomutex(c, c->c_connid, -1,
+				          SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN);
+		need_closure = 1;
+	} else if ((connection_activity(c, maxthreads)) == -1) {
+		/* This might happen as a result of
+		 * trying to acquire a closing connection
+		 */
+		LDAPDebug2Args(LDAP_DEBUG_ANY, "connection_activity: abandoning conn %" NSPRIu64
+			       " as fd=%d is already closing\n", c->c_connid, c->c_sd);
+		/* The call disconnect_server should do nothing,
+		 * as the connection c should be already set to CLOSING */
+		disconnect_server_nomutex(c, c->c_connid, -1,
+				          SLAPD_DISCONNECT_POLL, EPIPE);
+		need_closure = 1;
+	} else {
+		LDAPDebug2Args(LDAP_DEBUG_CONNS, "queued conn %" NSPRIu64 " for fd=%d\n",
+			       c->c_connid, c->c_sd);
+	}
+	if (need_closure) {
+		ns_connection_post_io_or_closing(c);
+	}
+	PR_Unlock(c->c_mutex);
+	ns_job_done(job);
+	return;
+}
+#endif
+
 /*
  * wrapper functions required so we can implement ioblock_timeout and
  * avoid blocking forever.
@@ -2796,7 +3030,7 @@ handle_closed_connection(Connection *conn)
 
 /* NOTE: this routine is not reentrant */
 static int
-handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local)
+handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn)
 {
 	int ns = 0;
 	Connection *conn = NULL;
@@ -2806,6 +3040,9 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
 	ber_len_t maxbersize;
 	slapdFrontendConfig_t *fecfg = getFrontendConfig();
 
+	if (newconn) {
+		*newconn = NULL;
+	}
 	memset(&from, 0, sizeof(from)); /* reset to nulls so we can see what was set */
 	if ( (ns = accept_and_configure( tcps, pr_acceptfd, &from,
 		sizeof(from), secure, local, &pr_clonefd)) == SLAPD_INVALID_SOCKET ) {
@@ -2936,9 +3173,57 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
 
 	g_increment_current_conn_count();
 
+	if (newconn) {
+		*newconn = conn;
+	}
 	return 0;
 }
 
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_handle_new_connection(struct ns_job_t *job)
+{
+	int rc;
+	Connection *c = NULL;
+	listener_info *li = (listener_info *)ns_job_get_data(job);
+
+	/* only accept new connections if we have enough fds, more than
+	 * the number of reserved descriptors
+	 */
+	if ((li->ct->size - g_get_current_conn_count())
+	     <= config_get_reservedescriptors()) {
+		/* too many open fds - shut off this listener - when an fd is
+		 * closed, try to resume this listener
+		 */
+		ns_disable_listener(li);
+		return;
+	}
+
+	rc = handle_new_connection(li->ct, SLAPD_INVALID_SOCKET, li->listenfd, li->secure, li->local, &c);
+	if (rc) {
+		PRErrorCode prerr = PR_GetError();
+		if (PR_PROC_DESC_TABLE_FULL_ERROR == prerr) {
+			/* too many open fds - shut off this listener - when an fd is
+			 * closed, try to resume this listener
+			 */
+			ns_disable_listener(li);
+		} else {
+			LDAPDebug(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d [%d:%s]\n",
+				  PR_FileDesc2NativeHandle(li->listenfd), prerr,
+				  slapd_pr_strerror(prerr));
+		}
+		return;
+	}
+	/* now, set up the conn for reading - no thread - ns_handle_pr_read_ready
+	 * must be run in the event loop thread
+	 */
+	c->c_tp = ns_job_get_tp(job);
+	connection_acquire_nolock(c); /* event framework now has ref */
+	ns_add_job(ns_job_get_tp(job), NULL, NS_JOB_NONE, ns_handle_pr_read_ready, c);
+	return;
+}
+#endif
+
 static int init_shutdown_detect()
 {
 
@@ -3003,8 +3288,10 @@ static int init_shutdown_detect()
 	(void) SIGNAL( SIGUSR1, slapd_do_nothing );
 	(void) SIGNAL( SIGUSR2, set_shutdown );
 #endif
+#ifndef ENABLE_NUNC_STANS
 	(void) SIGNAL( SIGTERM, set_shutdown );
 	(void) SIGNAL( SIGHUP,  set_shutdown );
+#endif
 #endif /* _WIN32 */
 	return 0;
 }
@@ -3193,6 +3480,15 @@ set_shutdown (int sig)
 #endif
 }
 
+#ifdef ENABLE_NUNC_STANS
+static void
+ns_set_shutdown(struct ns_job_t *job)
+{
+	set_shutdown(0);
+	ns_thrpool_shutdown(ns_job_get_tp(job));
+}
+#endif
+
 #ifndef LINUX
 void
 slapd_do_nothing (int sig)
diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h
index 2504a4b..27d858e 100644
--- a/ldap/servers/slapd/fe.h
+++ b/ldap/servers/slapd/fe.h
@@ -158,7 +158,7 @@ Connection_Table *connection_table_new(int table_size);
 void connection_table_free(Connection_Table *ct);
 void connection_table_abandon_all_operations(Connection_Table *ct);
 Connection *connection_table_get_connection(Connection_Table *ct, int sd);
-void connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connection *c);
+int connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connection *c);
 void connection_table_move_connection_on_to_active_list(Connection_Table *ct, Connection *c);
 void connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e);
 void connection_table_dump_activity_to_errors_log(Connection_Table *ct);
@@ -185,6 +185,7 @@ int daemon_register_reslimits( void );
 PRFileDesc * get_ssl_listener_fd();
 int configure_pr_socket( PRFileDesc **pr_socket, int secure, int local );
 void configure_ns_socket( int * ns );
+void ns_enable_listeners();
 
 /*
  * sasl_io.c
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index bc88221..40f5f9e 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1421,6 +1421,7 @@ int mapping_tree_get_extension_type ();
  * connection.c
  */
 int connection_acquire_nolock (Connection *conn);
+int connection_acquire_nolock_ext (Connection *conn, int allow_when_closing);
 int connection_release_nolock (Connection *conn);
 int connection_is_free (Connection *conn);
 int connection_is_active_nolock (Connection *conn);
@@ -1462,6 +1463,10 @@ void slapd_wait4child (int);
 #else
 void *slapd_service_exit_wait();
 #endif
+#ifdef ENABLE_NUNC_STANS
+void ns_handle_pr_read_ready(struct ns_job_t *job);
+#endif
+void ns_connection_post_io_or_closing(Connection *conn);
 
 /*
  * main.c
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 3612632..b856afe 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -172,6 +172,10 @@ typedef struct symbol_t {
 #include "csngen.h"
 #include "uuid.h"
 
+#ifdef ENABLE_NUNC_STANS
+#include <ns_thrpool.h>
+#endif
+
 #if defined(OS_solaris)
 #  include <thread.h>
 #  define GET_THREAD_ID() thr_self()
@@ -1503,7 +1507,11 @@ typedef struct conn {
     Conn_IO_Layer_cb c_push_io_layer_cb; /* callback to push an IO layer on the conn->c_prfd */
     Conn_IO_Layer_cb c_pop_io_layer_cb; /* callback to pop an IO layer off of the conn->c_prfd */
     void             *c_io_layer_cb_data; /* callback data */
-
+#ifdef ENABLE_NUNC_STANS
+    struct connection_table     *c_ct; /* connection table that this connection belongs to */
+    ns_thrpool_t                *c_tp; /* thread pool for this connection */
+    int                         c_ns_close_jobs; /* number of current close jobs */
+#endif
 } Connection;
 #define CONN_FLAG_SSL	1	/* Is this connection an SSL connection or not ? 
 							 * Used to direct I/O code when SSL is handled differently 
diff --git a/m4/lfds.m4 b/m4/lfds.m4
new file mode 100644
index 0000000..d5dcbb7
--- /dev/null
+++ b/m4/lfds.m4
@@ -0,0 +1,78 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+AC_CHECKING(for lfds)
+
+dnl  - check for --with-lfds
+AC_MSG_CHECKING(for --with-lfds)
+AC_ARG_WITH(lfds, AS_HELP_STRING([--with-lfds@<:@=PATH@:>@],[LFDS directory]),
+[
+  if test "$withval" = "yes"; then
+    AC_MSG_RESULT(yes)
+  elif test "$withval" = "no"; then
+    AC_MSG_RESULT(no)
+  elif test -d "$withval"/inc -a -d "$withval"/bin; then
+    AC_MSG_RESULT([using $withval])
+    dnl - check the user provided location
+    lfds_lib="-L$withval/bin"
+    lfds_libdir="$withval/lib"
+    lfds_incdir="$withval/inc"
+    if ! test -e "$lfds_incdir/liblfds.h" ; then
+      AC_MSG_ERROR([$withval include dir not found])
+    fi
+    lfds_inc="-I$lfds_incdir"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-lfds-inc
+AC_MSG_CHECKING(for --with-lfds-inc)
+AC_ARG_WITH(lfds-inc, AS_HELP_STRING([--with-lfds-inc=PATH],[LFDS include file directory]),
+[
+  if test -e "$withval"/liblfds.h
+  then
+    AC_MSG_RESULT([using $withval])
+    lfds_incdir="$withval"
+    lfds_inc="-I$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-lfds-lib
+AC_MSG_CHECKING(for --with-lfds-lib)
+AC_ARG_WITH(lfds-lib, AS_HELP_STRING([--with-lfds-lib=PATH],[LFDS library directory]),
+[
+  if test -d "$withval"
+  then
+    AC_MSG_RESULT([using $withval])
+    lfds_lib="-L$withval"
+    lfds_libdir="$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
diff --git a/m4/nunc-stans.m4 b/m4/nunc-stans.m4
new file mode 100644
index 0000000..e68f651
--- /dev/null
+++ b/m4/nunc-stans.m4
@@ -0,0 +1,78 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# END COPYRIGHT BLOCK
+
+AC_CHECKING(for nunc-stans)
+
+dnl  - check for --with-nunc-stans
+AC_MSG_CHECKING(for --with-nunc-stans)
+AC_ARG_WITH(nunc-stans, AS_HELP_STRING([--with-nunc-stans@<:@=PATH@:>@],[nunc-stans directory]),
+[
+  if test "$withval" = "yes"; then
+    AC_MSG_RESULT(yes)
+  elif test "$withval" = "no"; then
+    AC_MSG_RESULT(no)
+  elif test -d "$withval"; then
+    AC_MSG_RESULT([using $withval])
+    dnl - check the user provided location
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+    nunc_stans_incdir="$withval"
+    if ! test -e "$nunc_stans_incdir/ns_thrpool.h" ; then
+      AC_MSG_ERROR([$withval include dir not found])
+    fi
+    nunc_stans_inc="-I$nunc_stans_incdir"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-nunc-stans-inc
+AC_MSG_CHECKING(for --with-nunc-stans-inc)
+AC_ARG_WITH(nunc-stans-inc, AS_HELP_STRING([--with-nunc-stans-inc=PATH],[nunc-stans include file directory]),
+[
+  if test -e "$withval"/ns_thrpool.h
+  then
+    AC_MSG_RESULT([using $withval])
+    nunc_stans_incdir="$withval"
+    nunc_stans_inc="-I$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))
+
+# check for --with-nunc-stans-lib
+AC_MSG_CHECKING(for --with-nunc-stans-lib)
+AC_ARG_WITH(nunc-stans-lib, AS_HELP_STRING([--with-nunc-stans-lib=PATH],[nunc-stans library directory]),
+[
+  if test -d "$withval"
+  then
+    AC_MSG_RESULT([using $withval])
+    nunc_stans_lib="-L$withval"
+    nunc_stans_libdir="$withval"
+  else
+    echo
+    AC_MSG_ERROR([$withval not found])
+  fi
+],
+AC_MSG_RESULT(no))




More information about the 389-commits mailing list