#50670 Ticket 50669 - remove nunc-stans
Closed 3 years ago by spichugi. Opened 4 years ago by firstyear.
firstyear/389-ds-base 50669-remove-nunc-stans  into  master

file modified
+7 -52
@@ -68,9 +68,6 @@ 

  SDS_INCLUDES = -I$(srcdir)/src/libsds/include/ -I$(srcdir)/src/libsds/external/

  endif

  

- NUNCSTANS_INCLUDES = -I$(srcdir)/src/nunc-stans/include/

- NUNC_STANS_ON = 1

- 

  SVRCORE_INCLUDES = -I$(srcdir)/src/svrcore/src/

  

  # the -U undefines these symbols - should use the corresponding DS_ ones instead - see configure.ac
@@ -142,8 +139,6 @@ 

  DSINTERNAL_CPPFLAGS = -I$(srcdir)/include/ldaputil

  # Flags for Datastructure Library

  SDS_CPPFLAGS = $(SDS_INCLUDES) $(NSPR_INCLUDES)

- # Flags for nunc-stans

- NUNCSTANS_CPPFLAGS = $(NSPR_INCLUDES) $(NUNCSTANS_INCLUDES) $(SDS_INCLUDES) $(EVENT_CFLAGS)

  

  #------------------------

  # Linker Flags
@@ -345,7 +340,7 @@ 

  # based on defines

  # ----------------------------------------------------------------------------------------

  

- server_LTLIBRARIES = libsds.la libnunc-stans.la libslapd.la libldaputil.la libns-dshttpd.la

+ server_LTLIBRARIES = libsds.la libslapd.la libldaputil.la libns-dshttpd.la

  

  lib_LTLIBRARIES = libsvrcore.la

  
@@ -583,9 +578,7 @@ 

  	src/libsds/sds/bpt/bpt.h \

  	src/libsds/sds/bpt_cow/bpt_cow.h \

  	src/libsds/sds/queue/queue.h \

- 	src/libsds/sds/ht/ht.h \

- 	src/nunc-stans/ns/ns_event_fw.h \

- 	src/nunc-stans/ns/ns_private.h

+ 	src/libsds/sds/ht/ht.h

  

  if ATOMIC_QUEUE_OPERATIONS

  dist_noinst_HEADERS += \
@@ -606,8 +599,7 @@ 

  	test/test_slapd.h \

  	src/libsds/test/test_sds.h \

  	src/libsds/test/benchmark.h \

- 	src/libsds/test/benchmark_par.h \

- 	src/nunc-stans/test/test_nuncstans_stress.h

+ 	src/libsds/test/benchmark_par.h

  endif

  

  dist_noinst_DATA = \
@@ -908,7 +900,6 @@ 

  

  pkgconfig_DATA = src/pkgconfig/dirsrv.pc \

  	src/pkgconfig/libsds.pc \

- 	src/pkgconfig/nunc-stans.pc \

  	src/pkgconfig/svrcore.pc

  

  #------------------------
@@ -918,7 +909,6 @@ 

  	ldap/servers/slapd/slapi_pal.h \

  	ldap/servers/slapd/slapi-plugin.h \

  	ldap/servers/plugins/replication/winsync-plugin.h \

- 	src/nunc-stans/include/nunc-stans.h \

  	src/libsds/include/sds.h

  

  include_HEADERS = src/svrcore/src/svrcore.h
@@ -1221,20 +1211,6 @@ 

  endif

  

  #------------------------

- # libnunc-stans

- #------------------------

- 

- libnunc_stans_la_SOURCES = src/nunc-stans/ns/ns_thrpool.c \

- 						src/nunc-stans/ns/ns_event_fw_event.c

- 

- # EDIT THESE AT THE TOP OF THE MAKE FILE!!!

- libnunc_stans_la_CPPFLAGS = $(AM_CPPFLAGS) $(NUNCSTANS_CPPFLAGS)

- libnunc_stans_la_LDFLAGS = $(AM_LDFLAGS) $(NUNCSTANS_LDFLAGS)

- libnunc_stans_la_LIBADD = libsds.la

- libnunc_stans_la_DEPENDENCIES = libsds.la

- 

- 

- #------------------------

  # libns-dshttpd

  #------------------------

  libns_dshttpd_la_SOURCES = lib/libaccess/access_plhash.cpp \
@@ -2094,9 +2070,9 @@ 

  	$(GETSOCKETPEER)

  

  ns_slapd_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_CFLAGS) $(SVRCORE_INCLUDES)

- ns_slapd_LDADD = libnunc-stans.la libslapd.la libldaputil.la libsvrcore.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \

+ ns_slapd_LDADD = libslapd.la libldaputil.la libsvrcore.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \

  	$(NSPR_LINK) $(SASL_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LIBS) $(EVENT_LINK)

- ns_slapd_DEPENDENCIES = libslapd.la libnunc-stans.la libldaputil.la

+ ns_slapd_DEPENDENCIES = libslapd.la libldaputil.la

  # We need to link ns-slapd with the C++ compiler on HP-UX since we load

  # some C++ shared libraries (such as icu).

  if HPUX
@@ -2133,15 +2109,10 @@ 

  check_PROGRAMS = test_slapd \

  	test_libsds \

  	benchmark_sds \

- 	benchmark_par_sds \

- 	test_nuncstans \

- 	test_nuncstans_stress_small \

- 	test_nuncstans_stress_large

+ 	benchmark_par_sds

  # Mark all check programs for testing

  TESTS = test_slapd \

- 	test_libsds \

- 	test_nuncstans \

- 	test_nuncstans_stress_small

+ 	test_libsds

  

  test_slapd_SOURCES = test/main.c \

  	test/libslapd/test.c \
@@ -2193,22 +2164,6 @@ 

  benchmark_par_sds_LDADD = libsds.la $(NSPR_LINK)

  benchmark_par_sds_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(SDS_CPPFLAGS) $(DS_INCLUDES)

  

- test_nuncstans_SOURCES = src/nunc-stans/test/test_nuncstans.c

- test_nuncstans_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

- test_nuncstans_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_LDFLAGS = $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

- 

- test_nuncstans_stress_large_SOURCES = src/nunc-stans/test/test_nuncstans_stress_large.c src/nunc-stans/test/test_nuncstans_stress_core.c

- test_nuncstans_stress_large_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

- test_nuncstans_stress_large_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_stress_large_LDFLAGS = $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

- 

- test_nuncstans_stress_small_SOURCES = src/nunc-stans/test/test_nuncstans_stress_small.c src/nunc-stans/test/test_nuncstans_stress_core.c

- test_nuncstans_stress_small_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

- test_nuncstans_stress_small_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_stress_small_LDFLAGS = $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

- 

- 

  endif

  #------------------------

  # end cmocka tests

file modified
-3
@@ -862,9 +862,6 @@ 

  AC_SUBST(ldaptool_bindir)

  AC_SUBST(ldaptool_opts)

  AC_SUBST(plainldif_opts)

- AC_SUBST(nunc_stans_inc)

- AC_SUBST(nunc_stans_lib)

- AC_SUBST(nunc_stans_libdir)

  AC_SUBST(localrundir)

  

  AC_SUBST(brand)

@@ -711,12 +711,6 @@ 

      } else {

          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;

      }

  }
@@ -1351,10 +1345,6 @@ 

      conn->c_gettingber = 0;

      slapi_log_err(SLAPI_LOG_CONNS, "connection_make_readable_nolock", "making readable conn %" PRIu64 " fd=%d\n",

                    conn->c_connid, conn->c_sd);

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

-     }

  }

  

  /*
@@ -1496,10 +1486,8 @@ 

      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;

-     int enable_nunc_stans = 0;

      long bypasspollcnt = 0;

  

-     enable_nunc_stans = config_get_enable_nunc_stans();

  #if defined(hpux)

      /* Arrange to ignore SIGPIPE signals. */

      SIGNAL(SIGPIPE, SIG_IGN);
@@ -1730,7 +1718,7 @@ 

                   * when using nunc-stans - it is supposed to be an optimization but turns out

                   * to not be the opposite with nunc-stans

                   */

-             } else if (!enable_nunc_stans) { /* more data in conn - just put back on work_q - bypass poll */

+             } else { /* more data in conn - just put back on work_q - bypass poll */

                  bypasspollcnt++;

                  pthread_mutex_lock(&(conn->c_mutex));

                  /* don't do this if it would put us over the max threads per conn */
@@ -2327,9 +2315,6 @@ 

                  }

              }

          }

-         if (schedule_closure_job) {

-             ns_connection_post_io_or_closing(conn); /* make sure event loop wakes up and closes this conn */

-         }

  

      } else {

          slapi_log_err(SLAPI_LOG_CONNS, "disconnect_server_nomutex_ext", "Not setting conn %d to be disconnected: %s\n",

file modified
+63 -470
@@ -99,8 +99,6 @@ 

  static size_t 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(void);
@@ -150,22 +148,12 @@ 

   * This is the shiny new re-born daemon function, without all the hair

   */

  static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn);

- static void ns_handle_new_connection(struct ns_job_t *job);

- static void ns_handle_closure(struct ns_job_t *job);

  static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);

  static int clear_signal(struct POLL_STRUCT *fds);

  static void unfurl_banners(Connection_Table *ct, daemon_ports_t *ports, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix);

  static int write_pid_file(void);

  static int init_shutdown_detect(void);

  

- #define NS_HANDLER_NEW_CONNECTION   0

- #define NS_HANDLER_READ_CONNECTION  1

- #define NS_HANDLER_CLOSE_CONNECTION 2

- static ns_job_func_t ns_handlers[] = {

-     ns_handle_new_connection,

-     ns_handle_pr_read_ready,

-     ns_handle_closure

- };

  /* Globals which are used to store the sockets between

   * calls to daemon_pre_setuid_init() and the daemon thread

   * creation. */
@@ -804,7 +792,7 @@ 

  }

  

  void

- slapd_daemon(daemon_ports_t *ports, ns_thrpool_t *tp)

+ slapd_daemon(daemon_ports_t *ports)

  {

      /* We are passed some ports---one for regular connections, one

       * for SSL connections, one for ldapi connections.
@@ -825,7 +813,13 @@ 

      int connection_table_size = get_configured_connection_table_size();

      the_connection_table = connection_table_new(connection_table_size);

  

-     enable_nunc_stans = config_get_enable_nunc_stans();

+     /*

+      * Log a warning if we detect nunc-stans

+      */

+     if (config_get_enable_nunc_stans()) {

+         slapi_log_err(SLAPI_LOG_WARNING, "slapd_daemon", "cn=config: nsslapd-enable-nunc-stans is on. nunc-stans has been deprecated and this flag is now ignored.\n");

+         slapi_log_err(SLAPI_LOG_WARNING, "slapd_daemon", "cn=config: nsslapd-enable-nunc-stans should be set to off or deleted from cn=config.\n");

+     }

  

  #ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS

      /*
@@ -848,11 +842,9 @@ 

      i_unix = ports->i_socket;

  #endif /* ENABLE_LDAPI */

  

-     if (!enable_nunc_stans) {

-         createsignalpipe();

-         /* Setup our signal interception. */

-         init_shutdown_detect();

-     }

+     createsignalpipe();

+     /* Setup our signal interception. */

+     init_shutdown_detect();

  

      if (

          (n_tcps == NULL) &&
@@ -961,17 +953,6 @@ 

       */

      convert_pbe_des_to_aes();

  

-     if (enable_nunc_stans && !g_get_shutdown()) {

-         setup_pr_read_pds(the_connection_table, n_tcps, s_tcps, i_unix, &num_poll);

-         for (size_t ii = 0; ii < listeners; ++ii) {

-             listener_idxs[ii].ct = the_connection_table; /* to pass to handle_new_connection */

-             ns_result_t result = ns_add_io_job(tp, listener_idxs[ii].listenfd, NS_JOB_ACCEPT | NS_JOB_PERSIST | NS_JOB_PRESERVE_FD,

-                                                ns_handlers[NS_HANDLER_NEW_CONNECTION], &listener_idxs[ii], &(listener_idxs[ii].ns_job));

-             if (result != NS_SUCCESS) {

-                 slapi_log_err(SLAPI_LOG_CRIT, "slapd_daemon", "ns_add_io_job failed to create add acceptor %d\n", result);

-             }

-         }

-     }

      /* Now we write the pid file, indicating that the server is finally and listening for connections */

      write_pid_file();

  
@@ -985,58 +966,32 @@ 

                 (unsigned long)getpid());

  #endif

  

-     if (enable_nunc_stans) {

-         if (ns_thrpool_wait(tp)) {

-             slapi_log_err(SLAPI_LOG_ERR,

-                           "slapd-daemon", "ns_thrpool_wait failed errno %d (%s)\n", errno,

-                           slapd_system_strerror(errno));

-         }

- 

-         /* we have exited from ns_thrpool_wait. This means we are shutting down! */

-         /* Please see https://firstyear.fedorapeople.org/nunc-stans/md_docs_job-safety.html */

-         /* tldr is shutdown needs to run first to allow job_done on an ARMED job */

-         for (uint64_t i = 0; i < listeners; i++) {

-             PRStatus shutdown_status;

+     /* The meat of the operation is in a loop on a call to select */

+     while (!g_get_shutdown()) {

+         int select_return = 0;

+         PRErrorCode prerr;

  

-             if (listener_idxs[i].ns_job) {

-                 shutdown_status = ns_job_done(listener_idxs[i].ns_job);

-                 if (shutdown_status != PR_SUCCESS) {

-                     slapi_log_err(SLAPI_LOG_CRIT, "ns_set_shutdown", "Failed to shutdown listener idx %" PRIu64 " !\n", i);

-                 }

-                 PR_ASSERT(shutdown_status == PR_SUCCESS);

-             } else {

-                 slapi_log_err(SLAPI_LOG_CRIT, "slapd_daemon", "Listeners uninitialized. Possibly the server was shutdown while starting\n");

-             }

-             listener_idxs[i].ns_job = NULL;

-         }

-     } else {

-         /* The meat of the operation is in a loop on a call to select */

-         while (!g_get_shutdown()) {

-             int select_return = 0;

-             PRErrorCode prerr;

- 

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

-             switch (select_return) {

-             case 0: /* Timeout */

-                 break;

-             case -1: /* Error */

-                 prerr = PR_GetError();

-                 slapi_log_err(SLAPI_LOG_TRACE, "slapd_daemon", "PR_Poll() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

-                               prerr, slapd_system_strerror(prerr));

-                 break;

-             default: /* either a new connection or some new data ready */

-                 /* handle new connections from the 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);

-                 break;

-             }

+         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);

+         switch (select_return) {

+         case 0: /* Timeout */

+             break;

+         case -1: /* Error */

+             prerr = PR_GetError();

+             slapi_log_err(SLAPI_LOG_TRACE, "slapd_daemon", "PR_Poll() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

+                           prerr, slapd_system_strerror(prerr));

+             break;

+         default: /* either a new connection or some new data ready */

+             /* handle new connections from the 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);

+             break;

          }

-         /* We get here when the server is shutting down */

-         /* Do what we have to do before death */

      }

+     /* We get here when the server is shutting down */

+     /* Do what we have to do before death */

  

  #ifdef WITH_SYSTEMD

      sd_notify(0, "STOPPING=1");
@@ -1103,19 +1058,6 @@ 

       */

      connection_table_disconnect_all(the_connection_table);

  

-     /*

-      * WARNING: Normally we should close the tp in main

-      * but because of issues in the current connection design

-      * we need to close it here to guarantee events won't fire!

-      *

-      * All the connection close jobs "should" complete before

-      * shutdown at least.

-      */

-     if (enable_nunc_stans) {

-         ns_thrpool_shutdown(tp);

-         ns_thrpool_wait(tp);

-     }

- 

      if (!in_referral_mode) {

          /* signal tasks to start shutting down */

          task_cancel_all();
@@ -1130,33 +1072,31 @@ 

  

      threads = g_get_active_threadcnt();

      while (threads > 0) {

-         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();

-                     slapi_log_err(SLAPI_LOG_ERR, "slapd_daemon", "listener could not clear signal pipe, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

-                                   prerr, slapd_system_strerror(prerr));

-                     break;

-                 }

-             } else if (spe == -1) {

+         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();

-                 slapi_log_err(SLAPI_LOG_ERR, "slapd_daemon", "PR_Poll() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

+                 slapi_log_err(SLAPI_LOG_ERR, "slapd_daemon", "listener could not clear signal pipe, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

                                prerr, slapd_system_strerror(prerr));

                  break;

-             } else {

-                 /* no data */

              }

+         } else if (spe == -1) {

+             PRErrorCode prerr = PR_GetError();

+             slapi_log_err(SLAPI_LOG_ERR, "slapd_daemon", "PR_Poll() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",

+                           prerr, slapd_system_strerror(prerr));

+             break;

+         } else {

+             /* no data */

          }

          DS_Sleep(PR_INTERVAL_NO_WAIT);

          if (threads != g_get_active_threadcnt()) {
@@ -1226,9 +1166,6 @@ 

  int

  signal_listner()

  {

-     if (enable_nunc_stans) {

-         return (0);

-     }

      /* Replaces previous macro---called to bump the thread out of select */

      if (write(writesignalpipe, "", 1) != 1) {

          /* this now means that the pipe is full
@@ -1244,9 +1181,6 @@ 

  static int

  clear_signal(struct POLL_STRUCT *fds)

  {

-     if (enable_nunc_stans) {

-         return 0;

-     }

      if (fds[FDS_SIGNAL_PIPE].out_flags & SLAPD_POLL_FLAGS) {

          char buf[200];

  
@@ -1300,14 +1234,12 @@ 

              ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;

          }

  

-         if (!enable_nunc_stans) {

-             /* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE (== 0) */

-             count = FDS_SIGNAL_PIPE;

-             ct->fd[count].fd = signalpipe[0];

-             ct->fd[count].in_flags = SLAPD_POLL_FLAGS;

-             ct->fd[count].out_flags = 0;

-             count++;

-         }

+         /* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE (== 0) */

+         count = FDS_SIGNAL_PIPE;

+         ct->fd[count].fd = signalpipe[0];

+         ct->fd[count].in_flags = SLAPD_POLL_FLAGS;

+         ct->fd[count].out_flags = 0;

+         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) {
@@ -1543,293 +1475,6 @@ 

      }

  }

  

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

-  */

- static void

- ns_handle_closure(struct ns_job_t *job)

- {

-     Connection *c = (Connection *)ns_job_get_data(job);

-     int do_yield = 0;

- 

-     pthread_mutex_lock(&(c->c_mutex));

-     /* Assert we really have the right job state. */

-     PR_ASSERT(job == c->c_job);

- 

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

-     /* Because handle closure will add a new job, we need to detach our current one. */

-     c->c_job = NULL;

-     do_yield = ns_handle_closure_nomutex(c);

-     pthread_mutex_unlock(&(c->c_mutex));

-     /* Remove this task now. */

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

- }

- 

- /**

-  * Schedule more I/O for this connection, or make sure that it

-  * is closed in the event loop.

-  *

-  * caller must hold c_mutex

-  */

- void

- ns_connection_post_io_or_closing(Connection *conn)

- {

-     struct timeval tv;

- 

-     if (!enable_nunc_stans) {

-         return;

-     }

- 

-     /*

-      * A job was already scheduled.

-      * Check if it is the appropriate one

-      */

-     if (conn->c_job != NULL) {

-         if (connection_is_free(conn, 0)) {

-             PRStatus shutdown_status;

- 

-             /* The connection being freed,

-              * It means that ns_handle_closure already completed and the connection

-              * is no longer on the active list.

-              * The scheduled job is useless and scheduling a new one as well

-              */

-             shutdown_status = ns_job_done(conn->c_job);

-             if (shutdown_status != PR_SUCCESS) {

-                 slapi_log_err(SLAPI_LOG_CRIT, "ns_connection_post_io_or_closing", "Failed cancel a job on a freed connection %d !\n", conn->c_sd);

-             }

-             conn->c_job = NULL;

-             return;

-         }

-         if (CONN_NEEDS_CLOSING(conn)) {

-             if (ns_job_is_func(conn->c_job, ns_handlers[NS_HANDLER_CLOSE_CONNECTION])) {

-                 /* Due to the closing state we would schedule a ns_handle_closure

-                  * but one is already registered.

-                  * Just return;

-                  */

-                 slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "Already ns_handle_closure "

-                         "job in progress on conn %" PRIu64 " for fd=%d\n",

-                         conn->c_connid, conn->c_sd);

-                 return;

-             } else {

-                 /* Due to the closing state we would schedule a ns_handle_closure

-                  * but a different handler is registered. Stop it and schedule (below) ns_handle_closure

-                  */

-                 ns_job_done(conn->c_job);

-                 conn->c_job = NULL;

-             }

-         } else {

-             /* Here the connection is still active => ignore the call and return */

-             if (ns_job_is_func(conn->c_job, ns_handlers[NS_HANDLER_READ_CONNECTION])) {

-                 /* Connection is still active and a read_ready is already scheduled

-                  * Likely a consequence of async operations

-                  * Just let the current read_ready do its job

-                  */

-                 slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "Already ns_handle_pr_read_ready "

-                                                                                "job in progress on conn %" PRIu64 " for fd=%d\n",

-                           conn->c_connid, conn->c_sd);

-             } else {

-                 /* Weird situation where the connection is not flagged closing but ns_handle_closure

-                  * is scheduled.

-                  * We should not try to read it anymore

-                  */

-                 PR_ASSERT(ns_job_is_func(conn->c_job, ns_handlers[NS_HANDLER_CLOSE_CONNECTION]));

-             }

-             return;

-         }

-     }

- 

-     /* At this point conn->c_job is NULL

-      * Either it was null when the function was called

-      * Or we cleared it (+ns_job_done) if the wrong (according

-      * to the connection state) handler was scheduled

-      *

-      * Now we need to determine which handler to schedule

-      */

- 

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

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "Already a close "

-                                                                                "job in progress on conn %" PRIu64 " for fd=%d\n",

-                           conn->c_connid, conn->c_sd);

-             return;

-         } else {

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

-             /* Close the job asynchronously. Why? */

-             ns_result_t job_result = ns_add_job(conn->c_tp, NS_JOB_TIMER, ns_handlers[NS_HANDLER_CLOSE_CONNECTION], conn, &(conn->c_job));

-             if (job_result != NS_SUCCESS) {

-                 if (job_result == NS_SHUTDOWN) {

-                     slapi_log_err(SLAPI_LOG_INFO, "ns_connection_post_io_or_closing", "post closure job "

-                                                                                       "for conn %" PRIu64 " for fd=%d failed to be added to event queue as server is shutting down\n",

-                                   conn->c_connid, conn->c_sd);

-                 } else {

-                     slapi_log_err(SLAPI_LOG_ERR, "ns_connection_post_io_or_closing", "post closure job "

-                                                                                      "for conn %" PRIu64 " for fd=%d failed to be added to event queue %d\n",

-                                   conn->c_connid, conn->c_sd, job_result);

-                 }

-             } else {

-                 slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "post closure job "

-                                                                                    "for conn %" PRIu64 " for fd=%d\n",

-                               conn->c_connid, conn->c_sd);

-             }

-         }

-     } else {

-         /* process event normally - wait for I/O until idletimeout */

-         /* With nunc-stans there is a quirk. When we have idleTimeout of -1

-          * which is set on some IPA bind dns for infinite, this causes libevent

-          * to *instantly* timeout. So if we detect < 0, we set 0 to this timeout, to

-          * catch all possible times that an admin could set.

-          */

-         if (conn->c_idletimeout < 0) {

-             tv.tv_sec = 0;

-         } else {

-             tv.tv_sec = conn->c_idletimeout;

-         }

-         tv.tv_usec = 0;

- #ifdef DEBUG

-         PR_ASSERT(0 == connection_acquire_nolock(conn));

- #else

-         if (connection_acquire_nolock(conn) != 0) { /* event framework now has a reference */

-             /*

-              * This has already been logged as an error in ./ldap/servers/slapd/connection.c

-              * The error occurs when we get a connection in a closing state.

-              * For now we return, but there is probably a better way to handle the error case.

-              */

-             return;

-         }

- #endif

-         ns_result_t job_result = ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,

-                                                        NS_JOB_READ | NS_JOB_PRESERVE_FD,

-                                                        ns_handlers[NS_HANDLER_READ_CONNECTION], conn, &(conn->c_job));

-         if (job_result != NS_SUCCESS) {

-             if (job_result == NS_SHUTDOWN) {

-                 slapi_log_err(SLAPI_LOG_INFO, "ns_connection_post_io_or_closing", "post I/O job for "

-                                                                                   "conn %" PRIu64 " for fd=%d failed to be added to event queue as server is shutting down\n",

-                               conn->c_connid, conn->c_sd);

-             } else {

-                 slapi_log_err(SLAPI_LOG_ERR, "ns_connection_post_io_or_closing", "post I/O job for "

-                                                                                  "conn %" PRIu64 " for fd=%d failed to be added to event queue %d\n",

-                               conn->c_connid, conn->c_sd, job_result);

-             }

-         } else {

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "post I/O job for "

-                                                                                "conn %" PRIu64 " for fd=%d added to event queue\n",

-                           conn->c_connid, conn->c_sd);

-         }

-     }

-     return;

- }

- 

- /* 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)

- {

-     Connection *c = (Connection *)ns_job_get_data(job);

- 

-     pthread_mutex_lock(&(c->c_mutex));

-     /* Assert we really have the right job state. */

-     PR_ASSERT(job == c->c_job);

- 

-     /* On all code paths we remove the job, so set it null now */

-     c->c_job = NULL;

- 

-     slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "activity on conn %" PRIu64 " 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) {

-         /* check socket state */

-         char buf[1];

-         ssize_t rc = recv(c->c_sd, buf, sizeof(buf), MSG_PEEK);

-         if (!rc) {

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "socket is closed conn"

-                                                                       " %" PRIu64 " for fd=%d\n",

-                           c->c_connid, c->c_sd);

-         } else if (rc > 0) {

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "socket read data available"

-                                                                       " for conn %" PRIu64 " for fd=%d\n",

-                           c->c_connid, c->c_sd);

-         } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "socket has no data available"

-                                                                       " conn %" PRIu64 " for fd=%d\n",

-                           c->c_connid, c->c_sd);

-         } else {

-             slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "socket has error [%d] "

-                                                                       "conn %" PRIu64 " for fd=%d\n",

-                           errno, c->c_connid, c->c_sd);

-         }

-     }

-     connection_release_nolock_ext(c, 1); /* release ref acquired when job was added */

-     if (CONN_NEEDS_CLOSING(c)) {

-         ns_handle_closure_nomutex(c);

-         /* We shouldn't need the c_idletimeout check here because of how libevent works.

-          * consider testing this and removing it oneday.

-          */

-     } else if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-         if (c->c_idletimeout > 0) {

-             /* idle timeout */

-             disconnect_server_nomutex_ext(c, c->c_connid, -1,

-                                           SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN,

-                                           0 /* do not schedule closure, do it next */);

-         } else {

-             slapi_log_err(SLAPI_LOG_WARNING, "ns_handle_pr_read_ready", "Received idletime out with c->c_idletimeout as 0. Ignoring.\n");

-         }

-         ns_handle_closure_nomutex(c);

-     } else if ((connection_activity(c, c->c_max_threads_per_conn)) == -1) {

-         /* This might happen as a result of

-          * trying to acquire a closing connection

-          */

-         slapi_log_err(SLAPI_LOG_ERR, "ns_handle_pr_read_ready", "connection_activity: abandoning"

-                                                                 " conn %" PRIu64 " 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_ext(c, c->c_connid, -1,

-                                       SLAPD_DISCONNECT_POLL, EPIPE,

-                                       0 /* do not schedule closure, do it next */);

-         ns_handle_closure_nomutex(c);

-     } else {

-         slapi_log_err(SLAPI_LOG_CONNS, "ns_handle_pr_read_ready", "queued conn %" PRIu64 " for fd=%d\n",

-                       c->c_connid, c->c_sd);

-     }

-     /* Since we call done on the job, we need to remove it here. */

-     pthread_mutex_unlock(&(c->c_mutex));

-     ns_job_done(job);

-     return;

- }

- 

  /*

   * wrapper functions required so we can implement ioblock_timeout and

   * avoid blocking forever.
@@ -2403,53 +2048,6 @@ 

      return 0;

  }

  

- 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 - Just return, and hope next time is better. */

-         slapi_log_error(SLAPI_LOG_FATAL, "ns_handle_new_connection", "Insufficient Reserve FD: File Descriptor exhaustion has occured! Connections will be silently dropped!\n");

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

-              *

-              * WARNING: This generates a lot of false negatives. Why?

-              */

-             slapi_log_error(SLAPI_LOG_FATAL, "ns_handle_new_connection", "PR_PROC_DESC_TABLE_FULL_ERROR: File Descriptor exhaustion has occured! Connections will be silently dropped!\n");

-         } else {

-             slapi_log_err(SLAPI_LOG_FATAL, "ns_handle_new_connection", "Error accepting new connection listenfd=%d [%d:%s]\n",

-                           PR_FileDesc2NativeHandle(li->listenfd), prerr,

-                           slapd_pr_strerror(prerr));

-         }

-         return;

-     }

-     c->c_tp = ns_job_get_tp(job);

-     /* 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.

-      */

-     pthread_mutex_lock(&(c->c_mutex));

-     ns_connection_post_io_or_closing(c);

-     pthread_mutex_unlock(&(c->c_mutex));

-     return;

- }

- 

  static int

  init_shutdown_detect(void)

  {
@@ -2497,10 +2095,8 @@ 

      (void)SIGNAL(SIGUSR1, slapd_do_nothing);

      (void)SIGNAL(SIGUSR2, set_shutdown);

  #endif

-     if (!enable_nunc_stans) {

-         (void)SIGNAL(SIGTERM, set_shutdown);

-         (void)SIGNAL(SIGHUP, set_shutdown);

-     }

+     (void)SIGNAL(SIGTERM, set_shutdown);

+     (void)SIGNAL(SIGHUP, set_shutdown);

  #endif /* HPUX */

      return 0;

  }
@@ -2928,9 +2524,6 @@ 

  static int

  createsignalpipe(void)

  {

-     if (enable_nunc_stans) {

-         return (0);

-     }

      if (PR_CreatePipe(&signalpipe[0], &signalpipe[1]) != 0) {

          PRErrorCode prerr = PR_GetError();

          slapi_log_err(SLAPI_LOG_ERR, "createsignalpipe",

file modified
+1 -1
@@ -116,7 +116,7 @@ 

   */

  int signal_listner(void);

  int daemon_pre_setuid_init(daemon_ports_t *ports);

- void slapd_daemon(daemon_ports_t *ports, ns_thrpool_t *tp);

+ void slapd_daemon(daemon_ports_t *ports);

  void daemon_register_connection(void);

  int slapd_listenhost2addr(const char *listenhost, PRNetAddr ***addr);

  int daemon_register_reslimits(void);

file modified
+1 -151
@@ -115,149 +115,6 @@ 

  static int slapd_debug_level_string2level(const char *s);

  static void slapd_debug_level_log(int level);

  static void slapd_debug_level_usage(void);

- /*

-  * global variables

-  */

- 

- struct ns_job_t *ns_signal_job[6];

- 

- /*

-  * Nunc stans logging function.

-  */

- static void

- nunc_stans_logging(int severity, const char *format, va_list varg)

- {

-     va_list varg_copy;

-     int loglevel = SLAPI_LOG_ERR;

- 

-     if (severity == LOG_DEBUG) {

-         loglevel = SLAPI_LOG_NUNCSTANS;

-     } else if (severity == LOG_INFO) {

-         loglevel = SLAPI_LOG_CONNS;

-     }

- 

-     va_copy(varg_copy, varg);

-     slapi_log_error_ext(loglevel, "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_memalign(size_t size, size_t alignment)

- {

-     return (void *)slapi_ch_memalign(size, alignment);

- }

- 

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

- }

- 

- static void

- ns_set_user(struct ns_job_t *job __attribute__((unused)))

- {

-     /* This literally does nothing. We intercept user signals (USR1, USR2) */

-     /* Could be good for a status output, or an easter egg. */

-     return;

- }

- 

- static void

- ns_set_shutdown(struct ns_job_t *job)

- {

-     /* Is there a way to make this a bit more atomic? */

-     /* I think NS protects this by only executing one signal job at a time */

-     if (g_get_shutdown() == 0) {

-         g_set_shutdown(SLAPI_SHUTDOWN_SIGNAL);

- 

-         /* Signal all the worker threads to stop */

-     }

-     ns_thrpool_shutdown(ns_job_get_tp(job));

- }

- 

- 

- /*

-  * Setup our nunc-stans worker pool from our config.

-  * we must have read dse.ldif before this point.

-  */

- 

- static int_fast32_t

- main_create_ns(ns_thrpool_t **tp_in)

- {

-     if (!config_get_enable_nunc_stans()) {

-         return 1;

-     }

-     struct ns_thrpool_config tp_config;

- 

-     int32_t maxthreads = (int32_t)config_get_threadnumber();

-     /* Set the nunc-stans thread pool config */

-     ns_thrpool_config_init(&tp_config);

- 

-     tp_config.max_threads = maxthreads;

-     tp_config.stacksize = SLAPD_DEFAULT_THREAD_STACKSIZE;

-     /* Highly likely that we need to re-write logging to be controlled by NS here. */

-     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.memalign_fct = nunc_stans_memalign;

-     tp_config.calloc_fct = nunc_stans_calloc;

-     tp_config.realloc_fct = nunc_stans_realloc;

-     tp_config.free_fct = nunc_stans_free;

- 

-     *tp_in = ns_thrpool_new(&tp_config);

- 

-     /* We mark these as persistent so they keep blocking signals forever. */

-     /* These *must* be in the event thread (ie not ns_job_thread) to prevent races */

-     ns_add_signal_job(*tp_in, SIGINT, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[0]);

-     ns_add_signal_job(*tp_in, SIGTERM, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[1]);

-     ns_add_signal_job(*tp_in, SIGTSTP, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[3]);

-     ns_add_signal_job(*tp_in, SIGHUP, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[2]);

-     ns_add_signal_job(*tp_in, SIGUSR1, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[4]);

-     ns_add_signal_job(*tp_in, SIGUSR2, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[5]);

-     return 0;

- }

- 

- static int_fast32_t

- main_stop_ns(ns_thrpool_t *tp)

- {

-     if (tp == NULL) {

-         return 0;

-     }

-     ns_thrpool_shutdown(tp);

-     ns_thrpool_wait(tp);

- 

-     /* Now we free the signal jobs. We do it late here to keep intercepting

-      * them for as long as possible .... Later we need to rethink this to

-      * have plugins and such destroy while the tp is still active.

-      */

-     ns_job_done(ns_signal_job[0]);

-     ns_job_done(ns_signal_job[1]);

-     ns_job_done(ns_signal_job[2]);

-     ns_job_done(ns_signal_job[3]);

-     ns_job_done(ns_signal_job[4]);

-     ns_job_done(ns_signal_job[5]);

-     ns_thrpool_destroy(tp);

- 

-     return 0;

- }

  

  /*

     Four cases:
@@ -666,7 +523,6 @@ 

  

      slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

      daemon_ports_t ports_info = {0};

-     ns_thrpool_t *tp = NULL;

  

  #ifdef LINUX

      char *m = getenv("SLAPD_MXFAST");
@@ -951,11 +807,6 @@ 

      }

  

      /*

-      * Create our thread pool here for tasks to utilise.

-      */

-     main_create_ns(&tp);

- 

-     /*

       * if we were called upon to do special database stuff, do it and be

       * done.

       */
@@ -1212,7 +1063,7 @@ 

  

      {

          starttime = slapi_current_utc_time();

-         slapd_daemon(&ports_info, tp);

+         slapd_daemon(&ports_info);

      }

      slapi_log_err(SLAPI_LOG_INFO, "main", "slapd stopped.\n");

      reslimit_cleanup();
@@ -1225,7 +1076,6 @@ 

      SSL_ClearSessionCache();

      ndn_cache_destroy();

      NSS_Shutdown();

-     main_stop_ns(tp);

      PR_Cleanup();

  

      /*

@@ -1497,9 +1497,6 @@ 

  void disk_mon_get_dirs(char ***list);

  int32_t disk_get_info(char *dir, uint64_t *total_space, uint64_t *avail_space, uint64_t *used_space);

  

- void ns_handle_pr_read_ready(struct ns_job_t *job);

- void ns_connection_post_io_or_closing(Connection *conn);

- 

  /*

   * main.c

   */

file modified
+3 -8
@@ -124,8 +124,6 @@ 

   */

  #include <pwd.h>

  

- #include <nunc-stans.h>

- 

  #ifdef WITH_SYSTEMD

  #ifdef HAVE_JOURNALD

  #include <systemd/sd-journal.h>
@@ -1651,9 +1649,6 @@ 

      PRInt32 c_threadnumber;          /* # threads used in this conn    */

      int c_refcnt;                    /* # ops refering to this conn    */

      pthread_mutex_t c_mutex;         /* protect each conn structure; need to be re-entrant */

-                                      /* Note that c_mutex is a pthreadmutex to allow sharing

-                                       * into nunc-stans.

-                                       */

      PRLock *c_pdumutex;              /* only write one pdu at a time   */

      time_t c_idlesince;              /* last time of activity on conn  */

      int c_idletimeout;               /* local copy of idletimeout */
@@ -1683,8 +1678,6 @@ 

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

      struct connection_table *c_ct;   /* connection table that this connection belongs to */

-     ns_thrpool_t *c_tp;              /* thread pool for this connection */

-     struct ns_job_t *c_job;          /* If it exists, the current ns_job_t */

      int c_ns_close_jobs;             /* number of current close jobs */

      char *c_ipaddr;                  /* ip address str - used by monitor */

      /* per conn static config */
@@ -2541,7 +2534,9 @@ 

      slapi_onoff_t cn_uses_dn_syntax_in_dns; /* indicates the cn value in dns has dn syntax */

      slapi_onoff_t global_backend_lock;

      slapi_int_t maxsimplepaged_per_conn; /* max simple paged results reqs handled per connection */

-     slapi_onoff_t enable_nunc_stans;

+     slapi_onoff_t enable_nunc_stans; /* Despite the removal of NS, we have to leave the value in

+                                       * case someone was setting it.

+                                       */

  #if defined(LINUX)

      int malloc_mxfast;         /* mallopt M_MXFAST */

      int malloc_trim_threshold; /* mallopt M_TRIM_THRESHOLD */

@@ -1,11 +0,0 @@ 

- # nunc-stans

- 

- Nunc Stans is an event framework wrapper that provides a thread pool for event callback execution. It provides thread safety to event frameworks by isolating and protecting the thread safe parts from the non-thread safe parts, and allows multi-threaded applications to use event frameworks that are not thread safe.

- 

- It has been primarily developed using http://libevent.org .

- 

- # Documentation

- 

- Nunc Stans uses doxygen to generate docs from the source. The generated docs are here: https://firstyear.fedorapeople.org/nunc-stans/index.html .

- 

- 

@@ -1,965 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- /*! \file nunc-stans.h

-     \brief Nunc Stans public API

- 

-     This is the public API for Nunc Stans

- */

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- #ifndef NS_THRPOOL_H

- /** \cond */

- #define NS_THRPOOL_H

- /** \endcond */

- 

- #include "nspr.h"

- 

- /**

-  * ns_result_t encapsulates the set of results that can occur when interacting

-  * with nunc_stans. This is better than a simple status, because we can indicate

-  * why a failure occured, and allow the caller to handle it gracefully.

-  */

- typedef enum _ns_result_t {

-     /**

-      * Indicate the operation succeded.

-      */

-     NS_SUCCESS = 0,

-     /**

-      * indicate that the event loop is shutting down, so we may reject operations.

-      */

-     NS_SHUTDOWN = 1,

-     /**

-      * We failed to allocate resources as needed.

-      */

-     NS_ALLOCATION_FAILURE = 2,

-     /**

-      * An invalid request was made to the API, you should probably check your

-      * call.

-      */

-     NS_INVALID_REQUEST = 3,

-     /**

-      * You made a request against a job that would violate the safety of the job

-      * state machine.

-      */

-     NS_INVALID_STATE = 4,

-     /**

-      * This occurs when a lower level OS issue occurs, generally thread related.

-      */

-     NS_THREAD_FAILURE = 5,

-     /**

-      * The job is being deleted

-      */

-     NS_DELETING = 6,

- } ns_result_t;

- 

- /**

-  * Forward declaration of the thread pool struct

-  *

-  * The actual struct is opaque to applications.  The forward declaration is here

-  * for the typedef.

-  */

- struct ns_thrpool_t;

- /**

-  * This is the thread pool typedef

-  *

-  * The actual thread pool is opaque to applications.

-  * \sa ns_thrpool_new, ns_thrpool_wait, ns_thrpool_destroy, ns_job_get_tp

-  */

- typedef struct ns_thrpool_t ns_thrpool_t;

- 

- /** \struct ns_job_t

-  * The nunc stans event and worker job object.

-  *

-  * When a new job is created, a pointer to a struct of this object type

-  * is returned.  This is the object that will be the argument to the job

-  * callback specified.  Since the struct is opaque, the functions ns_job_get_data(), ns_job_get_tp(),

-  * ns_job_get_type(), ns_job_get_fd(), and ns_job_get_output_type() can be used to get

-  * information about the job.  The function ns_job_done() must be used

-  * when the job should be freed.

-  * \sa ns_job_get_data, ns_job_get_fd, ns_job_get_tp, ns_job_get_type, ns_job_get_output_type

-  */

- struct ns_job_t;

- 

- /**

-  * The job callback function type

-  *

-  * Job callback functions must have a function signature of ns_job_func_t.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_add_timeout_job, ns_add_signal_job, ns_add_job

-  */

- typedef void (*ns_job_func_t)(struct ns_job_t *);

- 

- /**

-  * Flag for jobs that are not associated with an event.

-  *

-  * Use this flag when creating a job that you want to be run but

-  * not associated with an event.  Usually used in conjunction with

-  * ns_add_job() and #NS_JOB_THREAD to execute a function using the

-  * thread pool.

-  * \sa ns_add_job, NS_JOB_THREAD

-  */

- #define NS_JOB_NONE 0x0

- /**

-  * Flag for accept() jobs - new connection listeners

-  *

-  * Use this flag when creating jobs that listen for and accept

-  * new connections.  This is typically used in conjunction with

-  * the #NS_JOB_PERSIST flag so that the job does not have to be

-  * rearmed every time it is called.

-  *

-  * \code

-  *   struct ns_job_t *listenerjob;

-  *   PRFileDesc *listenfd = PR_OpenTCPSocket(...);

-  *   PR_Bind(listenfd, ...);

-  *   PR_Listen(listenfd, ...);

-  *   listenerctx = new_listenerctx(...); // the application context object

-  *   ns_add_io_job(threadpool, NS_JOB_ACCEPT|NS_JOB_PERSIST,

-  *                 accept_new_connection, listenerctx, &listenerjob);

-  * \endcode

-  * You will probably want to keep track of listenerjob and use it with

-  * ns_job_done() at application shutdown time to avoid leaking resources.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, NS_JOB_IS_ACCEPT, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_ACCEPT 0x1

- /**

-  * Flag for jobs that will use connect()

-  *

-  * When creating an I/O job, set this flag in the job_type to be notified

-  * when the file descriptor is available for outgoing connections.  In the

-  * job callback, use ns_job_get_output_type() and #NS_JOB_IS_CONNECT to

-  * see if the callback was called due to connect available if the callback is

-  * used with more than one of the job flags.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_CONNECT

-  */

- #define NS_JOB_CONNECT 0x2

- /**

-  * Flag for I/O read jobs

-  *

-  * When creating an I/O job, set this flag in the job_type to be notified

-  * when the file descriptor is available for reading.  In the

-  * job callback, use ns_job_get_output_type() and #NS_JOB_IS_READ to

-  * see if the callback was called due to read available if the callback is

-  * used with more than one of the job flags.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_READ

-  */

- #define NS_JOB_READ 0x4

- /**

-  * Flag for I/O write jobs

-  *

-  * When creating an I/O job, set this flag in the job_type to be notified

-  * when the file descriptor is available for writing.  In the

-  * job callback, use ns_job_get_output_type() and #NS_JOB_IS_WRITE to

-  * see if the callback was called due to write available if the callback is

-  * used with more than one of the job flags.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_WRITE

-  */

- #define NS_JOB_WRITE 0x8

- /**

-  * Flag for timer jobs

-  *

-  * When creating a timeout or I/O timeout job, set this flag in the job_type

-  * to be notified when the time given by the timeval argument has elapsed.

-  * In the job callback, use ns_job_get_output_type() and #NS_JOB_IS_TIMER to

-  * see if the callback was called due to elapsed time if the callback is

-  * used with more than one of the job flags.

-  * \sa ns_add_timeout_job, ns_add_io_timeout_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_TIMER

-  */

- #define NS_JOB_TIMER 0x10

- /**

-  * Flag for signal jobs

-  *

-  * When creating a signal job, set this flag in the job_type

-  * to be notified when the process receives the given signal.

-  * In the job callback, use ns_job_get_output_type() and #NS_JOB_IS_SIGNAL to

-  * see if the callback was called due to receiving the signal if the callback is

-  * used with more than one of the job flags.

-  * \sa ns_add_signal_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_SIGNAL

-  */

- #define NS_JOB_SIGNAL 0x20

- /**

-  * Flag to make jobs persistent

-  *

-  * By default, when an event (I/O, timer, signal) is triggered and

-  * the job callback is called, the event is removed from the event framework,

-  * and the application will no longer receive callbacks for events.  The

-  * application is then responsible for calling ns_job_rearm to "re-arm"

-  * the job to respond to the event again.  Adding the job with the

-  * #NS_JOB_PERSIST flag added to the job_type means the job will not have

-  * to be rearmed.  This is usually used in conjunction with #NS_JOB_ACCEPT

-  * for accept jobs.  Use ns_job_get_type() or ns_job_get_output_type() with

-  * #NS_JOB_IS_PERSIST to test if the job is persistent.

-  *

-  * \note Be very careful when using this flag in conjunction with #NS_JOB_THREAD.

-  * For example, for a #NS_JOB_ACCEPT job, once you call accept(), the socket

-  * may be immediately available for another accept, and your callback could be

-  * called again immediately in another thread.  Same for the other types of I/O

-  * jobs.  In that case, your job callback function must be thread safe - global

-  * resources must be protected with a mutex, the function must be reentrant, etc.

-  *

-  * \sa NS_JOB_ACCEPT, NS_JOB_THREAD, NS_JOB_IS_PERSIST, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_PERSIST 0x40

- /**

-  * Flag to make jobs run in a thread pool thread

-  *

-  * This flag allows you to specify if you want a job to run threaded or not.

-  * If the job is threaded, the job callback is executed by a thread in

-  * the thread pool, and the job callback function must be thread safe and

-  * reentrant.  If the job is not threaded, the job runs in the same thread

-  * as the event loop thread.

-  *

-  * \note When #NS_JOB_THREAD is \e not used, the job callback will be run in the

-  *       event loop thread, and will block all events from being processed.

-  *       Care must be taken to ensure that the job callback does not block.

-  *

-  * Use ns_job_get_type() or ns_job_get_output_type() with #NS_JOB_IS_THREAD to

-  * test if the job is threaded.

-  *

-  * \sa NS_JOB_IS_THREAD, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_THREAD 0x80

- /**

-  * Flag to tell ns_job_done() not to close the job fd

-  *

-  * I/O jobs will have a file descriptor (fd). If the job->fd lifecycle

-  * is managed by the application, this flag tells ns_job_done() not to close

-  * the fd.

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_job_get_type, ns_job_get_output_type, NS_JOB_IS_PRESERVE_FD

-  */

- #define NS_JOB_PRESERVE_FD 0x100

- /**

-  * Internal flag to shutdown a worker thread.

-  *

-  * If you assign this to a job it will cause the worker thread that dequeues it to be

-  * shutdown, ready for pthread_join() to be called on it.

-  *

-  * You probably DON'T want to use this ever, as it really will shutdown threads

-  * and you can't get them back .... you have been warned.

-  */

- #define NS_JOB_SHUTDOWN_WORKER 0x200

- /**

-  * Bitflag type for job types

-  *

-  * This is the job_type bitfield argument used when adding jobs, and the return

-  * value of the functions ns_job_get_type() and ns_job_get_output_type().  The

-  * value is one or more of the NS_JOB_* macros OR'd together.

-  * \code

-  *   ns_job_type_t job_type = NS_JOB_READ|NS_JOB_SIGNAL;

-  * \endcode

-  * When used with ns_job_get_type() or ns_job_get_output_type() to see what type

-  * of job it is, use the return value with one of the NS_JOB_IS_* macros:

-  * \code

-  *   if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-  *     // handle timeout

-  *   }

-  * \endcode

-  * \sa ns_add_io_job, ns_add_io_timeout_job, ns_add_job, ns_add_signal_job, ns_add_timeout_job, ns_job_get_type, ns_job_get_output_type

-  */

- typedef uint_fast16_t ns_job_type_t;

- 

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_ACCEPT

-  * \sa NS_JOB_ACCEPT, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_ACCEPT(eee) ((eee)&NS_JOB_ACCEPT)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_READ

-  * \sa NS_JOB_READ, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_READ(eee) ((eee)&NS_JOB_READ)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_CONNECT

-  * \sa NS_JOB_CONNECT, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_CONNECT(eee) ((eee)&NS_JOB_CONNECT)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_WRITE

-  * \sa NS_JOB_WRITE, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_WRITE(eee) ((eee)&NS_JOB_WRITE)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_TIMER

-  * \sa NS_JOB_TIMER, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_TIMER(eee) ((eee)&NS_JOB_TIMER)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_SIGNAL

-  * \sa NS_JOB_SIGNAL, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_SIGNAL(eee) ((eee)&NS_JOB_SIGNAL)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_PERSIST

-  * \sa NS_JOB_PERSIST, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_PERSIST(eee) ((eee)&NS_JOB_PERSIST)

- /**

-  * Used to test if an #ns_job_type_t is to shutdown the worker thread.

-  */

- #define NS_JOB_IS_SHUTDOWN_WORKER(eee) ((eee)&NS_JOB_SHUTDOWN_WORKER)

- /**

-  * Used to test an #ns_job_type_t value to see if it is any sort of I/O job

-  * \sa NS_JOB_IS_ACCEPT, NS_JOB_IS_READ, NS_JOB_IS_CONNECT, NS_JOB_IS_WRITE, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_IO(eee) (NS_JOB_IS_ACCEPT(eee) || NS_JOB_IS_READ(eee) || NS_JOB_IS_CONNECT(eee) || NS_JOB_IS_WRITE(eee))

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_THREAD

-  * \sa NS_JOB_THREAD, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_THREAD(eee) ((eee)&NS_JOB_THREAD)

- /**

-  * Used to test an #ns_job_type_t value for #NS_JOB_PRESERVE_FD

-  * \sa NS_JOB_PRESERVE_FD, ns_job_get_type, ns_job_get_output_type

-  */

- #define NS_JOB_IS_PRESERVE_FD(eee) ((eee)&NS_JOB_PRESERVE_FD)

- 

- /**

-  * Used to set an #ns_job_type_t value to have #NS_JOB_READ

-  */

- #define NS_JOB_SET_READ(eee) ((eee) |= NS_JOB_READ)

- /**

-  * Used to set an #ns_job_type_t value to have #NS_JOB_WRITE

-  */

- #define NS_JOB_SET_WRITE(eee) ((eee) |= NS_JOB_WRITE)

- /**

-  * Used to set an #ns_job_type_t value to have #NS_JOB_THREAD

-  */

- #define NS_JOB_SET_THREAD(eee) ((eee) |= NS_JOB_THREAD)

- /**

-  * Remove #NS_JOB_READ from an #ns_job_type_t value

-  */

- #define NS_JOB_UNSET_READ(eee) ((eee) &= ~NS_JOB_READ)

- /**

-  * Remove #NS_JOB_WRITE from an #ns_job_type_t value

-  */

- #define NS_JOB_UNSET_WRITE(eee) ((eee) &= ~NS_JOB_WRITE)

- /**

-  * Remove #NS_JOB_THREAD from an #ns_job_type_t value

-  */

- #define NS_JOB_UNSET_THREAD(eee) ((eee) &= ~NS_JOB_THREAD)

- 

- /**

-  * Used to configure the thread pool

-  *

-  * This is the argument to ns_thrpool_new().  This is used to set all of the

-  * configuration parameters for the thread pool.

-  *

-  * This must be initialized using ns_thrpool_config_init().  This will

-  * initialize the fields to their default values.  Use like this:

-  * \code

-  *   struct ns_thrpool_config nsconfig;

-  *   ns_thrpool_config_init(&nsconfig);

-  *   nsconfig.max_threads = 16;

-  *   nsconfig.malloc_fct = mymalloc;

-  *   ...

-  *   rc = ns_thrpool_new(&nsconfig);

-  * \endcode

-  * \sa ns_thrpool_config_init, ns_thrpool_new

-  */

- struct ns_thrpool_config

- {

-     /** \cond */

-     int32_t init_flag;

-     /** \endcond */

-     size_t max_threads; /**< Do not grow the thread pool greater than this size */

-     size_t stacksize;   /**< Thread stack size */

- 

-     /* pluggable logging functions  */

-     void (*log_fct)(int, const char *, va_list); /**< Provide a function that works like vsyslog */

-     void (*log_start_fct)(void);                 /**< Function to call to initialize the logging system */

-     void (*log_close_fct)(void);                 /**< Function to call to shutdown the logging system */

- 

-     /* pluggable memory functions */

-     void *(*malloc_fct)(size_t);                          /**< malloc() replacement */

-     void *(*memalign_fct)(size_t size, size_t alignment); /**< posix_memalign() replacement. Note the argument order! */

-     void *(*calloc_fct)(size_t, size_t);                  /**< calloc() replacement */

-     void *(*realloc_fct)(void *, size_t);                 /**< realloc() replacement */

-     void (*free_fct)(void *);                             /**< free() replacement */

- };

- 

- /**

-  * Initialize a thrpool config struct

-  *

-  * The config struct must be allocated/freed by the caller.  A stack

-  * variable is typically used.

-  * \code

-  *   struct ns_thrpool_config nsconfig;

-  *   ns_thrpool_config_init(&nsconfig);

-  *   nsconfig.max_threads = 16;

-  *   nsconfig.malloc_fct = mymalloc;

-  *   ...

-  *   rc = ns_thrpool_new(&nsconfig);

-  * \endcode

-  * \sa ns_thrpool_config, ns_thrpool_new

-  * \param tp_config - thread pool config struct

-  */

- void ns_thrpool_config_init(struct ns_thrpool_config *tp_config);

- 

- /**

-  * The application is finished with this job

-  *

-  * The application uses this function to tell nunc-stans that it is finished

-  * using this job.  Once the application calls this function, it may no

-  * longer refer to job - it should be considered as an allocated pointer

-  * that the free() function has been called with.  An application will

-  * typically call ns_job_done() at the end of a job callback function for

-  * non-persistent jobs (not using #NS_JOB_PERSIST), or at application

-  * shutdown time for persistent jobs (using #NS_JOB_PERSIST).  For an I/O job,

-  * ns_job_done will close() the file descriptor associated with the job unless

-  * the #NS_JOB_PRESERVE_FD is specified when the job is added.

-  *

-  * Note that a persistant job can only disarm/ns_job_done() itself, unless the

-  * threadpool is in shutdown, then external threads may request the job to be marked

-  * as done(). This is to protect from a set of known race conditions that may occur.

-  *

-  * All jobs *must* have ns_job_done() called upon them to clean them correctly. Failure

-  * to do so may cause resource leaks.

-  *

-  * \code

-  *   void read_callback(struct ns_job_t *job)

-  *   {

-  *       appctx_t *appctx = (appctx_t *)ns_job_get_data(job);

-  *       ...

-  *       ns_job_done(job);

-  *       // ok to use appctx here, but not job

-  *       // app must free or ensure appctx is not leaked

-  *       return;

-  *   }

-  * \endcode

-  * \param job the job to clean up

-  * \retval NS_SUCCESS Job was successfully queued for removal.

-  * \retval NS_INVALID_STATE Failed to mark job for removal. Likely the job is ARMED!

-  *    We cannot remove jobs that are armed due to the race conditions it can cause.

-  * \retval NS_INVALID_REQUEST No job was provided to remove (IE NULL request)

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_PERSIST, NS_JOB_PRESERVE_FD

-  */

- ns_result_t ns_job_done(struct ns_job_t *job);

- 

- /**

-  * Create a new job which is not yet armed.

-  *

-  * Specify the type of job using the job_type bitfield.  You can specify

-  * more than one type of job.

-  *

-  * The callback will need to rearm the job or add another job if it wants to

-  * be notified of more events.

-  *

-  * This job is not armed at creation unlike other ns_add_*_job. This means that

-  * after the job is created, you can use ns_job_set_*, and when ready, arm the job.

-  *

-  * \code

-  *   struct ns_job_t *job;

-  *   ns_create_job(tp, NS_JOB_READ, my_callback, &job);

-  *   ns_job_set_data(job, data);

-  *   // You may not alter job once it is armed.

-  *   ns_job_rearm(job);

-  * \endcode

-  *

-  * \param tp The thread pool you want to add an I/O job to.

-  * \param job_type A set of flags that indicates the job type.

-  * \param func The callback function to call when processing the job.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \retval NS_INVALID_REQUEST As create job does not create armed, if you make a request

-  *  with a NULL job parameter, this would create a memory leak. As a result, we fail if

-  *  the request is NULL.

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return PR_FAILURE in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_READ, NS_JOB_WRITE, NS_JOB_ACCEPT, NS_JOB_CONNECT, NS_JOB_IS_IO, ns_job_done

-  */

- ns_result_t

- ns_create_job(struct ns_thrpool_t *tp, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_t **job);

- 

- /**

-  * Adds an I/O job to the thread pool

-  *

-  * Specify the type of I/O job using the job_type bitfield.  You can specify

-  * more than one type of I/O job.  Use ns_job_get_output_type(job) to

-  * determine which event triggered the I/O.

-  * \code

-  *   ns_add_io_job(tp, fd, NS_JOB_READ|NS_JOB_WRITE, my_io_callback, ...);

-  *   ...

-  *   void my_io_callback(struct ns_job_t *job)

-  *   {

-  *       if (NS_JOB_IS_READ(ns_job_get_output_type(job))) {

-  *           // handle reading from fd

-  *       } else {

-  *           // handle writing to fd

-  *       }

-  *   }

-  * \endcode

-  * The callback will need to rearm the job or add another job if it wants to

-  * be notified of more events, or use #NS_JOB_PERSIST.  If you want an I/O job

-  * that will timeout if I/O is not detected within a certain period of time,

-  * use ns_add_io_timeout_job().

-  * \param tp The thread pool you want to add an I/O job to.

-  * \param fd The file descriptor to use for I/O.

-  * \param job_type A set of flags that indicates the job type.

-  * \param func The callback function to call when processing the job.

-  * \param data Arbitrary data that will be available to the job callback function.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  *            \c NULL can be passed if a pointer to the job is not needed.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \retval NS_INVALID_REQUEST An invalid job request was made: likely you asked for an

-  * accept job to be threaded, which is currently invalid.

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return PR_FAILURE in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_READ, NS_JOB_WRITE, NS_JOB_ACCEPT, NS_JOB_CONNECT, NS_JOB_IS_IO, ns_job_done

-  */

- ns_result_t ns_add_io_job(struct ns_thrpool_t *tp,

-                           PRFileDesc *fd,

-                           ns_job_type_t job_type,

-                           ns_job_func_t func,

-                           void *data,

-                           struct ns_job_t **job);

- 

- /**

-  * Adds a timeout job to the thread pool

-  *

-  * The func function will be called when the timer expires.

-  *

-  * \param tp The thread pool you want to add a timeout job to.

-  * \param tv The timer that needs to expire before triggering the callback function.

-  * \param job_type A set of flags that indicates the job type - #NS_JOB_TIMER + other flags

-  * \param func The callback function to call when processing the job.

-  * \param data Arbitrary data that will be available to the job callback function.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  *            \c NULL can be passed if a pointer to the job is not needed.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \retval NS_INVALID_REQUEST An invalid job request was made: likely you asked for a

-  * timeout that is not valid (negative integer).

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return PR_FAILURE in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_TIMER, NS_JOB_IS_TIMER, ns_job_done

-  */

- ns_result_t ns_add_timeout_job(struct ns_thrpool_t *tp,

-                                struct timeval *tv,

-                                ns_job_type_t job_type,

-                                ns_job_func_t func,

-                                void *data,

-                                struct ns_job_t **job);

- 

- /**

-  * Adds an I/O job to the thread pool's work queue with a timeout.

-  *

-  * The callback func function should test the type of event that triggered

-  * the callback using ns_job_get_output_type(job) to get the

-  * #ns_job_type_t, then use #NS_JOB_IS_TIMER(output_type) to see if

-  * this callback was triggered by a timer event.  This is useful if

-  * you want to perform some sort of I/O, but you require that I/O

-  * must happen in a certain amount of time.

-  * \code

-  *   ns_add_io_timeout_job(tp, fd, &tv, NS_JOB_READ|NS_JOB_TIMER, my_iot_callback, ...);

-  *   ...

-  *   void my_iot_callback(struct ns_job_t *job)

-  *   {

-  *       if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-  *           // handle timeout condition

-  *       } else {

-  *           // handle read from fd

-  *       }

-  *   }

-  * \endcode

-  * \note This is like adding an I/O job, with an optional timeout.

-  * This is not like adding a timeout job with an additional I/O

-  * event component.  This depends on the underlying event framework

-  * having the ability to have a timed I/O job.  For example, libevent

-  * I/O events can have a timeout.

-  *

-  * \param tp The thread pool whose work queue you want to add an I/O job to.

-  * \param fd The file descriptor to use for I/O.

-  * \param tv The timer that needs to expire before triggering the callback function.

-  * \param job_type A set of flags that indicates the job type.

-  * \param func The callback function for a worker thread to call when processing the job.

-  * \param data Arbitrary data that will be available to the job callback function.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  *            \c NULL can be passed if a pointer to the job is not needed.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \retval NS_INVALID_REQUEST An invalid job request was made: likely you asked for a

-  * timeout that is not valid (negative integer). Another failure is you requested a

-  * threaded accept job.

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return NS_SHUTDOWN in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_READ, NS_JOB_WRITE, NS_JOB_ACCEPT, NS_JOB_CONNECT, NS_JOB_IS_IO, ns_job_done, NS_JOB_TIMER, NS_JOB_IS_TIMER

-  */

- ns_result_t ns_add_io_timeout_job(struct ns_thrpool_t *tp,

-                                   PRFileDesc *fd,

-                                   struct timeval *tv,

-                                   ns_job_type_t job_type,

-                                   ns_job_func_t func,

-                                   void *data,

-                                   struct ns_job_t **job);

- 

- /**

-  * Adds a signal job to the thread pool

-  *

-  * The \a func function will be called when the signal is received by the process.

-  *

-  * \param tp The thread pool you want to add a signal job to.

-  * \param signum The signal number that you want to trigger the callback function.

-  * \param job_type A set of flags that indicates the job type.

-  * \param func The callback function to call when processing the job.

-  * \param data Arbitrary data that will be available to the job callback function.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  *            \c NULL can be passed if a pointer to the job is not needed.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return PR_FAILURE in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_SIGNAL, NS_JOB_IS_SIGNAL

-  */

- ns_result_t ns_add_signal_job(ns_thrpool_t *tp,

-                               int32_t signum,

-                               ns_job_type_t job_type,

-                               ns_job_func_t func,

-                               void *data,

-                               struct ns_job_t **job);

- 

- /**

-  * Add a non-event related job to the thread pool

-  *

-  * A non-event related job is a job that is executed immediately that is not contingent

-  * on an event or signal.  This is typically used when the application wants to do some

-  * processing in parallel using a thread from the thread pool.

-  * \code

-  *   ns_add_job(tp, NS_JOB_NONE|NS_JOB_THREAD, my_callback, ...);

-  *   ...

-  *   void my_callback(struct ns_job_t *job)

-  *   {

-  *      // now in a separate thread

-  *   }

-  * \endcode

-  *

-  * \param tp The thread pool you want to add the job to.

-  * \param job_type A set of flags that indicates the job type (usually just NS_JOB_NONE|NS_JOB_THREAD)

-  * \param func The callback function to call when processing the job.

-  * \param data Arbitrary data that will be available to the job callback function.

-  * \param[out] job The address of a job pointer that will be filled in once the job is allocated.

-  *            \c NULL can be passed if a pointer to the job is not needed.

-  * \retval NS_SUCCESS Job was successfully added.

-  * \retval NS_ALLOCATION_FAILURE Failed to allocate job.

-  * \warning The thread pool will not allow a job to be added when it has been signaled

-  *          to shutdown.  It will return PR_FAILURE in that case.

-  * \sa ns_job_t, ns_job_get_data, NS_JOB_NONE, NS_JOB_THREAD

-  */

- ns_result_t ns_add_job(ns_thrpool_t *tp, ns_job_type_t job_type, ns_job_func_t func, void *data, struct ns_job_t **job);

- 

- /**

-  * Allows the callback to access the file descriptor for an I/O job

-  *

-  * \code

-  *   void my_io_job_callback(struct ns_job_t *job)

-  *   {

-  *       PRFileDesc *fd = ns_job_get_fd(job);

-  *       rc = PR_Read(fd, ...);

-  *       ...

-  *   }

-  * \endcode

-  * If the job is not an I/O job, the function will return NULL.

-  *

-  * \param job The job to get the fd for.

-  * \retval fd The file descriptor associated with the I/O job.

-  * \retval NULL The job is not an I/O job

-  * \sa ns_job_t, ns_add_io_job, ns_add_io_timeout_job

-  */

- PRFileDesc *ns_job_get_fd(struct ns_job_t *job);

- 

- /**

-  * Allows the callback to access the private data field in the job.

-  *

-  * This is the \c data field passed in when the job is added.  This

-  * data is private to the application - nunc-stans does not touch it

-  * in any way.  The application is responsible for managing the lifecycle

-  * of this data.

-  * \code

-  *   void my_job_callback(struct ns_job_t *job)

-  *   {

-  *       myappctx_t *myappctx = (myappctx_t *)ns_job_get_data(job);

-  *       ...

-  *   }

-  * \endcode

-  *

-  * \param job The job to get the data for.

-  * \return The private data associated with the job.

-  * \sa ns_job_t

-  */

- void *ns_job_get_data(struct ns_job_t *job);

- 

- /**

-  * Allows the caller to set private data into the job

-  * Care should be taken to make sure that the previous contents are

-  * freed, or that the data is freed after use. Leaks will be annoying to track

-  * down with this!

-  *

-  * This sets the \c data field. This data is private to the application - nunc-stans

-  * will not touch it in any way.

-  * \code

-  *   void my_job_callback(struct ns_job_t *job)

-  *   {

-  *      myappctx_t *myappctx = malloc(sizeof(struct appctx));

-  *      ...

-  *      // You must check and *free* the data if required.

-  *      // Else you may introduce a memory leak!

-  *      void *data = ns_job_get_data(job);

-  *      if (data != NULL) {

-  *          myapp_use_data(data);

-  *          ...

-  *      }

-  *      free(data);

-  *      if (ns_job_set_data(job, (void *)myappctx) == PR_SUCCESS) {

-  *          //handle the error, you probably have a bug ....

-  *      }

-  *   }

-  * \endcode

-  *

-  * \param job The job to set the data for

-  * \param data The void * pointer to the data to set

-  * \retval NS_SUCCESS Job was modified correctly.

-  * \retval NS_INVALID_STATE Failed to modify the job as this may be unsafe.

-  * \sa ns_job_t

-  */

- ns_result_t ns_job_set_data(struct ns_job_t *job, void *data);

- 

- /**

-  * Allows the callback to access the job type flags.

-  *

-  * Usually used in conjunction with one of the NS_JOB_IS_* macros.

-  *

-  * \code

-  *   void my_job_callback(struct ns_job_t *job)

-  *   {

-  *       if (NS_JOB_IS_READ(ns_job_get_type(job)) {

-  *       ...

-  *       }

-  *   }

-  * \endcode

-  * \param job The job to get the type for.

-  * \return The #ns_job_type_t flags for the job

-  * \sa ns_job_t, NS_JOB_IS_READ, NS_JOB_IS_WRITE, NS_JOB_IS_IO, NS_JOB_IS_TIMER

-  */

- ns_job_type_t ns_job_get_type(struct ns_job_t *job);

- 

- /**

-  * Allows the callback to access the thread pool that the job is associated with.

-  *

-  * Useful for adding jobs from within job callbacks.

-  *

-  * \code

-  *   void my_job_callback(struct ns_job_t *job)

-  *   {

-  *      // do some work

-  *      // need to listen for some events

-  *      ns_add_io_job(ns_job_get_tp(job), fd, ...);

-  *      // finished with job

-  *      ns_job_done(job);

-  *      return;

-  *   }

-  * \endcode

-  * \param job The job to get the thread pool for.

-  * \return The thread pool associated with the job.

-  * \sa ns_job_t, ns_add_io_job

-  */

- ns_thrpool_t *ns_job_get_tp(struct ns_job_t *job);

- 

- /**

-  * Allows the callback to know which event triggered the callback. Can only be called from within the callback itself.

-  *

-  * The callback func may need to know which event triggered the

-  * callback.  This function will allow access to the type of event

-  * that triggered the callback.  For example, when using

-  * ns_add_io_timeout_job(), the callback can be called either because of

-  * an I/O event or a timer event.  Use #NS_JOB_IS_TIMER to tell if

-  * the event is a timer event, like this:

-  * \code

-  *   if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-  *      ... handle timeout ...

-  *   } else {

-  *      ... handle I/O ...

-  *   }

-  * \endcode

-  * \param job The job to get the output type for.

-  * \return The #ns_job_type_t corresponding to the event that triggered the callback

-  * \sa ns_job_t, NS_JOB_IS_TIMER, NS_JOB_IS_READ, NS_JOB_IS_WRITE, NS_JOB_IS_IO, ns_add_io_timeout_job

-  */

- ns_job_type_t ns_job_get_output_type(struct ns_job_t *job);

- 

- /**

-  * Allows setting the job done callback.

-  *

-  * The job done callback will be triggered when ns_job_done is called on the

-  * job. This allows jobs to have private data fields cleaned and freed correctly

-  * \code

-  *  ns_create_job(tp, NS_JOB_READ, my_callback, &job);

-  *  if (ns_job_set_done_cb(job, my_done_callback) != PR_SUCCESS) {

-  *      // you must handle this error!!!! the cb did not set!

-  *  }

-  *  ns_job_rearm(job);

-  *  ...

-  *  void my_done_callback(struct ns_job_t job) {

-  *      free(ns_job_get_data(job));

-  *  }

-  * \endcode

-  * \param job The job to set the callback for.

-  * \param func The callback function, to be called when ns_job_done is triggered.

-  * \retval NS_SUCCESS Job was modified correctly.

-  * \retval NS_INVALID_STATE Failed to modify the job as this may be unsafe.

-  * \sa ns_job_t, ns_job_done

-  */

- ns_result_t ns_job_set_done_cb(struct ns_job_t *job, ns_job_func_t func);

- 

- /**

-  * Block until a job is completed. This returns the next state of the job as as a return.

-  *

-  * \param job The job to set the callback for.

-  * \retval ns_job_state_t The next state the job will move to. IE, WAITING, DELETED, ARMED.

-  */

- ns_result_t ns_job_wait(struct ns_job_t *job);

- 

- /**

-  * Creates a new thread pool

-  *

-  * Must be called with a struct ns_thrpool_config that has been

-  * initialized by ns_thrpool_config_init().  Typically, once the

-  * thread pool has been created, one or more listener jobs or

-  * other long lived jobs will be added, and the application will

-  * just call ns_thrpool_wait().  The application should add at least

-  * one job that will listen for shutdown events, signals, etc. which

-  * will call ns_thrpool_shutdown().  After ns_thrpool_wait() returns,

-  * the application should use ns_job_done() to finish any long-lived

-  * jobs, then call ns_thrpool_destroy().

-  * \param config A pointer to a struct ns_thrpool_config

-  * \return A pointer to the newly created thread pool.

-  * \sa ns_thrpool_config, ns_thrpool_config_init, ns_thrpool_wait, ns_thrpool_shutdown, ns_thrpool_destroy

-  */

- struct ns_thrpool_t *ns_thrpool_new(struct ns_thrpool_config *config);

- 

- /**

-  * Frees a thread pool from memory

-  *

-  * This will free a thread pool and it's internal resources from memory.  You should

-  * be sure that the thread pool has been shutdown before destroying it by calling

-  * ns_thrpool_wait(), then call ns_job_done() to finish any long-lived jobs.  After

-  * calling ns_thrpool_destroy(), do not use tp.

-  *

-  * \param tp The thread pool to destroy.

-  * \sa ns_thrpool_config, ns_thrpool_config_init, ns_thrpool_new, ns_thrpool_wait, ns_thrpool_shutdown

-  */

- void ns_thrpool_destroy(struct ns_thrpool_t *tp);

- 

- /**

-  * Tells a thread pool to shutdown its threads

-  *

-  * The application will usually call ns_thrpool_shutdown() from an event

-  * callback that is listening for shutdown events e.g. a signal job that

-  * is listening for SIGINT or SIGTERM events.

-  * \code

-  *   tp = ns_thrpool_new(...);

-  *   ns_add_signal_job(tp, SIGTERM, handle_shutdown_signal, NS_JOB_SIGNAL|NS_JOB_THREAD, ...);

-  *

-  *   void handle_shutdown_signal(job)

-  *   {

-  *     ns_thrpool_shutdown(ns_job_get_tp(job));

-  *     // set application shutdown flag

-  *     return;

-  *   }

-  * \endcode

-  * Use NS_JOB_SIGNAL|NS_JOB_THREAD so that the job will run in a worker thread, not

-  * in the event loop thread.

-  * \note The application must call ns_thrpool_shutdown() or ns_thrpool_wait() will

-  *       never return.

-  *

-  * \param tp The thread pool to shutdown.

-  * \warning This must only be called from a job that runs in a worker thread.  Calling

-  *          this function from the event thread can cause a deadlock.

-  * \sa ns_thrpool_config, ns_thrpool_config_init, ns_thrpool_new, ns_thrpool_wait, ns_thrpool_destroy, ns_add_signal_job, NS_JOB_THREAD

-  */

- void ns_thrpool_shutdown(struct ns_thrpool_t *tp);

- 

- /**

-  * Checks if a thread pool is shutting down

-  *

-  * This can be called by worker threads so they know when the thread pool has

-  * been requested to shut down.

-  *

-  * \retval 0 if the thread pool is not shutting down.

-  * \retval 1 if the thread pool is shutting down.

-  * \sa ns_thrpool_shutdown

-  */

- int32_t ns_thrpool_is_shutdown(struct ns_thrpool_t *tp);

- 

- /**

-  * Waits for all threads in the pool to exit

-  *

-  * This call will block the caller until all threads in the thread pool have exited.  A

-  * program will typically create the thread pool by calling ns_thrpool_new(), then it

-  * will call ns_thrpool_wait() to wait until the thread pool is shutdown (which is likely

-  * initiated by a signal handler).  Once this function successfully returns, the thread

-  * pool can be safely destroyed by calling ns_thrpool_destroy().

-  * \note The application must call ns_thrpool_shutdown() or ns_thrpool_wait() will

-  *       never return.

-  *

-  * \param tp The thread pool to wait for.

-  * \retval NS_SUCCESS The thread pool threads completed successfully

-  * \retval NS_THREAD_FAILURE Failure waiting for a thread to rejoin.

-  * \sa ns_thrpool_config, ns_thrpool_config_init, ns_thrpool_new, ns_thrpool_destroy, ns_thrpool_shutdown

-  */

- ns_result_t ns_thrpool_wait(struct ns_thrpool_t *tp);

- 

- 

- /**

-  * Convenience function to re-arm the same job

-  *

-  * This is used for non-persistent (not using #NS_JOB_PERSIST) jobs.

-  * For example, if you have an I/O reading job, and the job needs to read more data,

-  * the job callback can just call ns_job_rearm(), and the job callback will be

-  * called again when read is ready on the job fd.  Once this function is called,

-  * the job callback may be called immediately if the job uses #NS_JOB_THREAD.  Do not

-  * refer to job after calling ns_job_rearm().

-  * \note Do not call ns_job_done() with a job if using ns_job_rearm() with the job

-  * \param job The job to re-arm

-  * \retval NS_SUCCESS The job was queued correctly.

-  * \retval NS_SHUTDOWN The job was not able to be queued as the server is in the procees

-  * of shutting down.

-  * \retval NS_INVALID_STATE The job was not able to be queued as it is in an invalid state

-  * \retval NS_INVALID_REQUEST The job to be queued is invalid.

-  * \sa ns_job_t, ns_job_done, NS_JOB_PERSIST, NS_JOB_THREAD

-  */

- ns_result_t ns_job_rearm(struct ns_job_t *job);

- 

- int

- ns_job_is_func(struct ns_job_t *job, ns_job_func_t func);

- 

- #endif /* NS_THRPOOL_H */

@@ -1,180 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #ifndef NS_EVENT_FW_H

- #define NS_EVENT_FW_H

- 

- #include "ns_private.h"

- 

- /* For locks and cond var */

- #include <pthread.h>

- 

- struct ns_event_fw_ctx_t;

- struct ns_event_fw_fd_t;

- struct ns_event_fw_time_t;

- struct ns_event_fw_sig_t;

- 

- #ifndef NO_EVENT_TYPEDEFS

- typedef struct ns_event_fw_ctx_t ns_event_fw_ctx_t;

- typedef struct ns_event_fw_fd_t ns_event_fw_fd_t;

- typedef struct ns_event_fw_time_t ns_event_fw_time_t;

- typedef struct ns_event_fw_sig_t ns_event_fw_sig_t;

- #endif

- 

- /*

-  * The states we can have for a job.

-  * We start in WAITING. Valid transitions are:

-  * // With waiting, *any* thread can change this. Prevents races.

-  * WAITING -> NEEDS_DELETE

-  * WAITING -> NEEDS_ARM

-  * NEEDS_ARM -> ARMED

-  * NEEDS_ARM -> NEEDS_DELETE

-  * ARMED -> RUNNING

-  * When a job is ARMED, and tp->shutdown 1, it CAN move to NEEDS_DELETE

-  * ARMED -> NEEDS_DELETE // Only by shutdown of event loop

-  * // The trick with RUNNING is that only the current thread working thread can change this!

-  * RUNNING -> NEEDS_DELETE

-  * RUNNING -> NEEDS_ARM

-  * RUNNING -> WAITING

-  * NEEDS_DELETE -> DELETED

-  */

- 

- typedef enum _ns_job_state {

-     NS_JOB_NEEDS_DELETE = 2,

-     NS_JOB_DELETED = 3,

-     NS_JOB_NEEDS_ARM = 4,

-     NS_JOB_ARMED = 5,

-     NS_JOB_RUNNING = 6,

-     NS_JOB_WAITING = 7,

- } ns_job_state_t;

- 

- /* this is our "kitchen sink" pblock/glue object that is the main

-    interface between the app/thread pool/event framework */

- typedef struct ns_job_t

- {

-     pthread_mutex_t monitor;

-     pthread_cond_t notify;

-     struct ns_thrpool_t *tp;

-     ns_job_func_t func;

-     struct ns_job_data_t *data;

-     ns_job_type_t job_type;               /* NS_JOB_ACCEPT etc. */

-     PRFileDesc *fd;                       /* for I/O events */

-     struct timeval tv;                    /* used for timed events */

-     int signal;                           /* if the event was triggered by a signal, this is the signal number */

-     ns_event_fw_fd_t *ns_event_fw_fd;     /* event framework fd event object */

-     ns_event_fw_time_t *ns_event_fw_time; /* event framework timer event object */

-     ns_event_fw_sig_t *ns_event_fw_sig;   /* event framework signal event object */

-     ns_job_type_t output_job_type;        /* info about event that triggered the callback */

-     ns_job_state_t state;                 /* What state the job is currently in. */

-     ns_event_fw_ctx_t *ns_event_fw_ctx;

-     void *(*alloc_event_context)(size_t size, struct ns_job_t *job);

-     void (*free_event_context)(void *ev_ctx, struct ns_job_t *job);

-     /* this is called by the event framework when an event is triggered */

-     void (*event_cb)(struct ns_job_t *tpec);

-     /* Called during dispose of the job, to allow user defined cleanup */

-     ns_job_func_t done_cb;

- } ns_job_t;

- 

- typedef void (*ns_event_fw_accept_cb_t)(PRFileDesc *fd, ns_job_t *job);

- typedef void (*ns_event_fw_read_cb_t)(PRFileDesc *fd, ns_job_t *job);

- typedef void (*ns_event_fw_write_cb_t)(PRFileDesc *fd, ns_job_t *job);

- typedef void (*ns_event_fw_connect_cb_t)(PRFileDesc *fd, ns_job_t *job);

- 

- typedef struct ns_event_fw_t

- {

-     ns_event_fw_ctx_t *(*ns_event_fw_init)(void);

-     /*

- struct event_base *event_base_new(void);

- struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx);

-     */

-     void (*ns_event_fw_destroy)(ns_event_fw_ctx_t *ns_event_fw_ctx);

-     /*

- void event_base_free(struct event_base *);

- int talloc_free(void *ptr);

-     */

-     int (*ns_event_fw_loop)(ns_event_fw_ctx_t *ns_event_fw_ctx); /* run the event fw main loop */

-     /*

-       the return value - 1 = no events to process; 0 = normal termination; -1 = error

- int event_base_loop(struct event_base *, int);

- int tevent_loop_wait(struct tevent_context *ev)

-     */

-     void (*ns_event_fw_add_io)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     /*

- void event_set(struct event *, int, short, void (*)(int, short, void *), void *);

- int event_add(struct event *ev, const struct timeval *timeout);

- 

- #define tevent_fd * tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \

-     */

-     void (*ns_event_fw_mod_io)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     /* write, accept, etc. */

-     void (*ns_event_fw_add_timer)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     /*

- tevent_timer *tevent_add_timer(ev, mem_ctx, next_event, handler, private_data)

- 

- evtimer_set(ev, cb, arg)

- evtimer_add(ev, tv)

-         */

-     void (*ns_event_fw_mod_timer)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     void (*ns_event_fw_add_signal)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     /*

- struct tevent_signal *tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data)

- 

- signal_set(ev, x, cb, arg)

- signal_add(ev, tv)

-     */

-     void (*ns_event_fw_mod_signal)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     void (*ns_event_fw_io_event_done)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     void (*ns_event_fw_timer_event_done)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

-     void (*ns_event_fw_signal_event_done)(

-         ns_event_fw_ctx_t *ns_event_fw_ctx,

-         ns_job_t *job);

- } ns_event_fw_t;

- 

- ns_event_fw_t *get_event_framework_event(void);

- ns_event_fw_t *get_event_framework_tevent(void);

- 

- #endif /* THRPOOL_NS_EVENT_FW_H */

@@ -1,336 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- /*

-  * This implements the thrpool event framework interface

-  * to the libevent event framework

-  */

- #include <private/pprio.h>

- #include <event.h>

- #include <event2/event.h>

- typedef struct event_base ns_event_fw_ctx_t;

- typedef struct event ns_event_fw_fd_t;

- typedef struct event ns_event_fw_time_t;

- typedef struct event ns_event_fw_sig_t;

- #define NO_EVENT_TYPEDEFS

- #include "ns_event_fw.h"

- #include <syslog.h>

- 

- static void

- event_logger_cb(int severity, const char *msg)

- {

-     int priority = 0;

-     char *text = NULL;

- 

-     switch (severity) {

-     case _EVENT_LOG_DEBUG:

-         priority = LOG_DEBUG;

-         break;

-     case _EVENT_LOG_MSG:

-         priority = LOG_DEBUG;

-         break;

-     case _EVENT_LOG_WARN:

-         priority = LOG_DEBUG;

-         break;

-     case _EVENT_LOG_ERR:

-         priority = LOG_ERR;

-         break;

-     default:

-         priority = LOG_ERR;

-         break; /* never reached */

-     }

-     /* need to append newline */

-     text = PR_smprintf("%s\n", msg);

-     ns_log(priority, text);

-     ns_free(text);

- }

- 

- static ns_job_type_t

- event_flags_to_type(short events)

- {

-     /* The volatile here prevents gcc rearranging this code within the thread. */

-     volatile ns_job_type_t job_type = 0;

- 

-     /* Either we timeout *or* we are a real event */

-     if (!(events & EV_TIMEOUT)) {

-         if (events & EV_READ) {

-             job_type |= NS_JOB_READ;

-         }

-         if (events & EV_WRITE) {

-             job_type |= NS_JOB_WRITE;

-         }

-         if (events & EV_SIGNAL) {

-             job_type |= NS_JOB_SIGNAL;

-         }

-     } else {

-         job_type = NS_JOB_TIMER;

-     }

-     return job_type;

- }

- 

- /* this is called by the event main loop when an event

-    is triggered - this "maps" the event library interface

-    to our nspr/thrpool interface */

- static void

- event_cb(int fd, short event, void *arg)

- {

-     ns_job_t *job = (ns_job_t *)arg;

- 

-     PR_ASSERT(arg);

-     if (job->fd && fd > 0) {

-         PR_ASSERT(fd == PR_FileDesc2NativeHandle(job->fd));

-     }

- 

-     job->output_job_type = event_flags_to_type(event);

- 

-     job->event_cb(job);

- }

- 

- /* convert from job job_type to event fw type */

- static short

- job_type_to_flags(ns_job_type_t job_type)

- {

-     short flags = 0;

-     if (NS_JOB_IS_ACCEPT(job_type) || NS_JOB_IS_READ(job_type)) {

-         flags |= EV_READ;

-     }

-     if (NS_JOB_IS_WRITE(job_type) || NS_JOB_IS_CONNECT(job_type)) {

-         flags |= EV_WRITE;

-     }

-     if (NS_JOB_IS_PERSIST(job_type)) {

-         flags |= EV_PERSIST;

-     }

-     if (NS_JOB_IS_TIMER(job_type)) {

-         flags |= EV_TIMEOUT;

-     }

-     if (NS_JOB_IS_SIGNAL(job_type)) {

-         flags |= EV_SIGNAL;

-     }

-     return flags;

- }

- 

- static ns_event_fw_ctx_t *

- ns_event_fw_init(void)

- {

-     event_set_log_callback(event_logger_cb);

- #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED

-     event_set_mem_functions(ns_malloc, ns_realloc, ns_free);

- #endif

-     return event_base_new();

- }

- 

- static void

- ns_event_fw_destroy(ns_event_fw_ctx_t *event_ctx_t)

- {

-     event_base_free(event_ctx_t);

- }

- 

- /*

-  * remove just removes the event from active consideration

-  * by the event framework - the event object may be

-  * reactivated by calling mod - event done will actually

-  * remove and free the object

-  */

- static void

- ns_event_fw_io_event_remove(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     event_del(job->ns_event_fw_fd);

- }

- 

- static void

- ns_event_fw_io_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_io_event_remove(ns_event_fw_ctx, job);

-     job->free_event_context(job->ns_event_fw_fd, job);

-     job->ns_event_fw_fd = NULL;

- }

- 

- static void

- ns_event_fw_timer_event_remove(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     evtimer_del(job->ns_event_fw_time);

- }

- 

- static void

- ns_event_fw_timer_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_timer_event_remove(ns_event_fw_ctx, job);

-     job->free_event_context(job->ns_event_fw_time, job);

-     job->ns_event_fw_time = NULL;

- }

- 

- static void

- ns_event_fw_signal_event_remove(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     evsignal_del(job->ns_event_fw_sig);

- }

- 

- static void

- ns_event_fw_signal_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_signal_event_remove(ns_event_fw_ctx, job);

-     job->free_event_context(job->ns_event_fw_sig, job);

-     job->ns_event_fw_sig = NULL;

- }

- 

- static void

- ns_event_fw_add_io(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     struct timeval *tv = NULL;

-     /* allocate a new event structure - use the job for the memory context */

-     struct event *ev = job->alloc_event_context(sizeof(struct event), job);

-     /* set the fields in the event */

-     short flags = job_type_to_flags(job->job_type);

- 

-     event_assign(ev, ns_event_fw_ctx, PR_FileDesc2NativeHandle(job->fd), flags, event_cb, job);

-     if (job->tv.tv_sec || job->tv.tv_usec) {

-         tv = &job->tv;

-     }

-     event_add(ev, tv);

-     job->ns_event_fw_fd = ev;

- }

- 

- static void

- ns_event_fw_mod_io(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     struct timeval *tv = NULL;

-     short events = job_type_to_flags(job->job_type);

- 

-     if (job->tv.tv_sec || job->tv.tv_usec) {

-         tv = &job->tv;

-     }

-     if (events) {

-         job->ns_event_fw_fd->ev_events = events;

-         event_add(job->ns_event_fw_fd, tv);

-     } else {

-         /* setting the job_type to remove IO events will remove it from the event system */

-         ns_event_fw_io_event_remove(ns_event_fw_ctx, job);

-     }

- }

- 

- static void

- ns_event_fw_add_timer(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     /* allocate a new event structure - use the job for the memory context */

-     struct event *ev = job->alloc_event_context(sizeof(struct event), job);

-     evtimer_assign(ev, ns_event_fw_ctx, event_cb, job);

-     evtimer_add(ev, &job->tv);

-     job->ns_event_fw_time = ev;

- }

- 

- static void

- ns_event_fw_mod_timer(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     evtimer_add(job->ns_event_fw_time, &job->tv);

- }

- 

- static void

- ns_event_fw_add_signal(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     /* allocate a new event structure - use the job for the memory context */

-     struct event *ev = job->alloc_event_context(sizeof(struct event), job);

-     evsignal_assign(ev, ns_event_fw_ctx, job->signal, event_cb, job);

-     evsignal_add(ev, NULL);

-     job->ns_event_fw_sig = ev;

- }

- 

- static void

- ns_event_fw_mod_signal(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     /* If the event in the ev argument already has a scheduled timeout, calling event_add() replaces the old timeout with the new one, or clears the old timeout if the timeout argument is NULL. */

-     evsignal_add(job->ns_event_fw_sig, NULL);

- }

- 

- /* returns

-    1 - no events to process

-    0 - normal termination

-    -1 - error

- */

- static int

- ns_event_fw_loop(ns_event_fw_ctx_t *ns_event_fw_ctx)

- {

-     int rc = event_base_loop(ns_event_fw_ctx, EVLOOP_ONCE);

-     if (rc == 0) {

-         rc = 1;

-     } else {

-         rc = -1;

-     }

- 

-     return rc;

- }

- 

- static ns_event_fw_t ns_event_fw_event = {

-     ns_event_fw_init,

-     ns_event_fw_destroy,

-     ns_event_fw_loop,

-     ns_event_fw_add_io,

-     ns_event_fw_mod_io,

-     ns_event_fw_add_timer,

-     ns_event_fw_mod_timer,

-     ns_event_fw_add_signal,

-     ns_event_fw_mod_signal,

-     ns_event_fw_io_event_done,

-     ns_event_fw_timer_event_done,

-     ns_event_fw_signal_event_done};

- 

- ns_event_fw_t *

- get_event_framework_event()

- {

-     return &ns_event_fw_event;

- }

@@ -1,328 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- /*

-  * This implements the thrpool event framework interface

-  * to the libtevent event framework

-  */

- #include <private/pprio.h>

- #include <talloc.h>

- #include <tevent.h>

- typedef struct tevent_context ns_event_fw_ctx_t;

- typedef struct tevent_fd ns_event_fw_fd_t;

- typedef struct tevent_timer ns_event_fw_time_t;

- typedef struct tevent_signal ns_event_fw_sig_t;

- #define NO_EVENT_TYPEDEFS

- #include "ns_event_fw.h"

- #include <syslog.h>

- 

- static void ns_event_fw_add_io(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_mod_io(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_add_timer(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_mod_timer(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_add_signal(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_mod_signal(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_io_event_remove(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_io_event_done(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_timer_event_done(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- static void ns_event_fw_signal_event_done(ns_event_fw_ctx_t *ns_event_fw_ctx, ns_job_t *job);

- 

- static void

- tevent_logger_cb(void *context __attribute__((unused)), enum tevent_debug_level level, const char *fmt, va_list ap)

- {

-     int priority = 0;

-     char *msg = NULL;

- 

-     switch (level) {

-     case TEVENT_DEBUG_FATAL:

-         priority = LOG_ERR;

-         break;

-     case TEVENT_DEBUG_ERROR:

-         priority = LOG_ERR;

-         break;

-     case TEVENT_DEBUG_WARNING:

-         priority = LOG_DEBUG;

-         break;

-     case TEVENT_DEBUG_TRACE:

-         priority = LOG_DEBUG;

-         break;

-     default:

-         priority = LOG_DEBUG;

-         break; /* never reached */

-     }

- 

-     msg = PR_smprintf("%s\n", fmt);

-     ns_log_valist(priority, msg, ap);

-     ns_free(msg);

- }

- 

- static ns_job_type_t

- event_flags_to_type(uint16_t flags)

- {

-     ns_job_type_t job_type = 0;

-     if (flags & TEVENT_FD_READ) {

-         job_type |= NS_JOB_READ;

-     }

-     if (flags & TEVENT_FD_WRITE) {

-         job_type |= NS_JOB_WRITE;

-     }

-     return job_type;

- }

- 

- /* this is called by the event main loop when an fd event

-    is triggered - this "maps" the event library interface

-    to our nspr/thrpool interface */

- static void

- fd_event_cb(struct tevent_context *ev __attribute__((unused)), struct tevent_fd *fde __attribute__((unused)), uint16_t flags, void *arg)

- {

-     ns_job_t *job = (ns_job_t *)arg;

- 

-     PR_ASSERT(arg);

- 

-     /* I/O jobs can be timed - if we get an fd event, cancel the timer */

-     if (job->ns_event_fw_time) {

-         ns_event_fw_timer_event_done(job->ns_event_fw_ctx, job);

-     }

-     job->output_job_type = event_flags_to_type(flags);

-     job->event_cb(job);

- }

- 

- /* this is called by the event main loop when a timer event

-    is triggered - this "maps" the event library interface

-    to our nspr/thrpool interface */

- static void

- timer_event_cb(struct tevent_context *ev __attribute__((unused)), struct tevent_timer *te __attribute__((unused)), struct timeval current_time __attribute__((unused)), void *arg)

- {

-     ns_job_t *job = (ns_job_t *)arg;

- 

-     PR_ASSERT(arg);

- 

-     /* I/O jobs can be timed - if we get an timer event, cancel the fd */

-     if (job->ns_event_fw_fd) {

-         ns_event_fw_io_event_done(job->ns_event_fw_ctx, job);

-     }

-     job->output_job_type = NS_JOB_TIMER;

-     job->event_cb(job);

- }

- 

- /* this is called by the event main loop when a signal event

-    is triggered - this "maps" the event library interface

-    to our nspr/thrpool interface */

- static void

- signal_event_cb(struct tevent_context *ev __attribute__((unused)), struct tevent_signal *se __attribute__((unused)), int signum, int count __attribute__((unused)), void *siginfo __attribute__((unused)), void *arg)

- {

-     ns_job_t *job = (ns_job_t *)arg;

- 

-     PR_ASSERT(arg);

- 

-     job->output_job_type = NS_JOB_SIGNAL;

-     job->signal = signum;

-     job->event_cb(job);

- }

- 

- /* convert from job job_type to event fw type */

- static uint16_t

- job_type_to_flags(ns_job_type_t job_type)

- {

-     uint16_t flags = 0;

-     if (NS_JOB_IS_ACCEPT(job_type) || NS_JOB_IS_READ(job_type)) {

-         flags |= TEVENT_FD_READ;

-     }

-     if (NS_JOB_IS_WRITE(job_type) || NS_JOB_IS_CONNECT(job_type)) {

-         flags |= TEVENT_FD_WRITE;

-     }

-     return flags;

- }

- 

- static ns_event_fw_ctx_t *

- ns_event_fw_init(void)

- {

-     ns_event_fw_ctx_t *ev = tevent_context_init(NULL);

-     tevent_set_debug(ev, tevent_logger_cb, NULL);

-     return ev;

- }

- 

- static void

- ns_event_fw_destroy(ns_event_fw_ctx_t *ns_event_fw_ctx_t)

- {

-     talloc_free(ns_event_fw_ctx_t);

- }

- 

- /*

-  * remove just removes the event from active consideration

-  * by the event framework - the event object may be

-  * reactivated by calling mod - event done will actually

-  * remove and free the object

-  */

- static void

- ns_event_fw_io_event_remove(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     tevent_fd_set_flags(job->ns_event_fw_fd, 0);

- }

- 

- static void

- ns_event_fw_io_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_io_event_remove(ns_event_fw_ctx, job);

-     talloc_free(job->ns_event_fw_fd);

-     job->ns_event_fw_fd = NULL;

- }

- 

- static void

- ns_event_fw_timer_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     talloc_free(job->ns_event_fw_time);

-     job->ns_event_fw_time = NULL;

- }

- 

- static void

- ns_event_fw_signal_event_done(

-     ns_event_fw_ctx_t *ns_event_fw_ctx __attribute__((unused)),

-     ns_job_t *job)

- {

-     talloc_free(job->ns_event_fw_sig);

-     job->ns_event_fw_sig = NULL;

- }

- 

- static void

- ns_event_fw_add_io(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     /* set the fields in the event */

-     uint16_t flags = job_type_to_flags(job->job_type);

- 

-     job->ns_event_fw_fd = tevent_add_fd(ns_event_fw_ctx, ns_event_fw_ctx,

-                                         PR_FileDesc2NativeHandle(job->fd),

-                                         flags, fd_event_cb, job);

-     /* add/schedule the timer event */

-     if (job->tv.tv_sec || job->tv.tv_usec) {

-         job->ns_event_fw_time = tevent_add_timer(ns_event_fw_ctx, ns_event_fw_ctx,

-                                                  job->tv, timer_event_cb, job);

-     }

- }

- 

- static void

- ns_event_fw_mod_io(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     uint16_t events = job_type_to_flags(job->job_type);

- 

-     if (job->tv.tv_sec || job->tv.tv_usec) {

-         ns_event_fw_mod_timer(ns_event_fw_ctx, job);

-     }

-     tevent_fd_set_flags(job->ns_event_fw_fd, events);

- }

- 

- static void

- ns_event_fw_add_timer(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     job->ns_event_fw_time = tevent_add_timer(ns_event_fw_ctx, ns_event_fw_ctx,

-                                              job->tv, timer_event_cb, job);

- }

- 

- static void

- ns_event_fw_mod_timer(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_timer_event_done(ns_event_fw_ctx, job);

-     ns_event_fw_add_timer(ns_event_fw_ctx, job);

- }

- 

- static void

- ns_event_fw_add_signal(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     job->ns_event_fw_sig = tevent_add_signal(ns_event_fw_ctx, ns_event_fw_ctx,

-                                              job->signal, 0, signal_event_cb, job);

- }

- 

- static void

- ns_event_fw_mod_signal(

-     ns_event_fw_ctx_t *ns_event_fw_ctx,

-     ns_job_t *job)

- {

-     ns_event_fw_signal_event_done(ns_event_fw_ctx, job);

-     ns_event_fw_add_signal(ns_event_fw_ctx, job);

- }

- 

- /* returns

-    1 - no events to process

-    0 - normal termination

-    -1 - error

- */

- static int

- ns_event_fw_loop(ns_event_fw_ctx_t *ns_event_fw_ctx)

- {

-     int rc = tevent_loop_once(ns_event_fw_ctx);

-     if (rc == 0) {

-         rc = 1;

-     } else {

-         rc = -1;

-     }

-     /* tevent apparently has no normal termination return value */

-     return rc;

- }

- 

- static ns_event_fw_t ns_event_fw_tevent = {

-     ns_event_fw_init,

-     ns_event_fw_destroy,

-     ns_event_fw_loop,

-     ns_event_fw_add_io,

-     ns_event_fw_mod_io,

-     ns_event_fw_add_timer,

-     ns_event_fw_mod_timer,

-     ns_event_fw_add_signal,

-     ns_event_fw_mod_signal,

-     ns_event_fw_io_event_done,

-     ns_event_fw_timer_event_done,

-     ns_event_fw_signal_event_done};

- 

- ns_event_fw_t *

- get_event_framework_tevent()

- {

-     return &ns_event_fw_tevent;

- }

@@ -1,106 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- /*! \file ns_private.h

-     \brief Nunc Stans private API

- 

-     This is the private API for Nunc Stans

- */

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- #include "nspr.h"

- #include "prmon.h"

- #include <nunc-stans.h>

- 

- #include <inttypes.h>

- 

- /**

-  * Forward declaration of the thread struct - internal

-  *

-  * The actual struct is opaque to applications.  The forward declaration is here

-  * for the typedef.

-  */

- struct ns_thread_t;

- /**

-  * This is the thread type - internal

-  *

-  * The actual thread type is opaque to applications.

-  */

- typedef struct ns_thread_t ns_thread_t;

- 

- /**

-  * Log an error to logging system. - internal

-  * \param priority The log level

-  * \param fmt The log message string format

-  */

- void ns_log(int priority, const char *fmt, ...);

- 

- /**

-  * Log an error to logging system. - internal

-  * \param priority The log level

-  * \param fmt The log message string format

-  * \param varg The va_list arg

-  */

- void ns_log_valist(int priority, const char *fmt, va_list varg);

- 

- /**

-  * \param size - Memory allocation size - internal

-  * \return - allocated memory

-  */

- void *ns_malloc(size_t size);

- 

- /**

-  * \param size - Memory allocation size - internal

-  * \param alignment - The allignment of the memory. Must be a power of two.

-  * \return - allocated memory

-  */

- void *ns_memalign(size_t size, size_t alignment);

- 

- /**

-  * \param count - number of items - internal

-  * \param size - Memory allocation size

-  * \return - allocated memory

-  */

- void *ns_calloc(size_t count, size_t size);

- 

- /**

-  * \param ptr - pointer to the memory block - internal

-  * \param size - size of allocation

-  * \return - allocated memory

-  */

- void *ns_realloc(void *ptr, size_t size);

- 

- /**

-  * \param ptr - pointer to memory to be freed - internal

-  */

- void ns_free(void *ptr);

@@ -1,1688 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- #ifdef HAVE_UNISTD_H

- #include <unistd.h>

- #endif

- #ifdef HAVE_FCNTL_H

- #include <fcntl.h>

- #endif

- #ifdef HAVE_SYSLOG_H

- #include <syslog.h>

- #endif

- #ifdef HAVE_ERRNO_H

- #include <errno.h>

- #endif

- #ifdef HAVE_STDLIB_H

- #include <stdlib.h>

- #endif

- #ifdef HAVE_INTTYPES_H

- #include <inttypes.h>

- #endif

- 

- #include <nspr.h>

- #include <private/pprio.h>

- #include "ns_event_fw.h"

- 

- /* SDS contains the lock free queue wrapper */

- #include <sds.h>

- 

- #include <assert.h>

- 

- 

- /*

-  * Threadpool

-  */

- struct ns_thrpool_t

- {

-     sds_lqueue *work_q;

-     sds_lqueue *event_q;

-     int32_t shutdown;

-     int32_t shutdown_event_loop;

-     pthread_cond_t work_q_cv;

-     pthread_mutex_t work_q_lock;

-     sds_queue *thread_stack;

-     uint32_t thread_count;

-     pthread_t event_thread;

-     PRFileDesc *event_q_wakeup_pipe_read;

-     PRFileDesc *event_q_wakeup_pipe_write;

-     ns_job_t *event_q_wakeup_job;

-     ns_event_fw_t *ns_event_fw;

-     ns_event_fw_ctx_t *ns_event_fw_ctx;

-     size_t stacksize;

- };

- 

- struct ns_thread_t

- {

-     pthread_t thr;           /* the thread */

-     struct ns_thrpool_t *tp; /* pointer back to thread pool */

- };

- 

- #define ERRNO_WOULD_BLOCK(iii) (iii == EWOULDBLOCK) || (iii == EAGAIN)

- 

- /* Forward declarations. */

- static void internal_ns_job_done(ns_job_t *job);

- static void internal_ns_job_rearm(ns_job_t *job);

- static void work_job_execute(ns_job_t *job);

- static void event_q_notify(ns_job_t *job);

- static void work_q_notify(ns_job_t *job);

- 

- /* logging function pointers */

- static void (*logger)(int, const char *, va_list) = NULL;

- static void (*log_start)(void) = NULL;

- static void (*log_close)(void) = NULL;

- 

- /* memory function pointers */

- static void *(*malloc_fct)(size_t) = NULL;

- static void *(*memalign_fct)(size_t size, size_t alignment) = NULL;

- static void *(*calloc_fct)(size_t, size_t) = NULL;

- static void *(*realloc_fct)(void *, size_t) = NULL;

- static void (*free_fct)(void *) = NULL;

- 

- /* syslog functions */

- static void

- ns_syslog(int priority, const char *fmt, va_list varg)

- {

-     vsyslog(priority, fmt, varg);

- }

- 

- static void

- ns_syslog_start(void)

- {

-     openlog("nunc-stans", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

- }

- 

- static void

- ns_syslog_close(void)

- {

-     closelog();

- }

- 

- /* default memory functions */

- static void *

- os_malloc(size_t size)

- {

-     return malloc(size);

- }

- 

- static void *

- os_memalign_malloc(size_t size, size_t alignment)

- {

-     void *ptr;

-     if (posix_memalign(&ptr, alignment, size) != 0) {

-         return NULL;

-     }

-     return ptr;

- }

- 

- static void *

- os_calloc(size_t count, size_t size)

- {

-     return calloc(count, size);

- }

- 

- static void *

- os_realloc(void *ptr, size_t size)

- {

-     return realloc(ptr, size);

- }

- 

- static void

- os_free(void *ptr)

- {

-     free(ptr);

- }

- 

- int32_t

- ns_thrpool_is_shutdown(struct ns_thrpool_t *tp)

- {

-     int32_t result = 0;

- #ifdef ATOMIC_64BIT_OPERATIONS

-     __atomic_load(&(tp->shutdown), &result, __ATOMIC_ACQUIRE);

- #else

-     result = PR_AtomicAdd(&(tp->shutdown), 0);

- #endif

-     return result;

- }

- 

- int32_t

- ns_thrpool_is_event_shutdown(struct ns_thrpool_t *tp)

- {

-     int32_t result = 0;

- #ifdef ATOMIC_64BIT_OPERATIONS

-     __atomic_load(&(tp->shutdown_event_loop), &result, __ATOMIC_ACQUIRE);

- #else

-     result = PR_AtomicAdd(&(tp->shutdown_event_loop), 0);

- #endif

-     return result;

- }

- 

- static int32_t

- validate_event_timeout(struct timeval *tv)

- {

-     if (tv->tv_sec < 0 || tv->tv_usec < 0) {

-         /* If we get here, you have done something WRONG */

-         return 1;

-     }

-     return 0;

- }

- 

- static void

- job_queue_cleanup(void *arg)

- {

-     struct ns_job_t *job = (ns_job_t *)arg;

-     if (job != NULL) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_queue_job_cleanup: destroying job %x\n", job);

- #endif

-         internal_ns_job_done(job);

-     }

- }

- 

- static void

- internal_ns_job_done(ns_job_t *job)

- {

-     pthread_mutex_lock(&(job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "internal_ns_job_done %x state %d moving to NS_JOB_DELETED\n", job, job->state);

- #endif

-     /* In theory, due to the monitor placement, this should never be able to be seen by any other thread ... */

-     job->state = NS_JOB_DELETED;

- 

-     if (job->ns_event_fw_fd) {

-         job->tp->ns_event_fw->ns_event_fw_io_event_done(job->tp->ns_event_fw_ctx, job);

-     }

-     if (job->ns_event_fw_time) {

-         job->tp->ns_event_fw->ns_event_fw_timer_event_done(job->tp->ns_event_fw_ctx, job);

-     }

-     if (job->ns_event_fw_sig) {

-         job->tp->ns_event_fw->ns_event_fw_signal_event_done(job->tp->ns_event_fw_ctx, job);

-     }

- 

-     if (job->fd && !NS_JOB_IS_PRESERVE_FD(job->job_type)) {

-         PR_Close(job->fd);

-     } /* else application is responsible for fd */

- 

-     if (job->done_cb != NULL) {

-         job->done_cb(job);

-     }

- 

-     pthread_mutex_unlock(&(job->monitor));

-     pthread_mutex_destroy(&(job->monitor));

-     pthread_cond_destroy(&(job->notify));

- 

-     ns_free(job);

- }

- 

- /* Is there a way to get a status back from here? */

- static void

- internal_ns_job_rearm(ns_job_t *job)

- {

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state == NS_JOB_NEEDS_ARM);

- /* Don't think I need to check persistence here, it could be the first arm ... */

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "internal_ns_rearm_job %x state %d moving to NS_JOB_ARMED\n", job, job->state);

- #endif

-     job->state = NS_JOB_ARMED;

- 

-     /* I think we need to check about is_shutdown here? */

- 

-     if (NS_JOB_IS_IO(job->job_type) || NS_JOB_IS_TIMER(job->job_type) || NS_JOB_IS_SIGNAL(job->job_type)) {

-         event_q_notify(job);

-     } else {

-         /* if this is a non event task, just queue it on the work q */

-         /* Prevents an un-necessary queue / dequeue to the event_q */

-         work_q_notify(job);

-     }

-     pthread_mutex_unlock(&(job->monitor));

- }

- 

- static void

- work_job_execute(ns_job_t *job)

- {

-     /*

-      * when we pull out a job to work on it, we do it here rather than calling

-      * job function directly.

-      *

-      * DANGER: After this is called, you must NOT ACCESS job again. It MAY be

-      * DELETED! Crashes abound, you have been warned ...

-      */

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "work_job_execute %x state %d moving to NS_JOB_RUNNING\n", job, job->state);

- #endif

-     job->state = NS_JOB_RUNNING;

-     /* Do the work. */

-     PR_ASSERT(job->func);

-     job->func(job);

- 

-     /* Only if !threaded job, and persistent, we automatically tell us to rearm */

-     if (!NS_JOB_IS_THREAD(job->job_type) && NS_JOB_IS_PERSIST(job->job_type) && job->state == NS_JOB_RUNNING) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "work_job_execute PERSIST and RUNNING, remarking %x as NS_JOB_NEEDS_ARM\n", job);

- #endif

-         job->state = NS_JOB_NEEDS_ARM;

-     }

- 

-     if (job->state == NS_JOB_NEEDS_DELETE) {

- /* Send it to the job mincer! */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "work_job_execute %x state %d job func complete, sending to job_done...\n", job, job->state);

- #endif

-         /*

-          * Let waiters know we are done, they'll pick up once

-          * we unlock.

-          */

-         pthread_cond_signal(&(job->notify));

-         pthread_mutex_unlock(&(job->monitor));

-         internal_ns_job_done(job);

-         /* MUST NOT ACCESS JOB AGAIN.*/

-     } else if (job->state == NS_JOB_NEEDS_ARM) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "work_job_execute %x state %d job func complete, sending to rearm...\n", job, job->state);

- #endif

-         /* Rearm the job! */

-         /* We *don't* notify here because we ARE NOT done! */

-         pthread_mutex_unlock(&(job->monitor));

-         internal_ns_job_rearm(job);

-     } else {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "work_job_execute %x state %d job func complete move to NS_JOB_WAITING\n", job, job->state);

- #endif

-         /* This should never occur? What's going on ... */

-         PR_ASSERT(!NS_JOB_IS_PERSIST(job->job_type));

-         /* We are now idle, set waiting. */

-         job->state = NS_JOB_WAITING;

-         /*

-          * Let waiters know we are done, they'll pick up once

-          * we unlock.

-          */

-         pthread_cond_signal(&(job->notify));

-         pthread_mutex_unlock(&(job->monitor));

-     }

-     /* MUST NOT ACCESS JOB AGAIN */

- }

- 

- static void

- work_q_wait(ns_thrpool_t *tp)

- {

-     pthread_mutex_lock(&(tp->work_q_lock));

-     pthread_cond_wait(&(tp->work_q_cv), &(tp->work_q_lock));

-     pthread_mutex_unlock(&(tp->work_q_lock));

- }

- 

- static void

- work_q_notify(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "work_q_notify %x state %d\n", job, job->state);

- #endif

-     PR_ASSERT(job->state == NS_JOB_ARMED);

-     if (job->state != NS_JOB_ARMED) {

-         /* Maybe we should return some error here? */

-         ns_log(LOG_ERR, "work_q_notify %x state %d is not ARMED, cannot queue!\n", job, job->state);

-         pthread_mutex_unlock(&(job->monitor));

-         return;

-     }

-     /* MUST NOT ACCESS job after enqueue. So we stash tp.*/

-     ns_thrpool_t *ltp = job->tp;

-     pthread_mutex_unlock(&(job->monitor));

-     sds_lqueue_enqueue(ltp->work_q, (void *)job);

-     pthread_mutex_lock(&(ltp->work_q_lock));

-     pthread_cond_signal(&(ltp->work_q_cv));

-     pthread_mutex_unlock(&(ltp->work_q_lock));

-     PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield to allow worker thread to pick up job */

- }

- 

- /*

-  * worker thread function

-  */

- static void *

- worker_thread_func(void *arg)

- {

-     ns_thread_t *thr = (ns_thread_t *)arg;

-     ns_thrpool_t *tp = thr->tp;

-     sds_result result = SDS_SUCCESS;

-     int_fast32_t is_shutdown = 0;

- 

-     /* Get ready to use lock free ds */

-     sds_lqueue_tprep(tp->work_q);

- 

-     /*

-      * Execute jobs until shutdown is set and the queues are empty.

-      */

-     while (!is_shutdown) {

-         ns_job_t *job = NULL;

-         result = sds_lqueue_dequeue(tp->work_q, (void **)&job);

-         /* Don't need monitor here, job_dequeue barriers the memory for us. Job will be valid */

-         /* Is it possible for a worker thread to get stuck here during shutdown? */

-         if (result == SDS_LIST_EXHAUSTED) {

-             work_q_wait(tp);

-         } else if (result == SDS_SUCCESS && job != NULL) {

-             /* Even if we are shutdown here, we can process a job. */

-             /* Should we just keep dequeing until we exhaust the list? */

-             if (NS_JOB_IS_SHUTDOWN_WORKER(job->job_type)) {

-                 ns_log(LOG_INFO, "worker_thread_func notified to shutdown!\n");

-                 internal_ns_job_done(job);

-                 is_shutdown = 1;

-             } else {

-                 work_job_execute(job);

-             }

-             /* MUST NOT ACCESS JOB FROM THIS POINT */

-         } else {

-             ns_log(LOG_ERR, "worker_thread_func encountered a recoverable issue during processing of the queue\n");

-         }

-     }

- 

-     ns_log(LOG_INFO, "worker_thread_func shutdown complete!\n");

-     /* With sds, it cleans the thread on join automatically. */

-     return NULL;

- }

- 

- /*

-  * Add a new event, or modify or delete an existing event

-  */

- static void

- update_event(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "update_event %x state %d\n", job, job->state);

- #endif

-     PR_ASSERT(job->state == NS_JOB_NEEDS_DELETE || job->state == NS_JOB_ARMED);

-     if (job->state == NS_JOB_NEEDS_DELETE) {

-         pthread_mutex_unlock(&(job->monitor));

-         internal_ns_job_done(job);

-         return;

-     } else if (NS_JOB_IS_IO(job->job_type) || job->ns_event_fw_fd) {

-         if (!job->ns_event_fw_fd) {

-             job->tp->ns_event_fw->ns_event_fw_add_io(job->tp->ns_event_fw_ctx, job);

-         } else {

-             job->tp->ns_event_fw->ns_event_fw_mod_io(job->tp->ns_event_fw_ctx, job);

-         }

-         pthread_mutex_unlock(&(job->monitor));

-         /* We need these returns to prevent a race on the next else if condition when we release job->monitor */

-         return;

-     } else if (NS_JOB_IS_TIMER(job->job_type) || job->ns_event_fw_time) {

-         if (!job->ns_event_fw_time) {

-             job->tp->ns_event_fw->ns_event_fw_add_timer(job->tp->ns_event_fw_ctx, job);

-         } else {

-             job->tp->ns_event_fw->ns_event_fw_mod_timer(job->tp->ns_event_fw_ctx, job);

-         }

-         pthread_mutex_unlock(&(job->monitor));

-         return;

-     } else if (NS_JOB_IS_SIGNAL(job->job_type) || job->ns_event_fw_sig) {

-         if (!job->ns_event_fw_sig) {

-             job->tp->ns_event_fw->ns_event_fw_add_signal(job->tp->ns_event_fw_ctx, job);

-         } else {

-             job->tp->ns_event_fw->ns_event_fw_mod_signal(job->tp->ns_event_fw_ctx, job);

-         }

-         pthread_mutex_unlock(&(job->monitor));

-         return;

-     } else {

-         /* It's a "run now" job. */

-         if (NS_JOB_IS_THREAD(job->job_type)) {

-             pthread_mutex_unlock(&(job->monitor));

-             work_q_notify(job);

-         } else {

-             pthread_mutex_unlock(&(job->monitor));

-             event_q_notify(job);

-         }

-     }

- 

-     return;

- }

- 

- static void

- event_q_wait(ns_thrpool_t *tp __attribute__((unused)))

- {

-     /* unused for now */

-     /* the main event loop will do our "waiting" - waiting for events

-        to happen, or we can trigger an event to "wakeup" the event

-        loop (see event_q_notify) */

- }

- 

- static void

- event_q_wake(ns_thrpool_t *tp)

- {

-     int32_t len;

- 

- /* Rather than trying to make  anew event, tell the event loop to exit with no

-      * events.

-      */

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "event_q_wake attempting to wake event queue.\n");

- #endif

- 

-     /* NSPR I/O doesn't allow non-blocking signal pipes, so use write instead of PR_Write */

-     len = write(PR_FileDesc2NativeHandle(tp->event_q_wakeup_pipe_write),

-                 "a", 1);

-     if (1 != len) {

-         if ((errno == 0) || ERRNO_WOULD_BLOCK(errno)) {

-             ns_log(LOG_DEBUG, "Write blocked for wakeup pipe - ignore %d\n",

-                    errno);

-         } else {

-             ns_log(LOG_ERR, "Error: could not write wakeup pipe: %d:%s\n",

-                    errno, PR_ErrorToString(errno, PR_LANGUAGE_I_DEFAULT));

-         }

-     }

-     PR_Sleep(PR_INTERVAL_NO_WAIT); /* yield to allow event thread to pick up event */

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "event_q_wake result. 0\n");

- #endif

- }

- 

- static void

- event_q_notify(ns_job_t *job)

- {

-     ns_thrpool_t *tp = job->tp;

-     /* if we are being called from a thread other than the

-        event loop thread, we have to notify that thread to

-        perform the event work */

-     if (pthread_equal(tp->event_thread, pthread_self()) != 0) {

-         /* If we are being run from the same thread as the event

-            loop thread, we can just update the event here */

-         update_event(job);

-     } else {

- /* The event loop may be waiting for events, and may wait a long

-            time by default if there are no events to process - since we

-            want to add an event, we have to "wake up" the event loop by

-            posting an event - this will cause the wakeup_cb to be called

-            which will empty the event_q and add all of the events

-         */

- /* NOTE: once job is queued, it may be deleted immediately in

-          * another thread, if the event loop picks up the deletion

-          * job before we can notify it below - so make sure not to

-          * refer to job after the enqueue.

-          */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "event_q_notify enqueuing %x with state %d\n", job, job->state);

- #endif

- 

-         sds_lqueue_enqueue(tp->event_q, (void *)job);

-         event_q_wake(tp);

-     }

- }

- 

- /* This is run inside the event loop thread, and only in the

-    event loop thread

-    This function pulls the io/timer/signal event requests off

-    the request queue, formats the events in the format required

-    by the event framework, and adds them

- */

- static void

- get_new_event_requests(ns_thrpool_t *tp)

- {

-     ns_job_t *job = NULL;

-     while (sds_lqueue_dequeue(tp->event_q, (void **)&job) == SDS_SUCCESS) {

-         if (job != NULL) {

- #ifdef DEBUG

-             ns_log(LOG_DEBUG, "get_new_event_requests Dequeuing %x with state %d\n", job, job->state);

- #endif

-             update_event(job);

- #ifdef DEBUG

-         } else {

-             ns_log(LOG_DEBUG, "get_new_event_requests Dequeuing NULL job\n");

- #endif

-         }

-     }

- }

- 

- static void *

- event_loop_thread_func(void *arg)

- {

-     struct ns_thrpool_t *tp = (struct ns_thrpool_t *)arg;

-     int rc;

- 

-     sds_lqueue_tprep(tp->event_q);

- 

-     while (!ns_thrpool_is_event_shutdown(tp)) {

-         /* get new event requests */

-         get_new_event_requests(tp);

-         /* process events */

-         /* return 1 - no events ; 0 - normal exit ; -1 - error */

-         rc = tp->ns_event_fw->ns_event_fw_loop(tp->ns_event_fw_ctx);

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "event_loop_thread_func woke event queue. rc=%d\n", rc);

- #endif

-         if (rc == -1) {       /* error */

-         } else if (rc == 0) { /* exiting */

-         } else {              /* no events to process */

-             event_q_wait(tp);

-         }

-     }

-     return NULL;

- }

- 

- /*

-  * The event framework calls this function when it receives an

-  * event - the event framework does all of the work to map

-  * the framework flags, etc. into the job

-  * This function is called only in the event loop thread.

-  * If the THREAD flag is set, this means the job is to be

-  * handed off to the work q - otherwise, execute it now

-  * in this thread (the event loop thread)

-  * the function must be careful not to block the event

-  * loop thread or starvation will occur

-  */

- static void

- event_cb(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     /*

-      * Sometimes if we queue then request to delete a job REALLY fast, this

-      * will trigger

-      * Fix is that if ARMED we don't allow the job to move to NS_JOB_NEEDS_DELETE

-      */

- 

-     /* There is no guarantee this won't be called once we start to enter the shutdown, especially with timers .... */

-     pthread_mutex_lock(&(job->monitor));

- 

-     PR_ASSERT(job->state == NS_JOB_ARMED || job->state == NS_JOB_NEEDS_DELETE);

-     if (job->state == NS_JOB_ARMED && NS_JOB_IS_THREAD(job->job_type)) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "event_cb %x state %d threaded, send to work_q\n", job, job->state);

- #endif

-         pthread_mutex_unlock(&(job->monitor));

-         work_q_notify(job);

-     } else if (job->state == NS_JOB_NEEDS_DELETE) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "event_cb %x state %d ignoring as NS_JOB_NEEDS_DELETE set\n", job, job->state);

- #endif

-         /*

-          * If the job is in need of delete we IGNORE IT

-          * It's here because it's been QUEUED for deletion and *may* be coming

-          * from the thrpool destroy thread!

-          */

-         pthread_mutex_unlock(&(job->monitor));

- 

-     } else {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "event_cb %x state %d non-threaded, execute right meow\n", job, job->state);

- #endif

-         /* Not threaded, execute now! */

-         pthread_mutex_unlock(&(job->monitor));

-         work_job_execute(job);

-         /* MUST NOT ACCESS JOB FROM THIS POINT */

-     }

- }

- 

- static void

- wakeup_cb(ns_job_t *job)

- {

-     int32_t len;

-     char buf[1];

- 

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "wakeup_cb %x state %d wakeup_cb\n", job, job->state);

- #endif

- 

-     /* NSPR I/O doesn't allow non-blocking signal pipes, so use read instead of PR_Read */

-     len = read(PR_FileDesc2NativeHandle(job->tp->event_q_wakeup_pipe_read),

-                buf, 1);

-     if (1 != len) {

-         if ((errno == 0) || ERRNO_WOULD_BLOCK(errno)) {

-             ns_log(LOG_DEBUG, "Read blocked for wakeup pipe - ignore %d\n",

-                    errno);

-         } else {

-             ns_log(LOG_ERR, "Error: could not read wakeup pipe: %d:%s\n",

-                    errno, PR_ErrorToString(errno, PR_LANGUAGE_I_DEFAULT));

-         }

-     }

-     /* wakeup_cb is usually called because a worker thread has posted a new

-        event we need to add - get all new event requests */

-     get_new_event_requests(job->tp);

- }

- /* convenience function for the event fw to use to allocate

-    space for its event fw event object

-    it is assumed that eventually job will have a memory region/arena

-    to use

-    these functions will be called in the event loop thread from

-    the event framework function that adds a new event

- */

- static void *

- alloc_event_context(size_t size, ns_job_t *job __attribute__((unused)))

- {

-     return ns_malloc(size);

- }

- 

- static void

- free_event_context(void *ev_ctx, ns_job_t *job __attribute__((unused)))

- {

-     ns_free(ev_ctx);

- }

- 

- static ns_job_t *

- new_ns_job(ns_thrpool_t *tp, PRFileDesc *fd, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_data_t *data)

- {

-     ns_job_t *job = ns_calloc(1, sizeof(ns_job_t));

- 

-     pthread_mutexattr_t *monitor_attr = ns_calloc(1, sizeof(pthread_mutexattr_t));

-     pthread_mutexattr_init(monitor_attr);

-     pthread_mutexattr_settype(monitor_attr, PTHREAD_MUTEX_RECURSIVE);

-     assert(pthread_mutex_init(&(job->monitor), monitor_attr) == 0);

-     assert(pthread_cond_init(&(job->notify), NULL) == 0);

-     ns_free(monitor_attr);

- 

-     job->tp = tp;

-     /* We have to have this due to our obsession of hiding struct contents ... */

-     /* It's only used in tevent anyway .... */

-     job->ns_event_fw_ctx = tp->ns_event_fw_ctx;

-     job->fd = fd;

-     job->func = func;

-     job->data = data;

-     job->alloc_event_context = alloc_event_context;

-     job->free_event_context = free_event_context;

-     job->event_cb = event_cb;

-     job->job_type = job_type;

-     job->done_cb = NULL;

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "new_ns_job %x initial NS_JOB_WAITING\n", job);

- #endif

-     job->state = NS_JOB_WAITING;

-     return job;

- }

- 

- static ns_job_t *

- alloc_io_context(ns_thrpool_t *tp, PRFileDesc *fd, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_data_t *data)

- {

-     ns_job_t *job = new_ns_job(tp, fd, job_type, func, data);

- 

-     return job;

- }

- 

- static ns_job_t *

- alloc_timeout_context(ns_thrpool_t *tp, struct timeval *tv, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_data_t *data)

- {

-     ns_job_t *job = new_ns_job(tp, NULL, NS_JOB_TIMER | job_type, func, data);

-     job->tv = *tv;

- 

-     return job;

- }

- 

- static ns_job_t *

- alloc_signal_context(ns_thrpool_t *tp, PRInt32 signum, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_data_t *data)

- {

-     ns_job_t *job = new_ns_job(tp, NULL, NS_JOB_SIGNAL | job_type, func, data);

-     job->signal = signum;

- 

-     return job;

- }

- 

- ns_result_t

- ns_job_done(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     if (job == NULL) {

-         return NS_INVALID_REQUEST;

-     }

- 

-     /* Get the shutdown state ONCE at the start, atomically */

-     int32_t shutdown_state = ns_thrpool_is_shutdown(job->tp);

- 

-     pthread_mutex_lock(&(job->monitor));

- 

-     if (job->state == NS_JOB_NEEDS_DELETE || job->state == NS_JOB_DELETED) {

- /* Just return if the job has been marked for deletion */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_job_done %x tp shutdown -> %x state %d return early\n", job, shutdown_state, job->state);

- #endif

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     }

- 

-     /* Do not allow an armed job to be removed UNLESS the server is shutting down */

-     if (job->state == NS_JOB_ARMED && !shutdown_state) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_job_done %x tp shutdown -> false state %d failed to mark as done\n", job, job->state);

- #endif

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_INVALID_STATE;

-     }

- 

-     if (job->state == NS_JOB_RUNNING || job->state == NS_JOB_NEEDS_ARM) {

- /* For this to be called, and NS_JOB_RUNNING, we *must* be the callback thread! */

- /* Just mark it (ie do nothing), the work_job_execute function will trigger internal_ns_job_done */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_job_done %x tp shutdown -> false state %d setting to async NS_JOB_NEEDS_DELETE\n", job, job->state);

- #endif

-         job->state = NS_JOB_NEEDS_DELETE;

-         pthread_mutex_unlock(&(job->monitor));

-     } else if (!shutdown_state) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_job_done %x tp shutdown -> false state %d setting NS_JOB_NEEDS_DELETE and queuing\n", job, job->state);

- #endif

-         job->state = NS_JOB_NEEDS_DELETE;

-         pthread_mutex_unlock(&(job->monitor));

-         event_q_notify(job);

-     } else {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_job_done %x tp shutdown -> true state %d setting NS_JOB_NEEDS_DELETE and delete immediate\n", job, job->state);

- #endif

-         job->state = NS_JOB_NEEDS_DELETE;

-         /* We are shutting down, just remove it! */

-         pthread_mutex_unlock(&(job->monitor));

-         internal_ns_job_done(job);

-     }

-     return NS_SUCCESS;

- }

- 

- ns_result_t

- ns_create_job(struct ns_thrpool_t *tp, ns_job_type_t job_type, ns_job_func_t func, struct ns_job_t **job)

- {

-     if (job == NULL) {

-         /* This won't queue the job, so to pass NULL makes no sense */

-         return NS_INVALID_REQUEST;

-     }

- 

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     *job = new_ns_job(tp, NULL, job_type, func, NULL);

-     if (*job == NULL) {

-         return NS_ALLOCATION_FAILURE;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- /* queue a file descriptor to listen for and accept new connections */

- ns_result_t

- ns_add_io_job(ns_thrpool_t *tp, PRFileDesc *fd, ns_job_type_t job_type, ns_job_func_t func, void *data, ns_job_t **job)

- {

-     ns_job_t *_job = NULL;

- 

-     if (job) {

-         *job = NULL;

-     }

- 

-     /* Don't allow a job to be added if the threadpool is being shut down. */

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     /* Don't allow an accept job to be run outside of the event thread.

-      * We do this so a listener job won't shut down while still processing

-      * current connections in other threads.

-      * TODO: Need to be able to have multiple threads accept() at the same time

-      * This is fine - just have to remove the listen job in the polling thread

-      * immediately after receiving notification - then call the job to do the

-      * accept(), which will add back the persistent listener job immediately after

-      * doing the accept()

-      * This will be a combination of a non-threaded job and a threaded job

-      *

-      */

-     if (NS_JOB_IS_ACCEPT(job_type) && NS_JOB_IS_THREAD(job_type)) {

-         return NS_INVALID_REQUEST;

-     }

- 

-     /* get an event context for an accept */

-     _job = alloc_io_context(tp, fd, job_type, func, data);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

- 

-     pthread_mutex_lock(&(_job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_add_io_job state %d moving to NS_JOB_ARMED\n", (_job)->state);

- #endif

-     _job->state = NS_JOB_NEEDS_ARM;

-     pthread_mutex_unlock(&(_job->monitor));

-     internal_ns_job_rearm(_job);

- 

-     /* fill in a pointer to the job for the caller if requested */

-     if (job) {

-         *job = _job;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- ns_result_t

- ns_add_timeout_job(ns_thrpool_t *tp, struct timeval *tv, ns_job_type_t job_type, ns_job_func_t func, void *data, ns_job_t **job)

- {

-     ns_job_t *_job = NULL;

- 

-     if (job) {

-         *job = NULL;

-     }

- 

-     /* Don't allow a job to be added if the threadpool is being shut down. */

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     if (validate_event_timeout(tv)) {

-         return NS_INVALID_REQUEST;

-     }

- 

-     /* get an event context for a timer job */

-     _job = alloc_timeout_context(tp, tv, job_type, func, data);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

- 

-     pthread_mutex_lock(&(_job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_add_timeout_job state %d moving to NS_JOB_ARMED\n", (_job)->state);

- #endif

-     _job->state = NS_JOB_NEEDS_ARM;

-     pthread_mutex_unlock(&(_job->monitor));

-     internal_ns_job_rearm(_job);

- 

-     /* fill in a pointer to the job for the caller if requested */

-     if (job) {

-         *job = _job;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- /* queue a file descriptor to listen for and accept new connections */

- ns_result_t

- ns_add_io_timeout_job(ns_thrpool_t *tp, PRFileDesc *fd, struct timeval *tv, ns_job_type_t job_type, ns_job_func_t func, void *data, ns_job_t **job)

- {

-     ns_job_t *_job = NULL;

- 

-     if (job) {

-         *job = NULL;

-     }

- 

-     /* Don't allow a job to be added if the threadpool is being shut down. */

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     if (validate_event_timeout(tv)) {

-         return NS_INVALID_REQUEST;

-     }

- 

-     /* Don't allow an accept job to be run outside of the event thread.

-      * We do this so a listener job won't shut down while still processing

-      * current connections in other threads.

-      * TODO: Need to be able to have multiple threads accept() at the same time

-      * This is fine - just have to remove the listen job in the polling thread

-      * immediately after receiving notification - then call the job to do the

-      * accept(), which will add back the persistent listener job immediately after

-      * doing the accept()

-      * This will be a combination of a non-threaded job and a threaded job

-      *

-      */

-     if (NS_JOB_IS_ACCEPT(job_type) && NS_JOB_IS_THREAD(job_type)) {

-         return NS_INVALID_REQUEST;

-     }

- 

-     /* get an event context for an accept */

-     _job = alloc_io_context(tp, fd, job_type | NS_JOB_TIMER, func, data);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

-     pthread_mutex_lock(&(_job->monitor));

-     _job->tv = *tv;

- 

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_add_io_timeout_job state %d moving to NS_JOB_ARMED\n", (_job)->state);

- #endif

-     _job->state = NS_JOB_NEEDS_ARM;

-     pthread_mutex_unlock(&(_job->monitor));

-     internal_ns_job_rearm(_job);

- 

-     /* fill in a pointer to the job for the caller if requested */

-     if (job) {

-         *job = _job;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- ns_result_t

- ns_add_signal_job(ns_thrpool_t *tp, int32_t signum, ns_job_type_t job_type, ns_job_func_t func, void *data, ns_job_t **job)

- {

-     ns_job_t *_job = NULL;

- 

-     if (job) {

-         *job = NULL;

-     }

- 

-     /* Don't allow a job to be added if the threadpool is being shut down. */

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     /* get an event context for a signal job */

-     _job = alloc_signal_context(tp, signum, job_type, func, data);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

- 

-     pthread_mutex_lock(&(_job->monitor));

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_add_signal_job state %d moving to NS_JOB_ARMED\n", (_job)->state);

- #endif

-     _job->state = NS_JOB_NEEDS_ARM;

-     pthread_mutex_unlock(&(_job->monitor));

-     internal_ns_job_rearm(_job);

- 

-     /* fill in a pointer to the job for the caller if requested */

-     if (job) {

-         *job = _job;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- ns_result_t

- ns_add_job(ns_thrpool_t *tp, ns_job_type_t job_type, ns_job_func_t func, void *data, ns_job_t **job)

- {

-     ns_job_t *_job = NULL;

- 

-     if (job) {

-         *job = NULL;

-     }

- 

-     /* Don't allow a job to be added if the threadpool is being shut down. */

-     if (ns_thrpool_is_shutdown(tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     _job = new_ns_job(tp, NULL, job_type, func, data);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

-     /* fill in a pointer to the job for the caller if requested */

-     if (job) {

-         *job = _job;

-     }

- 

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_add_job %x state %d moving to NS_JOB_ARMED\n", _job, (_job)->state);

- #endif

-     _job->state = NS_JOB_NEEDS_ARM;

-     internal_ns_job_rearm(_job);

- 

-     return NS_SUCCESS;

- }

- 

- ns_result_t

- ns_add_shutdown_job(ns_thrpool_t *tp)

- {

-     ns_job_t *_job = NULL;

-     _job = new_ns_job(tp, NULL, NS_JOB_SHUTDOWN_WORKER, NULL, NULL);

-     if (!_job) {

-         return NS_ALLOCATION_FAILURE;

-     }

-     pthread_mutex_lock(&(_job->monitor));

-     _job->state = NS_JOB_NEEDS_ARM;

-     pthread_mutex_unlock(&(_job->monitor));

-     internal_ns_job_rearm(_job);

-     return NS_SUCCESS;

- }

- 

- /*

-  * Because of the design of work_job_execute, when we are in RUNNING

-  * we hold the monitor. As a result, we don't need to assert the current thread

-  * because we *already must* be the current thread, as no one else could take

-  * the monitor away.

-  *

-  * The same is true of DELETED, which represents that we are deleting things.

-  * To set NEEDS_DELETE -> DELETED, we must hold the monitor, and at that point

-  * the monitor is released and the job destroyed. As a result, we only need to

-  * assert that we are not "NEEDS_DELETE" in many cases.

-  */

- 

- void *

- ns_job_get_data(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state != NS_JOB_DELETED);

-     if (job->state != NS_JOB_DELETED) {

-         pthread_mutex_unlock(&(job->monitor));

-         return job->data;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NULL;

-     }

- }

- 

- ns_result_t

- ns_job_set_data(ns_job_t *job, void *data)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state == NS_JOB_WAITING || job->state == NS_JOB_RUNNING);

-     if (job->state == NS_JOB_WAITING || job->state == NS_JOB_RUNNING) {

-         job->data = data;

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_INVALID_STATE;

-     }

- }

- 

- ns_thrpool_t *

- ns_job_get_tp(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state != NS_JOB_DELETED);

-     if (job->state != NS_JOB_DELETED) {

-         pthread_mutex_unlock(&(job->monitor));

-         return job->tp;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NULL;

-     }

- }

- 

- ns_job_type_t

- ns_job_get_output_type(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state == NS_JOB_RUNNING);

-     if (job->state == NS_JOB_RUNNING) {

-         pthread_mutex_unlock(&(job->monitor));

-         return job->output_job_type;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return 0;

-     }

- }

- 

- ns_job_type_t

- ns_job_get_type(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state != NS_JOB_DELETED);

-     if (job->state != NS_JOB_DELETED) {

-         pthread_mutex_unlock(&(job->monitor));

-         return job->job_type;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return 0;

-     }

- }

- 

- PRFileDesc *

- ns_job_get_fd(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state != NS_JOB_DELETED);

-     if (job->state != NS_JOB_DELETED) {

-         pthread_mutex_unlock(&(job->monitor));

-         return job->fd;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NULL;

-     }

- }

- 

- ns_result_t

- ns_job_set_done_cb(struct ns_job_t *job, ns_job_func_t func)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state == NS_JOB_WAITING || job->state == NS_JOB_RUNNING);

-     if (job->state == NS_JOB_WAITING || job->state == NS_JOB_RUNNING) {

-         job->done_cb = func;

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_INVALID_STATE;

-     }

- }

- 

- ns_result_t

- ns_job_wait(struct ns_job_t *job) {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     if (job->state == NS_JOB_WAITING) {

-         /* It's done */

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     } else {

-         pthread_cond_wait(&(job->notify), &(job->monitor));

-         ns_job_state_t result = job->state;

-         pthread_mutex_unlock(&(job->monitor));

-         if (result == NS_JOB_WAITING) {

-             return NS_SUCCESS;

-         } else if (result == NS_JOB_NEEDS_DELETE) {

-             return NS_DELETING;

-         } else {

-             PR_ASSERT(1 == 0);

-             return NS_INVALID_STATE;

-         }

-     }

- }

- 

- /*

-  * This is a convenience function - use if you need to re-arm the same event

-  * usually not needed for persistent jobs

-  */

- ns_result_t

- ns_job_rearm(ns_job_t *job)

- {

-     PR_ASSERT(job);

-     pthread_mutex_lock(&(job->monitor));

-     PR_ASSERT(job->state == NS_JOB_WAITING || job->state == NS_JOB_RUNNING);

- 

-     if (ns_thrpool_is_shutdown(job->tp)) {

-         return NS_SHUTDOWN;

-     }

- 

-     if (job->state == NS_JOB_WAITING) {

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_rearm_job %x state %d moving to NS_JOB_NEEDS_ARM\n", job, job->state);

- #endif

-         job->state = NS_JOB_NEEDS_ARM;

-         internal_ns_job_rearm(job);

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     } else if (!NS_JOB_IS_PERSIST(job->job_type) && job->state == NS_JOB_RUNNING) {

- /* For this to be called, and NS_JOB_RUNNING, we *must* be the callback thread! */

- /* Just mark it (ie do nothing), the work_job_execute function will trigger internal_ns_job_rearm */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_rearm_job %x state %d setting NS_JOB_NEEDS_ARM\n", job, job->state);

- #endif

-         job->state = NS_JOB_NEEDS_ARM;

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_SUCCESS;

-     } else {

-         pthread_mutex_unlock(&(job->monitor));

-         return NS_INVALID_STATE;

-     }

-     /* Unreachable code .... */

-     return NS_INVALID_REQUEST;

- }

- int

- ns_job_is_func(struct ns_job_t *job, ns_job_func_t func)

- {

-     return(job && job->func == func);

- }

- 

- static void

- ns_thrpool_delete(ns_thrpool_t *tp)

- {

-     ns_free(tp);

- }

- 

- static ns_thrpool_t *

- ns_thrpool_alloc(void)

- {

-     ns_thrpool_t *tp;

- 

-     tp = ns_calloc(1, sizeof(struct ns_thrpool_t));

-     if (NULL == tp) {

-         goto failed;

-     }

- 

-     return tp;

- failed:

-     ns_thrpool_delete(tp);

-     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);

-     return NULL;

- }

- 

- /* libevent does not make public the file descriptors used to

-    wakeup epoll_wait - you have to send a signal - instead of

-    that just create our own wakeup pipe */

- static void

- setup_event_q_wakeup(ns_thrpool_t *tp)

- {

-     ns_job_t *job;

-     PR_CreatePipe(&tp->event_q_wakeup_pipe_read, &tp->event_q_wakeup_pipe_write);

-     /* setting options is not supported on NSPR pipes - use fcntl

-     PRSocketOptionData prsod = {PR_SockOpt_Nonblocking, {PR_TRUE}};

-     PR_SetSocketOption(tp->event_q_wakeup_pipe_read, &prsod);

-     PR_SetSocketOption(tp->event_q_wakeup_pipe_write, &prsod);

-     */

-     if (fcntl(PR_FileDesc2NativeHandle(tp->event_q_wakeup_pipe_read), F_SETFD, O_NONBLOCK) == -1) {

-         ns_log(LOG_ERR, "setup_event_q_wakeup(): could not make read pipe non-blocking: %d\n",

-                PR_GetOSError());

-     }

-     if (fcntl(PR_FileDesc2NativeHandle(tp->event_q_wakeup_pipe_write), F_SETFD, O_NONBLOCK) == -1) {

-         ns_log(LOG_ERR, "setup_event_q_wakeup(): could not make write pipe non-blocking: %d\n",

-                PR_GetOSError());

-     }

-     /* wakeup events are processed inside the event loop thread */

-     job = alloc_io_context(tp, tp->event_q_wakeup_pipe_read,

-                            NS_JOB_READ | NS_JOB_PERSIST | NS_JOB_PRESERVE_FD,

-                            wakeup_cb, NULL);

- 

-     pthread_mutex_lock(&(job->monitor));

- 

- /* The event_queue wakeup is ready, arm it. */

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "setup_event_q_wakeup %x state %d moving NS_JOB_ARMED\n", job, job->state);

- #endif

-     job->state = NS_JOB_ARMED;

- 

-     /* Now allow it to process events */

-     tp->ns_event_fw->ns_event_fw_add_io(tp->ns_event_fw_ctx, job);

- 

-     /* Stash the wakeup job in tp so we can release it later. */

-     tp->event_q_wakeup_job = job;

-     pthread_mutex_unlock(&(job->monitor));

- }

- 

- /* Initialize the thrpool config */

- #define NS_INIT_MAGIC 0xdefa014

- 

- void

- ns_thrpool_config_init(struct ns_thrpool_config *tp_config)

- {

-     tp_config->init_flag = NS_INIT_MAGIC;

-     tp_config->max_threads = 1;

-     tp_config->stacksize = 0;

-     tp_config->log_fct = NULL;

-     tp_config->log_start_fct = NULL;

-     tp_config->log_close_fct = NULL;

-     tp_config->malloc_fct = NULL;

-     tp_config->memalign_fct = NULL;

-     tp_config->calloc_fct = NULL;

-     tp_config->realloc_fct = NULL;

-     tp_config->free_fct = NULL;

- }

- 

- /*

-  * Process the config and set the pluggable function pointers

-  */

- static ns_result_t

- ns_thrpool_process_config(struct ns_thrpool_config *tp_config)

- {

-     /* Check that the config has been properly initialized */

-     if (!tp_config || tp_config->init_flag != NS_INIT_MAGIC) {

-         return NS_INVALID_REQUEST;

-     }

-     /*

-      * Assign our logging function pointers

-      */

-     if (tp_config->log_fct) {

-         /* Set a logger function */

-         logger = tp_config->log_fct;

-         if (tp_config->log_start_fct) {

-             log_start = tp_config->log_start_fct;

-         }

-         if (tp_config->log_close_fct) {

-             log_close = tp_config->log_close_fct;

-         }

-     } else {

-         /* Default to syslog */

-         logger = ns_syslog;

-         log_start = ns_syslog_start;

-         log_close = ns_syslog_close;

-     }

-     if (log_start) {

-         /* Start logging */

-         (log_start)();

-     }

- 

-     /*

-      * Set the memory function pointers

-      */

-     /* malloc */

-     if (tp_config->malloc_fct) {

-         malloc_fct = tp_config->malloc_fct;

-     } else {

-         malloc_fct = os_malloc;

-     }

- 

-     if (tp_config->memalign_fct) {

-         memalign_fct = tp_config->memalign_fct;

-     } else {

-         memalign_fct = os_memalign_malloc;

-     }

- 

-     /* calloc */

-     if (tp_config->calloc_fct) {

-         calloc_fct = tp_config->calloc_fct;

-     } else {

-         calloc_fct = os_calloc;

-     }

-     /* realloc */

-     if (tp_config->realloc_fct) {

-         realloc_fct = tp_config->realloc_fct;

-     } else {

-         realloc_fct = os_realloc;

-     }

-     /* free */

-     if (tp_config->free_fct) {

-         free_fct = tp_config->free_fct;

-     } else {

-         free_fct = os_free;

-     }

- 

-     return NS_SUCCESS;

- }

- 

- ns_thrpool_t *

- ns_thrpool_new(struct ns_thrpool_config *tp_config)

- {

-     pthread_attr_t attr;

-     ns_thrpool_t *tp = NULL;

-     ns_thread_t *thr;

-     size_t ii;

- 

-     if (ns_thrpool_process_config(tp_config) != NS_SUCCESS) {

-         ns_log(LOG_ERR, "ns_thrpool_new(): config has not been properly initialized\n");

-         goto failed;

-     }

- 

-     tp = ns_thrpool_alloc();

-     if (NULL == tp) {

-         ns_log(LOG_ERR, "ns_thrpool_new(): failed to allocate thread pool\n");

-         goto failed;

-     }

- 

-     ns_log(LOG_DEBUG, "ns_thrpool_new():  max threads, (%d)\n"

-                       "stacksize (%d), event q size (unbounded), work q size (unbounded)\n",

-            tp_config->max_threads, tp_config->stacksize);

- 

-     tp->stacksize = tp_config->stacksize;

- 

-     if (sds_queue_init(&(tp->thread_stack), NULL) != SDS_SUCCESS) {

-         goto failed;

-     }

- 

-     if (pthread_mutex_init(&(tp->work_q_lock), NULL) != 0) {

-         goto failed;

-     }

-     if (pthread_cond_init(&(tp->work_q_cv), NULL) != 0) {

-         goto failed;

-     }

- 

-     if (sds_lqueue_init(&(tp->work_q), job_queue_cleanup) != SDS_SUCCESS) {

-         goto failed;

-     }

-     if (sds_lqueue_init(&(tp->event_q), job_queue_cleanup) != SDS_SUCCESS) {

-         goto failed;

-     }

- 

-     /* NGK TODO - add tevent vs. libevent switch */

-     /* tp->ns_event_fw = get_event_framework_tevent(); */

-     tp->ns_event_fw = get_event_framework_event();

-     tp->ns_event_fw_ctx = tp->ns_event_fw->ns_event_fw_init();

- 

-     setup_event_q_wakeup(tp);

- 

-     /* Create the thread attributes. */

-     if (pthread_attr_init(&attr) != 0) {

-         goto failed;

-     }

-     /* Setup the stack size. */

-     if (tp_config->stacksize > 0) {

-         if (pthread_attr_setstacksize(&attr, tp_config->stacksize) != 0) {

-             goto failed;

-         }

-     }

- 

-     for (ii = 0; ii < tp_config->max_threads; ++ii) {

-         tp->thread_count += 1;

-         thr = ns_calloc(1, sizeof(ns_thread_t));

-         PR_ASSERT(thr);

-         thr->tp = tp;

-         assert(pthread_create(&(thr->thr), &attr, &worker_thread_func, thr) == 0);

-         sds_queue_enqueue(tp->thread_stack, thr);

-     }

- 

-     assert(pthread_create(&(tp->event_thread), &attr, &event_loop_thread_func, tp) == 0);

- 

-     /* We keep the event thread separate from the stack of worker threads. */

-     // tp->event_thread = event_thr;

- 

-     return tp;

- failed:

-     ns_thrpool_destroy(tp);

-     return NULL;

- }

- 

- void

- ns_thrpool_destroy(struct ns_thrpool_t *tp)

- {

-     void *retval = NULL;

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_thrpool_destroy\n");

- #endif

-     if (tp) {

-         /* Set the flag to shutdown the event loop. */

- #ifdef ATOMIC_64BIT_OPERATIONS

-         __atomic_add_fetch(&(tp->shutdown_event_loop), 1, __ATOMIC_RELEASE);

- #else

-         PR_AtomicIncrement(&(tp->shutdown_event_loop));

- #endif

-         /* Finish the event queue wakeup job.  This has the

-          * side effect of waking up the event loop thread, which

-          * will cause it to exit since we set the event loop

-          * shutdown flag.  Fake the job to be a threaded job

-          * so that we can run it from outside the event loop,

-          * and use it to wake up the event loop.

-          */

- 

-         pthread_mutex_lock(&(tp->event_q_wakeup_job->monitor));

- 

- // tp->event_q_wakeup_job->job_type |= NS_JOB_THREAD;

- /* This triggers the job to "run", which will cause a shutdown cascade */

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_thrpool_destroy %x state %d moving to NS_JOB_NEEDS_DELETE\n", tp->event_q_wakeup_job, tp->event_q_wakeup_job->state);

- #endif

-         tp->event_q_wakeup_job->state = NS_JOB_NEEDS_DELETE;

-         pthread_mutex_unlock(&(tp->event_q_wakeup_job->monitor));

-         /* Has to be event_q_notify, not internal_job_done */

-         event_q_notify(tp->event_q_wakeup_job);

- 

-         /* Wait for the event thread to finish before we free the

-          * internals of tp. */

-         int32_t rc = pthread_join(tp->event_thread, &retval);

-         if (rc != 0) {

-             ns_log(LOG_DEBUG, "Failed to join event thread %d\n", rc);

-         }

- 

-         if (tp->work_q) {

-             sds_lqueue_destroy(tp->work_q);

-         }

- 

-         if (tp->thread_stack) {

-             sds_queue_destroy(tp->thread_stack);

-         }

- 

-         /* Free the work queue condition variable. */

-         pthread_cond_destroy(&(tp->work_q_cv));

-         /* Free the work queue lock. */

-         pthread_mutex_destroy(&(tp->work_q_lock));

- 

-         if (tp->event_q) {

-             sds_lqueue_destroy(tp->event_q);

-         }

- 

-         /* Free the event queue wakeup pipe/job. */

-         if (tp->event_q_wakeup_pipe_read) {

-             PR_Close(tp->event_q_wakeup_pipe_read);

-             tp->event_q_wakeup_pipe_read = NULL;

-         }

- 

-         if (tp->event_q_wakeup_pipe_write) {

-             PR_Close(tp->event_q_wakeup_pipe_write);

-             tp->event_q_wakeup_pipe_write = NULL;

-         }

-         /* Already destroyed in the event queue shutdown */

-         tp->event_q_wakeup_job = NULL;

- 

-         /* Free the event framework context. */

-         if (tp->ns_event_fw_ctx) {

-             tp->ns_event_fw->ns_event_fw_destroy(tp->ns_event_fw_ctx);

-             tp->ns_event_fw_ctx = NULL;

-         }

- 

-         /* Free the thread pool struct itself. */

-         ns_thrpool_delete(tp);

-     }

-     /* Stop logging */

-     if (log_close) {

-         (log_close)();

-     }

- }

- 

- /* Triggers the pool of worker threads to shutdown after finishing the remaining work.

-  * This must be run in a worker thread, not the event thread.  Running it in the event

-  * thread could cause a deadlock. */

- void

- ns_thrpool_shutdown(struct ns_thrpool_t *tp)

- {

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_thrpool_shutdown initiated ...\n");

- #endif

-     if (ns_thrpool_is_shutdown(tp) != 0) {

-         /* Already done! */

-         return;

-     }

- 

-     /* Set the shutdown flag.  This will cause the worker

-      * threads to exit after they finish all remaining work. */

- #ifdef ATOMIC_64BIT_OPERATIONS

-     __atomic_add_fetch(&(tp->shutdown), 1, __ATOMIC_RELEASE);

- #else

-     PR_AtomicIncrement(&(tp->shutdown));

- #endif

- 

-     /* Send worker shutdown jobs into the queues. This allows

-      * currently queued jobs to complete.

-      */

-     for (size_t i = 0; i < tp->thread_count; i++) {

-         ns_result_t result = ns_add_shutdown_job(tp);

-         if (result != NS_SUCCESS) {

- #ifdef DEBUG

-             ns_log(LOG_DEBUG, "ns_thrpool_shutdown - Failed to add shutdown job: error (%d)\n", result);

- #endif

-             PR_ASSERT(0);

-         }

-     }

-     /* Make sure all threads are woken up to their shutdown jobs. */

-     pthread_mutex_lock(&(tp->work_q_lock));

-     pthread_cond_broadcast(&(tp->work_q_cv));

-     pthread_mutex_unlock(&(tp->work_q_lock));

- }

- 

- ns_result_t

- ns_thrpool_wait(ns_thrpool_t *tp)

- {

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_thrpool_wait has begun\n");

- #endif

-     ns_result_t retval = NS_SUCCESS;

-     ns_thread_t *thr;

- 

-     while (sds_queue_dequeue(tp->thread_stack, (void **)&thr) == SDS_SUCCESS) {

-         /* void *thread_retval = NULL; */

-         int32_t rc = pthread_join(thr->thr, NULL);

- #ifdef DEBUG

-         ns_log(LOG_DEBUG, "ns_thrpool_wait joined thread, result %d\n", rc);

- #endif

-         if (rc != 0) {

-             /* NGK TODO - this is unused right now. */

-             ns_log(LOG_ERR, "ns_thrpool_wait, failed to join thread %d", rc);

-             retval = NS_THREAD_FAILURE;

-         }

-         ns_free(thr);

-     }

- 

- 

- #ifdef DEBUG

-     ns_log(LOG_DEBUG, "ns_thrpool_wait complete, retval %d\n", retval);

- #endif

-     return retval;

- }

- 

- /*

-  * nunc stans logger

-  */

- void

- ns_log(int priority, const char *fmt, ...)

- {

-     va_list varg;

- 

-     va_start(varg, fmt);

-     ns_log_valist(priority, fmt, varg);

-     va_end(varg);

- }

- 

- void

- ns_log_valist(int priority, const char *fmt, va_list varg)

- {

-     (logger)(priority, fmt, varg);

- }

- 

- /*

-  * Pluggable memory functions

-  */

- void *

- ns_malloc(size_t size)

- {

-     return (malloc_fct)(size);

- }

- 

- void *

- ns_memalign(size_t size, size_t alignment)

- {

-     return (memalign_fct)(size, alignment);

- }

- 

- void *

- ns_calloc(size_t count, size_t size)

- {

-     return (calloc_fct)(count, size);

- }

- 

- void *

- ns_realloc(void *ptr, size_t size)

- {

-     return (realloc_fct)(ptr, size);

- }

- 

- void

- ns_free(void *ptr)

- {

-     (free_fct)(ptr);

- }

@@ -1,292 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #include "nspr.h"

- #include "prio.h"

- #include "secitem.h"

- #include "nss.h"

- #include "ssl.h"

- #include "cert.h"

- #include "pk11pub.h"

- #include "keyhi.h"

- 

- #include "ns_tls.h"

- #include <syslog.h>

- #include "ns_private.h"

- 

- struct ns_sec_ctx_t

- {

-     NSSInitContext *initctx;

-     NSSInitParameters init_params;

-     PRFileDesc *model_fd;

-     PRBool is_client;

- };

- 

- typedef struct ns_sec_ctx_t ns_sec_ctx_t;

- 

- static void

- errExit(const char *msg)

- {

-     ns_log(LOG_ERR, msg);

- }

- 

- static PRFileDesc *

- create_tls_model_sock(const char *certname, PRBool is_client)

- {

-     PRFileDesc *model_sock = NULL;

-     int rv;

-     SECStatus secStatus;

-     PRBool disableSSL2 = PR_TRUE;

-     PRBool disableSSL3 = PR_FALSE;

-     PRBool disableTLS = PR_FALSE;

-     PRBool disableRollBack = PR_FALSE;

-     PRBool NoReuse = PR_FALSE;

-     PRBool disableStepDown = PR_FALSE;

-     PRBool bypassPKCS11 = PR_FALSE;

-     PRBool disableLocking = PR_FALSE;

-     PRBool enableFDX = PR_FALSE;

-     PRBool enableSessionTickets = PR_FALSE;

-     PRBool enableCompression = PR_FALSE;

-     SSLKEAType certKEA;

- 

-     model_sock = PR_NewTCPSocket();

-     if (model_sock == NULL) {

-         errExit("PR_NewTCPSocket on model socket");

-     }

-     model_sock = SSL_ImportFD(NULL, model_sock);

-     if (model_sock == NULL) {

-         errExit("SSL_ImportFD");

-     }

- 

-     /* do SSL configuration. */

-     rv = SSL_OptionSet(model_sock, SSL_SECURITY,

-                        !(disableSSL2 && disableSSL3 && disableTLS));

-     if (rv != SECSuccess) {

-         errExit("SSL_OptionSet SSL_SECURITY");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL3, !disableSSL3);

-     if (rv != SECSuccess) {

-         errExit("error enabling SSLv3 ");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_ENABLE_TLS, !disableTLS);

-     if (rv != SECSuccess) {

-         errExit("error enabling TLS ");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, !disableSSL2);

-     if (rv != SECSuccess) {

-         errExit("error enabling SSLv2 ");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack);

-     if (rv != SECSuccess) {

-         errExit("error enabling RollBack detection ");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_HANDSHAKE_AS_CLIENT, is_client);

-     if (rv != SECSuccess) {

-         errExit("error handshake as client ");

-     }

- 

-     rv = SSL_OptionSet(model_sock, SSL_HANDSHAKE_AS_SERVER, !is_client);

-     if (rv != SECSuccess) {

-         errExit("error handshake as server ");

-     }

- 

-     if (disableStepDown) {

-         rv = SSL_OptionSet(model_sock, SSL_NO_STEP_DOWN, PR_TRUE);

-         if (rv != SECSuccess) {

-             errExit("error disabling SSL StepDown ");

-         }

-     }

-     if (bypassPKCS11) {

-         rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, PR_TRUE);

-         if (rv != SECSuccess) {

-             errExit("error enabling PKCS11 bypass ");

-         }

-     }

-     if (disableLocking) {

-         rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, PR_TRUE);

-         if (rv != SECSuccess) {

-             errExit("error disabling SSL socket locking ");

-         }

-     }

-     if (enableSessionTickets) {

-         rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);

-         if (rv != SECSuccess) {

-             errExit("error enabling Session Ticket extension ");

-         }

-     }

- 

-     if (enableCompression) {

-         rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);

-         if (rv != SECSuccess) {

-             errExit("error enabling compression ");

-         }

-     }

- 

-     /* handle ciphers here - SSL_CipherPrefSetDefault etc. */

- 

-     /*

-     rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,

-                                  (void*)&virtServerNameArray);

-     if (rv != SECSuccess) {

-         errExit("error enabling SNI extension ");

-     }

-     */

- 

-     if (!is_client) {

-         CERTCertificate *cert;

-         SECKEYPrivateKey *privKey;

- 

-         cert = PK11_FindCertFromNickname(certname, NULL);

-         if (cert == NULL) {

-             ns_log(LOG_ERR, "selfserv: Can't find certificate %s\n", certname);

-             exit(10);

-         }

-         privKey = PK11_FindKeyByAnyCert(cert, NULL);

-         if (privKey == NULL) {

-             ns_log(LOG_ERR, "selfserv: Can't find Private Key for cert %s\n", certname);

-             exit(11);

-         }

-         certKEA = NSS_FindCertKEAType(cert);

-         secStatus = SSL_ConfigSecureServer(model_sock, cert, privKey, certKEA);

-         if (secStatus != SECSuccess) {

-             errExit("SSL_ConfigSecureServer");

-         }

-         CERT_DestroyCertificate(cert);

-         SECKEY_DestroyPrivateKey(privKey);

-         SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);

-     }

- 

-     if (enableFDX) { /* doing FDX */

-         rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);

-         if (rv != SECSuccess) {

-             errExit("SSL_OptionSet SSL_ENABLE_FDX");

-         }

-     }

- 

-     if (NoReuse) {

-         rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);

-         if (rv != SECSuccess) {

-             errExit("SSL_OptionSet SSL_NO_CACHE");

-         }

-     }

- 

-     /*

-     if (expectedHostNameVal) {

-         SSL_HandshakeCallback(model_sock, handshakeCallback,

-                               (void*)expectedHostNameVal);

-     }

-     */

- 

-     /*

-     SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,

-                             (void *)CERT_GetDefaultCertDB());

-     */

- 

-     rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE, PR_TRUE);

-     if (rv != SECSuccess) {

-         errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");

-     }

-     rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE, PR_FALSE);

-     if (rv != SECSuccess) {

-         errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");

-     }

- 

-     /* end of ssl configuration. */

-     return model_sock;

- }

- 

- void

- ns_tls_done(ns_sec_ctx_t *ctx)

- {

-     if (ctx->model_fd) {

-         PR_Close(ctx->model_fd);

-     }

-     if (ctx->initctx) {

-         NSS_ShutdownContext(ctx->initctx);

-     }

-     ns_free(ctx);

- }

- 

- ns_sec_ctx_t *

- ns_tls_init(const char *dir, const char *prefix, const char *certname, PRBool is_client)

- {

-     SECStatus rc = SECSuccess;

-     ns_sec_ctx_t *ctx = ns_calloc(1, sizeof(ns_sec_ctx_t));

- 

-     ctx->init_params.length = sizeof(ctx->init_params);

-     ctx->initctx = NSS_InitContext(dir, prefix, prefix, SECMOD_DB,

-                                    &ctx->init_params, NSS_INIT_READONLY);

-     if (ctx->initctx == NULL) {

-         rc = SECFailure;

-         goto fail;

-     }

- 

-     NSS_SetDomesticPolicy();

- 

-     ctx->model_fd = create_tls_model_sock(certname, is_client);

-     if (ctx->model_fd == NULL) {

-         rc = SECFailure;

-         goto fail;

-     }

- 

- fail:

-     if (rc != SECSuccess) {

-         ns_tls_done(ctx);

-         ctx = NULL;

-     }

- 

-     return ctx;

- }

- 

- PRErrorCode

- ns_add_sec_layer(PRFileDesc *fd, ns_sec_ctx_t *ctx)

- {

-     PRErrorCode err = PR_SUCCESS;

- 

-     fd = SSL_ImportFD(ctx->model_fd, fd);

-     if (fd == NULL) {

-         err = PR_GetError();

-         goto fail;

-     }

- 

-     if (SECSuccess != SSL_ResetHandshake(fd, !ctx->is_client)) {

-         err = PR_GetError();

-         goto fail;

-     }

- 

- fail:

-     return err;

- }

@@ -1,49 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2015  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- #ifndef NS_TLS_H

- #define NS_TLS_H

- 

- #include "nspr.h"

- #include "prerror.h"

- #include "prio.h"

- 

- /* should be in sec_ctx.h */

- struct ns_sec_ctx_t;

- /* adds the sec layer _in place_ to fd - if error returned, the sec

-    layer is unstable and the fd should be closed and discarded */

- PRErrorCode ns_add_sec_layer(PRFileDesc *fd, struct ns_sec_ctx_t *ctx);

- 

- /* tls specific functions */

- void ns_tls_done(struct ns_sec_ctx_t *ctx);

- struct ns_sec_ctx_t *ns_tls_init(const char *dir, const char *prefix, const char *certname, PRBool isClient);

- 

- #endif /* NS_TLS_H */

@@ -1,533 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2016  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- 

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- /* For cmocka */

- #include <stdarg.h>

- #include <stddef.h>

- #include <setjmp.h>

- #include <cmocka.h>

- 

- /* For string and time manipulation in tests */

- #include <unistd.h>

- #include <string.h>

- 

- /* For signaling tests */

- #include <signal.h>

- 

- /* NS requries inttypes.h */

- #include <inttypes.h>

- 

- /* For NS itself */

- #include <nunc-stans.h>

- /* We need the internal headers for state checks */

- #include "../ns/ns_event_fw.h"

- 

- #include <assert.h>

- 

- #include <time.h>

- 

- #ifdef HAVE_STDLIB_H

- #include <stdlib.h>

- #endif

- 

- 

- static int cb_check = 0;

- 

- static pthread_mutex_t cb_lock;

- static pthread_cond_t cb_cond;

- // static PRLock *cb_lock = NULL;

- // static PRCondVar *cb_cond = NULL;

- 

- void

- ns_test_logger(int priority __attribute__((unused)), const char *fmt, va_list varg)

- {

-     // Should we do anything with priority?

-     vprintf(fmt, varg);

- }

- 

- static int

- cond_wait_rel(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict reltime) {

-     struct timespec now;

-     struct timespec abswait;

- 

-     clock_gettime(CLOCK_REALTIME, &now);

- 

-     abswait.tv_sec = now.tv_sec + reltime->tv_sec;

-     abswait.tv_nsec = now.tv_nsec + reltime->tv_nsec;

- 

-     return pthread_cond_timedwait(cond, mutex, &abswait);

- }

- 

- /* All our other tests will use this in some form. */

- static int

- ns_test_setup(void **state)

- {

-     /* Ensure that we can create a new nunc-stans instance. */

-     struct ns_thrpool_t *tp = NULL;

-     struct ns_thrpool_config ns_config;

-     /* Reset the callback check */

-     cb_check = 0;

-     /* Create the cond var the CB check will use. */

-     assert(pthread_mutex_init(&cb_lock, NULL) == 0);

-     assert(pthread_cond_init(&cb_cond, NULL) == 0);

- 

-     ns_thrpool_config_init(&ns_config);

- 

-     ns_config.log_fct = ns_test_logger;

-     ns_config.max_threads = 4;

-     tp = ns_thrpool_new(&ns_config);

-     assert_non_null(tp);

- 

-     *state = tp;

- 

-     return 0;

- }

- 

- static int

- ns_test_teardown(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     ns_thrpool_shutdown(tp);

-     assert_int_equal(ns_thrpool_wait(tp), 0);

- 

-     ns_thrpool_destroy(tp);

- 

-     pthread_cond_destroy(&cb_cond);

-     pthread_mutex_destroy(&cb_lock);

- 

-     return 0;

- }

- 

- static void

- ns_init_test_job_cb(struct ns_job_t *job __attribute__((unused)))

- {

-     pthread_mutex_lock(&cb_lock);

-     cb_check += 1;

-     pthread_cond_signal(&cb_cond);

-     pthread_mutex_unlock(&cb_lock);

- }

- 

- static void

- ns_init_disarm_job_cb(struct ns_job_t *job)

- {

-     if (ns_job_done(job) == NS_SUCCESS) {

-         pthread_mutex_lock(&cb_lock);

-         cb_check = 1;

-         pthread_cond_signal(&cb_cond);

-         pthread_mutex_unlock(&cb_lock);

-     } else {

-         assert_int_equal(1, 0);

-     }

- }

- 

- static void

- ns_init_do_nothing_cb(struct ns_job_t *job __attribute__((unused)))

- {

-     /* I mean it, do nothing! */

-     return;

- }

- 

- static void

- ns_init_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {1, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_add_job(tp, NS_JOB_NONE | NS_JOB_THREAD, ns_init_test_job_cb, NULL, &job),

-         0);

- 

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     assert_int_equal(cb_check, 1);

- 

-     /* Once the job is done, it's not in the event queue, and it's complete */

-     assert(ns_job_wait(job) == NS_SUCCESS);

-     assert_int_equal(ns_job_done(job), NS_SUCCESS);

- }

- 

- static void

- ns_set_data_test(void **state)

- {

-     /* Add a job with data */

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {1, 0};

- 

-     char *data = malloc(6);

- 

-     strcpy(data, "first");

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_add_job(tp, NS_JOB_NONE | NS_JOB_THREAD, ns_init_test_job_cb, data, &job),

-         NS_SUCCESS);

- 

-     /* Let the job run */

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     /* Check that the data is correct */

-     char *retrieved = (char *)ns_job_get_data(job);

-     assert_int_equal(strcmp("first", retrieved), 0);

- 

-     free(retrieved);

- 

-     /* set new data */

-     data = malloc(7);

-     strcpy(data, "second");

- 

-     assert(ns_job_wait(job) == NS_SUCCESS);

-     ns_job_set_data(job, data);

- 

-     /* Rearm, and let it run again. */

-     pthread_mutex_lock(&cb_lock);

-     ns_job_rearm(job);

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     /* Make sure it's now what we expect */

-     retrieved = (char *)ns_job_get_data(job);

-     assert_int_equal(strcmp("second", retrieved), 0);

- 

-     free(retrieved);

- 

-     /* Because the job is not queued, we must free it */

-     /*

-      * It's possible here, that the worker thread is still processing state

-      * as a result, we aren't the owning thread, and ns_job_done fails.

-      * So we actually have to loop on freeing this until it's released to

-      * waiting. we might need a load barrier here ...

-      */

- 

-     assert(ns_job_wait(job) == NS_SUCCESS);

- 

-     assert_int_equal(ns_job_done(job), NS_SUCCESS);

- }

- 

- static void

- ns_job_done_cb_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {1, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_create_job(tp, NS_JOB_NONE | NS_JOB_THREAD, ns_init_do_nothing_cb, &job),

-         NS_SUCCESS);

- 

-     ns_job_set_done_cb(job, ns_init_test_job_cb);

-     /* Remove it */

-     assert_int_equal(ns_job_done(job), NS_SUCCESS);

- 

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     assert_int_equal(cb_check, 1);

- }

- 

- static void

- ns_init_rearm_job_cb(struct ns_job_t *job)

- {

-     if (ns_job_rearm(job) != NS_SUCCESS) {

-         pthread_mutex_lock(&cb_lock);

-         cb_check = 1;

-         /* we failed to re-arm as expected, let's go away ... */

-         assert_int_equal(ns_job_done(job), NS_SUCCESS);

-         pthread_cond_signal(&cb_cond);

-         pthread_mutex_unlock(&cb_lock);

-     } else {

-         assert_int_equal(1, 0);

-     }

- }

- 

- static void

- ns_job_persist_rearm_ignore_test(void **state)

- {

-     /* Test that rearm ignores the persistent job. */

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {1, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_create_job(tp, NS_JOB_NONE | NS_JOB_THREAD | NS_JOB_PERSIST, ns_init_rearm_job_cb, &job),

-         NS_SUCCESS);

- 

-     /* This *will* arm the job, and will trigger the cb. */

-     assert_int_equal(ns_job_rearm(job), 0);

-     /*

-      * Now when the CB fires, it will *try* to rearm, but will fail, so we

-      * should see only 1 in the cb_check.

-      */

- 

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     /* If we fail to rearm, this is set to 1 Which is what we want. */

-     assert_int_equal(cb_check, 1);

- }

- 

- static void

- ns_job_persist_disarm_test(void **state)

- {

-     /* Make a persistent job */

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {2, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_create_job(tp, NS_JOB_NONE | NS_JOB_PERSIST, ns_init_disarm_job_cb, &job),

-         NS_SUCCESS);

- 

-     assert_int_equal(ns_job_rearm(job), NS_SUCCESS);

- 

-     /* In the callback it should disarm */

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

-     /* Make sure it did */

-     assert_int_equal(cb_check, 1);

- }

- 

- /*

-  * This tests a very specific issue in the directory server code. It's possible

-  * that a job will try to disarm itself from within the worker thread. This can

-  * race, as the event thread will get the work, free the job. The worker then

-  * returns from the fn, and will heap-use-after-free because the job was

-  * yanked from under it. To test this, you *will* need ASAN enabled to detect

-  * the failure condition (it will crash and burn)

-  *

-  * The bug happens in ns_add_job, when it calls the cb.

-  * The moment we add this, it will then trigger the job to run in thrpool event_cb

-  * this of course will call job->func(job), in this case ns_init_race_done_job_cb.

-  * Because the race_done job sends to ns_job_done, this will free job in the event

-  * thread, but then the work thread will return after the PR_Sleep to event_cb.

-  * At this point, the wt attempts to access job->type and job->state, to determine

-  * if the job needs rearm. Because the et freed job, this is now a use after

-  * free.

-  */

- static void

- ns_init_race_done_job_cb(struct ns_job_t *job)

- {

-     ns_job_done(job);

-     /* We need to sleep to let the job race happen */

-     PR_Sleep(PR_SecondsToInterval(2));

-     pthread_mutex_lock(&cb_lock);

-     cb_check += 1;

-     pthread_cond_signal(&cb_cond);

-     pthread_mutex_unlock(&cb_lock);

- }

- 

- static void

- ns_job_race_done_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {5, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_add_job(tp, NS_JOB_NONE | NS_JOB_THREAD, ns_init_race_done_job_cb, NULL, &job),

-         NS_SUCCESS);

- 

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     assert_int_equal(cb_check, 1);

- }

- 

- /*

-  * This tests that when we raise a signal, we catch it and handle it correctly.

-  */

- 

- static void

- ns_job_signal_cb_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timespec timeout = {1, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(

-         ns_add_signal_job(tp, SIGUSR1, NS_JOB_SIGNAL, ns_init_test_job_cb, NULL, &job),

-         NS_SUCCESS);

- 

-     /* The addition of the signal job to the event fw is async */

-     PR_Sleep(PR_SecondsToInterval(2));

-     /* Send the signal ... */

-     raise(SIGUSR1);

- 

-     assert(cond_wait_rel(&cb_cond, &cb_lock, &timeout) == 0);

-     pthread_mutex_unlock(&cb_lock);

- 

-     assert_int_equal(cb_check, 1);

- 

-     /* Remove the signal job now */

-     assert_int_equal(ns_job_done(job), NS_SUCCESS);

- }

- 

- /*

-  * Test that given a timeout of -1, we fail to create a job.

-  */

- 

- static void

- ns_job_neg_timeout_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

- 

-     struct timeval tv = {-1, 0};

- 

-     PR_ASSERT(NS_INVALID_REQUEST == ns_add_io_timeout_job(tp, 0, &tv, NS_JOB_THREAD, ns_init_do_nothing_cb, NULL, NULL));

- 

-     PR_ASSERT(NS_INVALID_REQUEST == ns_add_timeout_job(tp, &tv, NS_JOB_THREAD, ns_init_do_nothing_cb, NULL, NULL));

- }

- 

- /*

-  * Test that a timeout job fires a within a time window

-  */

- 

- static void

- ns_timer_job_cb(struct ns_job_t *job)

- {

-     ns_job_done(job);

-     pthread_mutex_lock(&cb_lock);

-     cb_check += 1;

-     pthread_cond_signal(&cb_cond);

-     pthread_mutex_unlock(&cb_lock);

- }

- 

- static void

- ns_job_timer_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timeval tv = {3, 0};

-     struct timespec timeout = {2, 0};

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_true(ns_add_timeout_job(tp, &tv, NS_JOB_THREAD, ns_timer_job_cb, NULL, &job) == NS_SUCCESS);

- 

-     cond_wait_rel(&cb_cond, &cb_lock, &timeout);

-     // pthread_mutex_unlock(&cb_lock);

-     assert_int_equal(cb_check, 0);

- 

-     // pthread_mutex_lock(&cb_lock);

-     cond_wait_rel(&cb_cond, &cb_lock, &timeout);

-     pthread_mutex_unlock(&cb_lock);

-     assert_int_equal(cb_check, 1);

- }

- 

- /*

-  * Test that within a window, a looping timeout job has fired greater than X times.

-  */

- 

- static void

- ns_timer_persist_job_cb(struct ns_job_t *job)

- {

-     pthread_mutex_lock(&cb_lock);

-     cb_check += 1;

-     pthread_mutex_unlock(&cb_lock);

-     if (cb_check < 10) {

-         ns_job_rearm(job);

-     } else {

-         ns_job_done(job);

-     }

- }

- 

- static void

- ns_job_timer_persist_test(void **state)

- {

-     struct ns_thrpool_t *tp = *state;

-     struct ns_job_t *job = NULL;

-     struct timeval tv = {1, 0};

- 

-     assert_true(ns_add_timeout_job(tp, &tv, NS_JOB_THREAD, ns_timer_persist_job_cb, NULL, &job) == NS_SUCCESS);

- 

-     PR_Sleep(PR_SecondsToInterval(5));

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_true(cb_check <= 6);

-     pthread_mutex_unlock(&cb_lock);

- 

-     PR_Sleep(PR_SecondsToInterval(6));

- 

-     pthread_mutex_lock(&cb_lock);

-     assert_int_equal(cb_check, 10);

-     pthread_mutex_unlock(&cb_lock);

- }

- 

- int

- main(void)

- {

-     const struct CMUnitTest tests[] = {

-         cmocka_unit_test_setup_teardown(ns_init_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_set_data_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_done_cb_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_persist_rearm_ignore_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_persist_disarm_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_race_done_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_signal_cb_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_neg_timeout_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_timer_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-         cmocka_unit_test_setup_teardown(ns_job_timer_persist_test,

-                                         ns_test_setup,

-                                         ns_test_teardown),

-     };

-     return cmocka_run_group_tests(tests, NULL, NULL);

- }

@@ -1,44 +0,0 @@ 

- /** BEGIN COPYRIGHT BLOCK

-  * Copyright (c) 2017, Red Hat, Inc

-  * All rights reserved.

-  *

-  * License: GPL (version 3 or any later version).

-  * See LICENSE for details.

-  * END COPYRIGHT BLOCK **/

- 

- #ifdef HAVE_CONFIG_H

- #include <config.h>

- #endif

- 

- /* For cmocka */

- #include <stdarg.h>

- #include <stddef.h>

- #include <setjmp.h>

- #include <cmocka.h>

- 

- #include <inttypes.h>

- 

- #include <nunc-stans.h>

- 

- #include <stdio.h>

- #include <signal.h>

- 

- #include <syslog.h>

- #include <string.h>

- #include <inttypes.h>

- 

- #include <time.h>

- #include <sys/time.h>

- 

- #include <assert.h>

- 

- struct test_params

- {

-     int32_t client_thread_count;

-     int32_t server_thread_count;

-     int32_t jobs;

-     int32_t test_timeout;

- };

- 

- int ns_stress_teardown(void **state);

- void ns_stress_test(void **state);

@@ -1,531 +0,0 @@ 

- /* --- BEGIN COPYRIGHT BLOCK ---

-  * Copyright (C) 2016  Red Hat

-  * see files 'COPYING' and 'COPYING.openssl' for use and warranty

-  * information

-  *

-  * 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 3 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, see <http://www.gnu.org/licenses/>.

-  *

-  * Additional permission under GPLv3 section 7:

-  *

-  * If you modify this Program, or any covered work, by linking or

-  * combining it with OpenSSL, or a modified version of OpenSSL licensed

-  * under the OpenSSL license

-  * (https://www.openssl.org/source/license.html), the licensors of this

-  * Program grant you additional permission to convey the resulting

-  * work. Corresponding Source for a non-source form of such a

-  * combination shall include the source code for the parts that are

-  * licensed under the OpenSSL license as well as that of the covered

-  * work.

-  * --- END COPYRIGHT BLOCK ---

-  */

- 

- /*

-  * A self hosting echo server, that stress tests job addition,

-  * removal, timers, and more.

-  */

- 

- /* Our local stress test header */

- #include "test_nuncstans_stress.h"

- 

- struct conn_ctx

- {

-     size_t offset;              /* current offset into buffer for reading or writing */

-     size_t len;                 /* size of buffer */

-     size_t needed;              /* content-length + start of body */

-     size_t body;                /* when reading, offset from buffer of beginning of http body */

-     size_t cl;                  /* http content-length when reading */

- #define CONN_BUFFER_SIZE BUFSIZ /* default buffer size */

-     char *buffer;

- };

- 

- static FILE *logfp;

- 

- void do_logging(int, const char *, ...);

- 

- int64_t client_success_count = 0;

- int64_t server_success_count = 0;

- int64_t client_fail_count = 0;

- int64_t client_timeout_count = 0;

- int64_t server_fail_count = 0;

- 

- int

- ns_stress_teardown(void **state)

- {

-     struct test_params *tparams = (struct test_params *)*state;

-     free(tparams);

-     return 0;

- }

- 

- #define PR_WOULD_BLOCK(iii) (iii == PR_PENDING_INTERRUPT_ERROR) || (iii == PR_WOULD_BLOCK_ERROR)

- 

- static void

- setup_logging(void)

- {

-     logfp = stdout;

- }

- 

- static void

- do_vlogging(int level, const char *format, va_list varg)

- {

- #ifdef DEBUG

-     if (level <= LOG_DEBUG) {

- #else

-     if (level <= LOG_ERR) {

- #endif

-         fprintf(logfp, "%d ", level);

-         vfprintf(logfp, format, varg);

-     }

- }

- 

- void

- do_logging(int level, const char *format, ...)

- {

-     va_list varg;

-     va_start(varg, format);

-     do_vlogging(level, format, varg);

-     va_end(varg);

- }

- 

- /* Server specifics */

- 

- static struct conn_ctx *

- conn_ctx_new(void)

- {

-     struct conn_ctx *connctx = calloc(1, sizeof(struct conn_ctx));

-     return connctx;

- }

- 

- static void

- conn_ctx_free(struct conn_ctx *connctx)

- {

-     /* Why don't we use PR_DELETE here? */

-     if (connctx->buffer != NULL) {

-         free(connctx->buffer);

-     }

-     free(connctx);

- }

- 

- static void

- server_conn_write(struct ns_job_t *job)

- {

-     struct conn_ctx *connctx;

-     int32_t len;

- 

-     do_logging(LOG_DEBUG, "job about to write ...\n");

-     assert(job != NULL);

-     connctx = (struct conn_ctx *)ns_job_get_data(job);

-     assert(connctx != NULL);

-     if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-         do_logging(LOG_ERR, "conn_write: job [%p] timeout\n", job);

-         __atomic_add_fetch_8(&server_fail_count, 1, __ATOMIC_ACQ_REL);

-         conn_ctx_free(connctx);

-         assert_int_equal(ns_job_done(job), 0);

-         return;

-     }

- 

-     /* Get the data out of our connctx */

-     char *data = calloc(1, sizeof(char) * (connctx->offset + 1));

-     memcpy(data, connctx->buffer, connctx->offset);

-     data[connctx->offset] = '\0';

- 

-     /* Should I write a new line also */

-     len = PR_Write(ns_job_get_fd(job), data, connctx->offset);

- 

-     /* Set the buffer window back to the start */

-     connctx->offset = 0;

- 

-     if (len < 0) {

-         /* Error */

-         printf("ERROR: occured in conn_write\n");

-     }

-     /* After we finish writing, do we stop being a thread? */

-     do_logging(LOG_DEBUG, "Wrote \"%s\"\n", data);

-     free(data);

-     /* The job is still a *read* IO event job, so this should be okay */

-     assert_int_equal(ns_job_rearm(job), 0);

-     return;

- }

- 

- static void

- server_conn_read(struct ns_job_t *job)

- {

-     do_logging(LOG_DEBUG, "Reading from connection\n");

- 

-     struct conn_ctx *connctx;

-     int32_t len;

-     int32_t nbytes;

- 

-     assert(job != NULL);

-     connctx = (struct conn_ctx *)ns_job_get_data(job);

-     assert(connctx != NULL);

- 

-     if (NS_JOB_IS_TIMER(ns_job_get_output_type(job))) {

-         /* The event that triggered this call back is because we timed out waiting for IO */

-         do_logging(LOG_ERR, "conn_read: job [%p] timed out\n", job);

-         __atomic_add_fetch_8(&server_fail_count, 1, __ATOMIC_ACQ_REL);

-         conn_ctx_free(connctx);

-         assert_int_equal(ns_job_done(job), 0);

-         return;

-     }

- 

-     if (connctx->needed != 0) {

-         nbytes = connctx->needed - connctx->offset;

-     } else {

-         nbytes = CONN_BUFFER_SIZE;

-     }

- 

-     /* If our buffer is incorrectly sized, realloc it to match what we are about to read */

-     if ((nbytes + connctx->offset) > connctx->len) {

-         connctx->len = nbytes + connctx->offset;

-         connctx->buffer = (char *)PR_Realloc(connctx->buffer, connctx->len * sizeof(char));

-     }

- 

-     /* Read and append to our buffer */

-     len = PR_Read(ns_job_get_fd(job), connctx->buffer + connctx->offset, nbytes);

-     if (len < 0) {

-         PRErrorCode prerr = PR_GetError();

-         if (PR_WOULD_BLOCK(prerr)) {

-             /* We don't have poll, so we rearm the job for more data */

-             if (NS_JOB_IS_PERSIST(ns_job_get_type(job)) != 0) {

-                 assert_int_equal(ns_job_rearm(job), 0);

-             }

-             do_logging(LOG_ERR, "conn_read: block error for job [%p] %d: %s\n", job, PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));

-             return;

-         } else {

-             do_logging(LOG_ERR, "conn_read: read error for job [%p] %d: %s\n", job, PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));

- #ifdef ATOMIC_64BIT_OPERATIONS

-             __atomic_add_fetch_8(&server_fail_count, 1, __ATOMIC_ACQ_REL);

- #else

-             PR_AtomicIncrement(&server_fail_count);

- #endif

-             conn_ctx_free(connctx);

-             assert_int_equal(ns_job_done(job), 0);

-             return;

-         }

-         /* Error */

-     } else if (len == 0) {

-         /* Didn't read anything */

-         do_logging(LOG_DEBUG, "conn_read: job [%p] closed\n", job);

-         /* Increment the success */

-         __atomic_add_fetch_8(&server_success_count, 1, __ATOMIC_ACQ_REL);

-         conn_ctx_free(connctx);

-         assert_int_equal(ns_job_done(job), 0);

-         return;

-     } else {

-         /* Wild data appears! */

-         connctx->offset += len;

-         char *data = PR_Malloc(sizeof(char) * (connctx->offset + 1));

-         memcpy(data, connctx->buffer, connctx->offset);

-         data[connctx->offset] = '\0';

-         do_logging(LOG_DEBUG, "[%p] data received \n", job);

-         do_logging(LOG_DEBUG, "data: \"%s\" \n", data);

-         free(data);

-         server_conn_write(job);

-         do_logging(LOG_DEBUG, "job rearmed for write ...\n");

-         return;

-     }

- }

- 

- static void

- server_conn_handler(struct ns_job_t *job)

- {

-     do_logging(LOG_DEBUG, "Handling a connection\n");

- 

-     assert(job != NULL);

- 

-     if (NS_JOB_IS_READ(ns_job_get_type(job)) != 0) {

-         server_conn_read(job);

-     } else {

-         /* We should not be able to get here! */

-         assert(0);

-     }

- 

-     return;

- }

- 

- static void

- server_listen_accept(struct ns_job_t *job)

- {

-     PRFileDesc *connfd = NULL;

-     struct conn_ctx *connctx;

-     PRSocketOptionData prsod = {PR_SockOpt_Nonblocking, {PR_TRUE}};

- 

-     PR_ASSERT(job);

- 

-     PRFileDesc *listenfd = ns_job_get_fd(job);

-     PR_ASSERT(listenfd);

-     connfd = PR_Accept(listenfd, NULL, PR_INTERVAL_NO_WAIT);

- 

-     if (connfd != NULL) {

-         PR_SetSocketOption(connfd, &prsod);

-         connctx = conn_ctx_new();

- 

-         assert_int_equal(ns_add_io_job(ns_job_get_tp(job), connfd, NS_JOB_READ | NS_JOB_THREAD, server_conn_handler, connctx, NULL), 0);

- 

-         do_logging(LOG_DEBUG, "server_listen_accept: accepting connection to job [%p]\n", job);

- 

-     } else {

-         PRErrorCode prerr = PR_GetError();

-         if (PR_WOULD_BLOCK(prerr)) {

-             /* Let it go .... let it gooooo! */

-             /* Can't hold up connection dispatch anymore! */

-         } else {

-             do_logging(LOG_ERR, "server_listen_accept: accept error for job [%p] %d %s\n", job, prerr, PR_ErrorToString(prerr, PR_LANGUAGE_I_DEFAULT));

-         }

-     }

- }

- 

- static struct ns_job_t *

- server_listener_init(ns_thrpool_t *tp, PRFileDesc *listenfd)

- {

-     struct ns_job_t *listen_job = NULL;

-     ns_add_io_job(tp, listenfd, NS_JOB_ACCEPT | NS_JOB_PERSIST, server_listen_accept, NULL, &listen_job);

-     return listen_job;

- }

- 

- /* Client specifics */

- 

- static void

- test_client_shutdown(struct ns_job_t *job)

- {

-     do_logging(LOG_DEBUG, "Received shutdown signal\n");

-     do_logging(LOG_DEBUG, "status .... fail_count: %d success_count: %d\n", client_fail_count, client_success_count);

-     ns_thrpool_shutdown(ns_job_get_tp(job));

-     /* This also needs to start the thrpool shutdown for the server. */

-     ns_thrpool_shutdown(ns_job_get_data(job));

- }

- 

- static void

- client_response_cb(struct ns_job_t *job)

- {

- 

-     char *buffer = calloc(1, 20);

-     int32_t buflen = 20;

-     int32_t len = 0;

- 

-     len = PR_Read(ns_job_get_fd(job), buffer, buflen);

-     if (len < 0) {

-         /* PRErrorCode prerr = PR_GetError(); */

-         do_logging(LOG_ERR, "FAIL: connection error, no data \n");

-         __atomic_add_fetch_8(&client_fail_count, 1, __ATOMIC_ACQ_REL);

-         goto done;

-     } else if (len == 0) {

-         do_logging(LOG_ERR, "FAIL: connection closed, no data \n");

-         __atomic_add_fetch_8(&client_fail_count, 1, __ATOMIC_ACQ_REL);

-         goto done;

-     } else {

-         /* Be paranoid, force last byte null */

-         buffer[buflen - 1] = '\0';

-         if (strncmp("this is a test!\n", buffer, strlen("this is a test!\n")) != 0) {

-             do_logging(LOG_ERR, "FAIL: connection incorrect response, no data \n");

-             __atomic_add_fetch_8(&client_fail_count, 1, __ATOMIC_ACQ_REL);

-             goto done;

-         }

-     }

- 

-     struct timespec ts;

-     clock_gettime(CLOCK_MONOTONIC, &ts);

-     __atomic_add_fetch_8(&client_success_count, 1, __ATOMIC_ACQ_REL);

-     do_logging(LOG_ERR, "PASS: %ld.%ld %d\n", ts.tv_sec, ts.tv_nsec, client_success_count);

- 

- done:

-     free(buffer);

-     assert_int_equal(ns_job_done(job), 0);

- }

- 

- static void

- client_initiate_connection_cb(struct ns_job_t *job)

- {

-     /* Create a socket */

-     PRFileDesc *sock = NULL;

-     PRNetAddr netaddr = {{0}};

-     char *data = "this is a test!\n";

- 

-     sock = PR_OpenTCPSocket(PR_AF_INET);

-     if (sock == NULL) {

-         char *err = NULL;

-         PR_GetErrorText(err);

-         do_logging(LOG_ERR, "FAIL: Socket failed, %d -> %s\n", PR_GetError(), err);

-         __atomic_add_fetch_8(&client_fail_count, 1, __ATOMIC_ACQ_REL);

-         goto done;

-     }

- 

-     PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 12345, &netaddr);

- 

-     /* Connect */

-     /*  */

-     if (PR_Connect(sock, &netaddr, PR_SecondsToInterval(5)) != 0) {

-         /* char *err = malloc(PR_GetErrorTextLength()); */

-         char *err = NULL;

-         PR_GetErrorText(err);

-         do_logging(LOG_ERR, "FAIL: cannot connect, timeout %d -> %s check nspr4/prerr.h \n", PR_GetError(), err);

-         /* Atomic increment fail */

-         __atomic_add_fetch_8(&client_timeout_count, 1, __ATOMIC_ACQ_REL);

-         if (sock != NULL) {

-             PR_Close(sock);

-         }

-         goto done;

-     }

-     /* Now write data. */

-     assert_true(PR_Write(sock, data, strlen(data) + 1) > 0);

-     /* create the read job to respond to events on the socket. */

-     assert_int_equal(ns_add_io_job(ns_job_get_tp(job), sock, NS_JOB_READ | NS_JOB_THREAD, client_response_cb, NULL, NULL), 0);

- 

- done:

-     assert_int_equal(ns_job_done(job), 0);

- }

- 

- static void

- client_create_work(struct ns_job_t *job)

- {

-     struct test_params *tparams = ns_job_get_data(job);

- 

-     struct timespec ts;

-     PR_Sleep(PR_SecondsToInterval(1));

-     clock_gettime(CLOCK_MONOTONIC, &ts);

-     printf("BEGIN: %ld.%ld\n", ts.tv_sec, ts.tv_nsec);

-     for (int32_t i = 0; i < tparams->jobs; i++) {

-         assert_int_equal(ns_add_job(ns_job_get_tp(job), NS_JOB_NONE | NS_JOB_THREAD, client_initiate_connection_cb, NULL, NULL), 0);

-     }

-     assert_int_equal(ns_job_done(job), 0);

- 

-     printf("Create work thread complete!\n");

- }

- 

- void

- ns_stress_test(void **state)

- {

- 

-     struct test_params *tparams = *state;

- 

-     /* Setup both thread pools. */

- 

-     /* Client first */

- 

-     int64_t job_count = tparams->jobs * tparams->client_thread_count;

-     struct ns_thrpool_t *ctp;

-     struct ns_thrpool_config client_ns_config;

-     struct ns_job_t *sigterm_job = NULL;

-     struct ns_job_t *sighup_job = NULL;

-     struct ns_job_t *sigint_job = NULL;

-     struct ns_job_t *sigtstp_job = NULL;

-     struct ns_job_t *sigusr1_job = NULL;

-     struct ns_job_t *sigusr2_job = NULL;

-     struct ns_job_t *final_job = NULL;

- 

-     struct timeval timeout = {tparams->test_timeout, 0};

- 

-     setup_logging();

- 

-     ns_thrpool_config_init(&client_ns_config);

-     client_ns_config.max_threads = tparams->client_thread_count;

-     client_ns_config.log_fct = do_vlogging;

-     ctp = ns_thrpool_new(&client_ns_config);

- 

-     /* Now the server */

- 

-     struct ns_thrpool_t *stp;

-     struct ns_thrpool_config server_ns_config;

-     struct ns_job_t *listen_job = NULL;

- 

-     ns_thrpool_config_init(&server_ns_config);

-     server_ns_config.max_threads = tparams->server_thread_count;

-     server_ns_config.log_fct = do_vlogging;

-     stp = ns_thrpool_new(&server_ns_config);

- 

-     /* Now, add the signal handlers. */

- 

-     assert_int_equal(ns_add_signal_job(ctp, SIGTERM, NS_JOB_PERSIST, test_client_shutdown, stp, &sigterm_job), 0);

-     assert_int_equal(ns_add_signal_job(ctp, SIGHUP, NS_JOB_PERSIST, test_client_shutdown, stp, &sighup_job), 0);

-     assert_int_equal(ns_add_signal_job(ctp, SIGINT, NS_JOB_PERSIST, test_client_shutdown, stp, &sigint_job), 0);

-     assert_int_equal(ns_add_signal_job(ctp, SIGTSTP, NS_JOB_PERSIST, test_client_shutdown, stp, &sigtstp_job), 0);

-     assert_int_equal(ns_add_signal_job(ctp, SIGUSR1, NS_JOB_PERSIST, test_client_shutdown, stp, &sigusr1_job), 0);

-     assert_int_equal(ns_add_signal_job(ctp, SIGUSR2, NS_JOB_PERSIST, test_client_shutdown, stp, &sigusr2_job), 0);

- 

-     /* Create the socket for the server, and set it to listen. */

- 

-     PRFileDesc *listenfd = NULL;

-     PRNetAddr netaddr;

-     PRSocketOptionData prsod = {PR_SockOpt_Nonblocking, {PR_TRUE}};

- 

-     PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, 12345, &netaddr);

- 

-     listenfd = PR_OpenTCPSocket(PR_NetAddrFamily(&netaddr));

-     PR_SetSocketOption(listenfd, &prsod);

-     prsod.option = PR_SockOpt_Reuseaddr;

-     PR_SetSocketOption(listenfd, &prsod);

-     assert_true(PR_Bind(listenfd, &netaddr) == PR_SUCCESS);

-     assert_true(PR_Listen(listenfd, 32) == PR_SUCCESS);

- 

-     listen_job = server_listener_init(stp, listenfd);

- 

-     /* Add the timeout. */

- 

-     assert_int_equal(ns_add_timeout_job(ctp, &timeout, NS_JOB_NONE | NS_JOB_THREAD, test_client_shutdown, stp, &final_job), 0);

- 

-     /* While true, add connect / write jobs */

-     for (PRInt32 i = 0; i < tparams->client_thread_count; i++) {

-         assert_int_equal(ns_add_job(ctp, NS_JOB_NONE | NS_JOB_THREAD, client_create_work, tparams, NULL), 0);

-     }

- 

-     /* Wait for all the clients to be done dispatching jobs to the server */

- 

-     if (ns_thrpool_wait(ctp) != 0) {

-         printf("Error in ctp?\n");

-     }

- 

-     if (ns_thrpool_wait(stp) != 0) {

-         printf("Error in stp?\n");

-     }

- 

-     /* Can mark as done becaus shutdown has begun. */

-     assert_int_equal(ns_job_done(listen_job), 0);

- 

- 

-     assert_int_equal(ns_job_done(sigterm_job), 0);

-     assert_int_equal(ns_job_done(sighup_job), 0);

-     assert_int_equal(ns_job_done(sigint_job), 0);

-     assert_int_equal(ns_job_done(sigtstp_job), 0);

-     assert_int_equal(ns_job_done(sigusr1_job), 0);

-     assert_int_equal(ns_job_done(sigusr2_job), 0);

-     assert_int_equal(ns_job_done(final_job), 0);

- 

-     ns_thrpool_destroy(stp);

-     ns_thrpool_destroy(ctp);

- 

-     /* Destroy the server thread pool. */

- 

-     if (client_success_count != job_count) {

-         do_logging(LOG_ERR, "FAIL, not all client jobs succeeded!\n");

-     }

-     if (server_success_count != job_count) {

-         do_logging(LOG_ERR, "FAIL, not all server jobs succeeded!\n");

-     }

-     do_logging(LOG_ERR, "job_count: %d client_fail_count: %d client_timeout_count: %d server_fail_count: %d client_success_count: %d server_success_count: %d\n", job_count, client_fail_count, client_timeout_count, server_fail_count, client_success_count, server_success_count);

- 

-     assert_int_equal(client_fail_count, 0);

-     /* We don't check the client timeout count, because it's often non 0, and it's generally because we *really* overwhelm the framework, we can handle the loss */

-     /* assert_int_equal(client_timeout_count, 0); */

-     assert_int_equal(server_fail_count, 0);

-     /* Can't assert this due to timeout: instead guarantee if we connect to the server, we WORKED 100% of the time. */

-     /*

-     assert_int_equal(server_success_count, job_count);

-     assert_int_equal(client_success_count, job_count);

-     */

-     assert_int_equal(server_success_count, client_success_count);

-     int32_t job_threshold = (tparams->jobs * tparams->client_thread_count) * 0.95;

-     assert_true(client_success_count >= job_threshold);

- 

-     PR_Cleanup();

- }

@@ -1,32 +0,0 @@ 

- /** BEGIN COPYRIGHT BLOCK

-  * Copyright (c) 2017, Red Hat, Inc

-  * All rights reserved.

-  *

-  * License: GPL (version 3 or any later version).

-  * See LICENSE for details.

-  * END COPYRIGHT BLOCK **/

- 

- #include "test_nuncstans_stress.h"

- 

- int

- ns_stress_large_setup(void **state)

- {

-     struct test_params *tparams = malloc(sizeof(struct test_params));

-     tparams->client_thread_count = 80;

-     tparams->server_thread_count = 20;

-     tparams->jobs = 200;

-     tparams->test_timeout = 70;

-     *state = tparams;

-     return 0;

- }

- 

- int

- main(void)

- {

-     const struct CMUnitTest tests[] = {

-         cmocka_unit_test_setup_teardown(ns_stress_test,

-                                         ns_stress_large_setup,

-                                         ns_stress_teardown),

-     };

-     return cmocka_run_group_tests(tests, NULL, NULL);

- }

@@ -1,32 +0,0 @@ 

- /** BEGIN COPYRIGHT BLOCK

-  * Copyright (c) 2017, Red Hat, Inc

-  * All rights reserved.

-  *

-  * License: GPL (version 3 or any later version).

-  * See LICENSE for details.

-  * END COPYRIGHT BLOCK **/

- 

- #include "test_nuncstans_stress.h"

- 

- int

- ns_stress_small_setup(void **state)

- {

-     struct test_params *tparams = malloc(sizeof(struct test_params));

-     tparams->client_thread_count = 4;

-     tparams->server_thread_count = 1;

-     tparams->jobs = 64;

-     tparams->test_timeout = 30;

-     *state = tparams;

-     return 0;

- }

- 

- int

- main(void)

- {

-     const struct CMUnitTest tests[] = {

-         cmocka_unit_test_setup_teardown(ns_stress_test,

-                                         ns_stress_small_setup,

-                                         ns_stress_teardown),

-     };

-     return cmocka_run_group_tests(tests, NULL, NULL);

- }

Bug Description: We have been attempting to modernise our
connection code for a long time - one attempt was nunc-stans.
However after a series of attempts to integrate it, and multiple
failures we discussed this in the listed email thread and decided
to remove this.

https://lists.fedoraproject.org/archives/list/389-devel@lists.fedoraproject.org/thread/3JRQQRIPOVDLLRD2QMF2PWNHJGZFUDCC/

Fix Description: rm -r src/nunc-stans

https://pagure.io/389-ds-base/issue/50669

Author: William Brown william@blackhats.net.au

Review by: ???

We still have the configuration setting in libglobs.c It could be present in someone's dse.ldif, so we need to handle it and ignore it, maybe log a message that it's been abandoned?

I didn't remove the config option, if present it's ignored because nothing in the server reads it.

Logging taht we ignore it is a good idea though.

Updated with log message:

[25/Oct/2019:09:56:22.773067400 +1000] - WARN - slapd_daemon - cn=config: nsslapd-enable-nunc-stans is on. nunc-stans has been deprecated and this flag is now ignored.
[25/Oct/2019:09:56:22.778913200 +1000] - WARN - slapd_daemon - cn=config: nsslapd-enable-nunc-stans should be set to off or deleted from cn=config.
[25/Oct/2019:09:56:22.789553700 +1000] - INFO - slapd_daemon - slapd started.  Listening on All Interfaces port 3389 for LDAP requests

rebased onto f006e991790bf93de7519f30c4935a4aada8b502

4 years ago

rebased onto 44e92dc

4 years ago

Pull-Request has been merged by firstyear

4 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3725

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago