From 5d9d72c050e57d27f1ee4786b4175665bd768727 Mon Sep 17 00:00:00 2001 From: William Brown Date: Tue, 9 May 2017 10:05:20 +1000 Subject: [PATCH 1/2] Ticket 49099 - ns workers prep Bug Description: We wish to move to nunc-stans to control our worker threads and async tasks. Fix Description: This first patch moves the NS worker pool creation to main.c, which makes it accesible to both offline and online jobs. As well, we no longer "support" a server without nunc-stans so remove the configure options. We still allow enable disable of the feature however, so this has been fully tested. https://pagure.io/389-ds-base/issue/49099 Author: wibrown Review by: ??? --- configure.ac | 17 --- ldap/servers/slapd/connection.c | 4 - ldap/servers/slapd/conntable.c | 2 - ldap/servers/slapd/daemon.c | 253 +++++++------------------------- ldap/servers/slapd/fe.h | 2 +- ldap/servers/slapd/globals.c | 8 +- ldap/servers/slapd/libglobs.c | 8 - ldap/servers/slapd/main.c | 276 +++++++++++++++++++++-------------- ldap/servers/slapd/proto-slap.h | 4 - ldap/servers/slapd/slap.h | 8 - src/nunc-stans/ns/ns_thrpool.c | 21 ++- src/nunc-stans/test/test_nuncstans.c | 74 ++++++++++ 12 files changed, 308 insertions(+), 369 deletions(-) diff --git a/configure.ac b/configure.ac index 5fbf6ac..bfccc2c 100644 --- a/configure.ac +++ b/configure.ac @@ -266,23 +266,6 @@ else fi AM_CONDITIONAL(enable_posix_winsync,test "$enable_posix_winsync" = "yes") -if test -z "$enable_nunc_stans" ; then - enable_nunc_stans=yes # if not set on cmdline, set default -fi -AC_MSG_CHECKING(for --enable-nunc-stans) -AC_ARG_ENABLE(nunc_stans, - AS_HELP_STRING([--enable-nunc-stans], - [enable support for nunc-stans event framework (default: no)])) -if test "$enable_nunc_stans" = yes ; then - m4_include(m4/event.m4) - AC_MSG_RESULT(yes) - AC_DEFINE([ENABLE_NUNC_STANS], [1], [enable support for nunc-stans event framework]) -else - AC_MSG_RESULT(no) -fi -AM_CONDITIONAL(enable_nunc_stans,test "$enable_nunc_stans" = "yes") - - # the default prefix - override with --prefix or --with-fhs AC_PREFIX_DEFAULT([/opt/$PACKAGE_NAME]) diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c index f6242c3..d3b0f7e 100644 --- a/ldap/servers/slapd/connection.c +++ b/ldap/servers/slapd/connection.c @@ -241,10 +241,8 @@ connection_cleanup(Connection *conn) /* free the connection socket buffer */ connection_free_private_buffer(conn); -#ifdef ENABLE_NUNC_STANS /* even if !config_get_enable_nunc_stans, it is ok to set to 0 here */ conn->c_ns_close_jobs = 0; -#endif } /* @@ -1509,9 +1507,7 @@ connection_threadmain() Connection *pb_conn = NULL; Operation *pb_op = NULL; -#ifdef ENABLE_NUNC_STANS enable_nunc_stans = config_get_enable_nunc_stans(); -#endif #if defined( hpux ) /* Arrange to ignore SIGPIPE signals. */ SIGNAL( SIGPIPE, SIG_IGN ); diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c index 9e334e2..1c6757d 100644 --- a/ldap/servers/slapd/conntable.c +++ b/ldap/servers/slapd/conntable.c @@ -156,10 +156,8 @@ connection_table_get_connection(Connection_Table *ct, int sd) * far then `c' is not being used by any operation threads, etc. */ connection_cleanup(c); -#ifdef ENABLE_NUNC_STANS /* NOTE - ok to do this here even if enable_nunc_stans is off */ c->c_ct = ct; /* pointer to connection table that owns this connection */ -#endif } else { diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c index 866eac0..e63c26a 100644 --- a/ldap/servers/slapd/daemon.c +++ b/ldap/servers/slapd/daemon.c @@ -87,17 +87,13 @@ static PRLock *diskmon_mutex = NULL; void disk_monitoring_stop(void); typedef struct listener_info { -#ifdef ENABLE_NUNC_STANS PRStackElem stackelem; /* must be first in struct for PRStack to work */ -#endif int idx; /* index of this listener in the ct->fd array */ PRFileDesc *listenfd; /* the listener fd */ int secure; int local; -#ifdef ENABLE_NUNC_STANS Connection_Table *ct; /* for listen job callback */ struct ns_job_t *ns_job; /* the ns accept job */ -#endif } listener_info; static size_t listeners = 0; /* number of listener sockets */ @@ -117,11 +113,6 @@ static PRFileDesc **createprlistensockets(unsigned short port, static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf, size_t addrbuflen); static void set_shutdown (int); -#ifdef ENABLE_NUNC_STANS -struct ns_job_t *ns_signal_job[6]; -static void ns_set_shutdown (struct ns_job_t *job); -static void ns_set_user (struct ns_job_t *job); -#endif static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read); #ifdef HPUX10 @@ -161,9 +152,7 @@ accept_and_configure(int s __attribute__((unused)), PRFileDesc *pr_acceptfd, PRN */ /* GGOODREPL static void handle_timeout( void ); */ static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn ); -#ifdef ENABLE_NUNC_STANS static void ns_handle_new_connection(struct ns_job_t *job); -#endif 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); @@ -916,58 +905,7 @@ convert_pbe_des_to_aes(void) charray_free(attrs); } -#ifdef ENABLE_NUNC_STANS -/* - * 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); -} -#endif /* ENABLE_NUNC_STANS */ - -void slapd_daemon( daemon_ports_t *ports ) +void slapd_daemon( daemon_ports_t *ports, ns_thrpool_t *tp ) { /* We are passed some ports---one for regular connections, one * for SSL connections, one for ldapi connections. @@ -986,16 +924,10 @@ void slapd_daemon( daemon_ports_t *ports ) PRThread *time_thread_p; int threads; int in_referral_mode = config_check_referral_mode(); -#ifdef ENABLE_NUNC_STANS - ns_thrpool_t *tp = NULL; - struct ns_thrpool_config tp_config; -#endif int connection_table_size = get_configured_connection_table_size(); the_connection_table= connection_table_new(connection_table_size); -#ifdef ENABLE_NUNC_STANS enable_nunc_stans = config_get_enable_nunc_stans(); -#endif #ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS /* @@ -1022,38 +954,6 @@ void slapd_daemon( daemon_ports_t *ports ) createsignalpipe(); /* Setup our signal interception. */ init_shutdown_detect(); -#ifdef ENABLE_NUNC_STANS - } else { - PRInt32 maxthreads = (PRInt32)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; -#ifdef LDAP_ERROR_LOGGING - tp_config.log_fct = nunc_stans_logging; -#else - tp_config.log_fct = NULL; -#endif - 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 = 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, SIGINT, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[0]); - ns_add_signal_job(tp, SIGTERM, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[1]); - ns_add_signal_job(tp, SIGTSTP, NS_JOB_PERSIST, ns_set_shutdown, NULL, &ns_signal_job[3]); - ns_add_signal_job(tp, SIGHUP, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[2]); - ns_add_signal_job(tp, SIGUSR1, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[4]); - ns_add_signal_job(tp, SIGUSR2, NS_JOB_PERSIST, ns_set_user, NULL, &ns_signal_job[5]); -#endif /* ENABLE_NUNC_STANS */ } if ( @@ -1180,7 +1080,6 @@ void slapd_daemon( daemon_ports_t *ports ) */ convert_pbe_des_to_aes(); -#ifdef ENABLE_NUNC_STANS 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) { @@ -1190,7 +1089,6 @@ void slapd_daemon( daemon_ports_t *ports ) } } -#endif /* ENABLE_NUNC_STANS */ /* Now we write the pid file, indicating that the server is finally and listening for connections */ write_pid_file(); @@ -1205,42 +1103,55 @@ void slapd_daemon( daemon_ports_t *ports ) ); #endif -#ifdef ENABLE_NUNC_STANS - if (enable_nunc_stans && 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)); - } -#endif - /* The meat of the operation is in a loop on a call to select */ - while(!enable_nunc_stans && !g_get_shutdown()) - { - int select_return = 0; - PRErrorCode prerr; + 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)); + } - 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 */ - /* GGOODREPL handle_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 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 (size_t i = 0; i < listeners; i++) { + PRStatus 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); + 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 */ + /* GGOODREPL handle_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 */ + } #ifdef WITH_SYSTEMD sd_notify(0, "STOPPING=1"); @@ -1374,27 +1285,6 @@ void slapd_daemon( daemon_ports_t *ports ) */ log_access_flush(); -#ifdef ENABLE_NUNC_STANS - - /* - * We need to shutdown the nunc-stans thread pool before we free the - * connection table. - */ - if (enable_nunc_stans) { - /* 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); - } -#endif /* * connection_table_free could use callbacks in the backend. * (e.g., be_search_results_release) @@ -1804,7 +1694,6 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll __attribute__((unused } } -#ifdef ENABLE_NUNC_STANS #define CONN_NEEDS_CLOSING(c) (c->c_flags & CONN_FLAG_CLOSING) || (c->c_sd == SLAPD_INVALID_SOCKET) /* Used internally by ns_handle_closure and ns_handle_pr_read_ready. * Returns 0 if the connection was successfully closed, or 1 otherwise. @@ -1859,7 +1748,6 @@ ns_handle_closure(struct ns_job_t *job) } return; } -#endif /** * Schedule more I/O for this connection, or make sure that it @@ -1868,7 +1756,6 @@ ns_handle_closure(struct ns_job_t *job) void ns_connection_post_io_or_closing(Connection *conn) { -#ifdef ENABLE_NUNC_STANS struct timeval tv; if (!enable_nunc_stans) { @@ -1941,10 +1828,8 @@ ns_connection_post_io_or_closing(Connection *conn) "conn %" PRIu64 " for fd=%d\n", conn->c_connid, conn->c_sd); } } -#endif } -#ifdef ENABLE_NUNC_STANS /* This function must be called without the thread flag, in the * event loop. This function may free the connection. This can * only be done in the event loop thread. @@ -2025,7 +1910,6 @@ ns_handle_pr_read_ready(struct ns_job_t *job) ns_job_done(job); return; } -#endif /* * wrapper functions required so we can implement ioblock_timeout and @@ -2634,7 +2518,6 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i return 0; } -#ifdef ENABLE_NUNC_STANS static void ns_handle_new_connection(struct ns_job_t *job) { @@ -2680,7 +2563,6 @@ ns_handle_new_connection(struct ns_job_t *job) ns_connection_post_io_or_closing(c); return; } -#endif static int init_shutdown_detect(void) { @@ -2856,43 +2738,6 @@ set_shutdown (int sig __attribute__((unused))) (void) SIGNAL( SIGHUP, set_shutdown ); } -#ifdef ENABLE_NUNC_STANS -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 */ - PRStatus shutdown_status = PR_SUCCESS; - - 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)); - - /* Stop all the long running jobs */ - /* 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 (size_t i = 0; i < listeners; i++) { - 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); - listener_idxs[i].ns_job = NULL; - } - } -} -#endif - #ifndef LINUX void slapd_do_nothing (int sig) diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h index 3d9ac08..9667997 100644 --- a/ldap/servers/slapd/fe.h +++ b/ldap/servers/slapd/fe.h @@ -116,7 +116,7 @@ int connection_table_iterate_active_connections(Connection_Table *ct, void* arg, */ int signal_listner(void); int daemon_pre_setuid_init(daemon_ports_t *ports); -void slapd_daemon( daemon_ports_t *ports ); +void slapd_daemon( daemon_ports_t *ports, ns_thrpool_t *tp ); void daemon_register_connection(void); int slapd_listenhost2addr( const char *listenhost, PRNetAddr ***addr ); int daemon_register_reslimits( void ); diff --git a/ldap/servers/slapd/globals.c b/ldap/servers/slapd/globals.c index 003ffed..936c92e 100644 --- a/ldap/servers/slapd/globals.c +++ b/ldap/servers/slapd/globals.c @@ -38,10 +38,10 @@ #include "slap.h" #include "fe.h" -int should_detach = 1; -time_t starttime; -PRThread *listener_tid; -Slapi_PBlock *repl_pb = NULL; +int should_detach = 0; +time_t starttime; +PRThread *listener_tid; +Slapi_PBlock *repl_pb = NULL; /* * global variables that need mutex protection diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index e488885..7b338b3 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -241,9 +241,7 @@ slapi_onoff_t init_ignore_time_skew; slapi_onoff_t init_dynamic_plugins; slapi_onoff_t init_cn_uses_dn_syntax_in_dns; slapi_onoff_t init_global_backend_local; -#ifdef ENABLE_NUNC_STANS slapi_onoff_t init_enable_nunc_stans; -#endif #if defined (LINUX) slapi_int_t init_malloc_mxfast; slapi_int_t init_malloc_trim_threshold; @@ -1099,12 +1097,10 @@ static struct config_get_and_set { NULL, 0, (void**)&global_slapdFrontendConfig.maxsimplepaged_per_conn, CONFIG_INT, (ConfigGetFunc)config_get_maxsimplepaged_per_conn, SLAPD_DEFAULT_MAXSIMPLEPAGED_PER_CONN_STR}, -#ifdef ENABLE_NUNC_STANS {CONFIG_ENABLE_NUNC_STANS, config_set_enable_nunc_stans, NULL, 0, (void**)&global_slapdFrontendConfig.enable_nunc_stans, CONFIG_ON_OFF, (ConfigGetFunc)config_get_enable_nunc_stans, &init_enable_nunc_stans}, -#endif #ifdef MEMPOOL_EXPERIMENTAL {CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch, NULL, 0, @@ -1667,9 +1663,7 @@ FrontendConfig_init(void) { cfg->maxbersize = SLAPD_DEFAULT_MAXBERSIZE; cfg->logging_backend = slapi_ch_strdup(SLAPD_INIT_LOGGING_BACKEND_INTERNAL); cfg->rootdn = slapi_ch_strdup(SLAPD_DEFAULT_DIRECTORY_MANAGER); -#ifdef ENABLE_NUNC_STANS init_enable_nunc_stans = cfg->enable_nunc_stans = LDAP_ON; -#endif #if defined(LINUX) init_malloc_mxfast = cfg->malloc_mxfast = DEFAULT_MALLOC_UNSET; init_malloc_trim_threshold = cfg->malloc_trim_threshold = DEFAULT_MALLOC_UNSET; @@ -7488,7 +7482,6 @@ config_get_listen_backlog_size() return retVal; } -#ifdef ENABLE_NUNC_STANS int config_get_enable_nunc_stans() { @@ -7513,7 +7506,6 @@ config_set_enable_nunc_stans( const char *attrname, char *value, errorbuf, apply); return retVal; } -#endif static char * config_initvalue_to_onoff(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize) diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index ba1f5e8..5a41f04 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -78,87 +78,160 @@ static int slapd_exemode_suffix2instance(void); static int slapd_debug_level_string2level( const char *s ); static void slapd_debug_level_log( int level ); static void slapd_debug_level_usage( void ); -static void cmd_set_shutdown(int); /* * global variables */ static int slapd_exemode = SLAPD_EXEMODE_UNKNOWN; -static int init_cmd_shutdown_detect(void) + +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; - /* First of all, we must reset the signal mask to get rid of any blockages - * the process may have inherited from its parent (such as the console), which - * might result in the process not delivering those blocked signals, and thus, - * misbehaving.... - */ - { - int rc; - sigset_t proc_mask; - - slapi_log_err(SLAPI_LOG_TRACE, "init_cmd_shutdown_detect", "Reseting signal mask...\n"); - (void)sigemptyset( &proc_mask ); - rc = pthread_sigmask( SIG_SETMASK, &proc_mask, NULL ); - slapi_log_err(SLAPI_LOG_TRACE, "init_cmd_shutdown_detect", "%s\n", - rc ? "Failed to reset signal mask":"...Done (signal mask reset)!!"); - } + if (severity == LOG_DEBUG){ + loglevel = SLAPI_LOG_NUNCSTANS; + } else if(severity == LOG_INFO){ + loglevel = SLAPI_LOG_CONNS; + } -#if defined ( HPUX10 ) - PR_CreateThread ( PR_USER_THREAD, - catch_signals, - NULL, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, - SLAPD_DEFAULT_THREAD_STACKSIZE); -#elif defined ( HPUX11 ) - /* In the optimized builds for HPUX, the signal handler doesn't seem - * to get set correctly unless the primordial thread gets a chance - * to run before we make the call to SIGNAL. (At this point the - * the primordial thread has spawned the daemon thread which called - * this function.) The call to DS_Sleep will give the primordial - * thread a chance to run. */ - DS_Sleep(0); -#endif + va_copy(varg_copy, varg); + slapi_log_error_ext(loglevel, "nunc-stans", (char *)format, varg, varg_copy); + va_end(varg_copy); +} - (void) SIGNAL( SIGPIPE, SIG_IGN ); - (void) SIGNAL( SIGCHLD, slapd_wait4child ); -#ifndef LINUX - /* linux uses USR1/USR2 for thread synchronization, so we aren't - * allowed to mess with those. - */ - (void) SIGNAL( SIGUSR1, slapd_do_nothing ); - (void) SIGNAL( SIGUSR2, cmd_set_shutdown ); -#endif - (void) SIGNAL( SIGTERM, cmd_set_shutdown ); - (void) SIGNAL( SIGHUP, cmd_set_shutdown ); - (void) SIGNAL( SIGINT, cmd_set_shutdown ); +static void +ns_printf_logger(int priority __attribute__((unused)), const char *fmt, va_list varg) +{ + // Should we do anything with priority? + vprintf(fmt, varg); +} - return 0; +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 -cmd_set_shutdown (int sig __attribute__((unused))) +nunc_stans_free(void *ptr) { - /* don't log anything from a signal handler: - * you could be holding a lock when the signal was trapped. more - * specifically, you could be holding the logfile lock (and deadlock - * yourself). - */ + slapi_ch_free((void **)&ptr); +} - c_set_shutdown(); -#ifndef LINUX - /* don't mess with USR1/USR2 on linux, used by libpthread */ - (void) SIGNAL( SIGUSR2, cmd_set_shutdown ); -#endif - (void) SIGNAL( SIGTERM, cmd_set_shutdown ); - (void) SIGNAL( SIGHUP, cmd_set_shutdown ); +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; } -#ifdef HPUX10 -extern void collation_init(); +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; */ +#ifdef DEBUG + tp_config.log_fct = ns_printf_logger; #endif + 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: @@ -579,12 +652,8 @@ main( int argc, char **argv) int return_value = 0; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); daemon_ports_t ports_info = {0}; -#ifndef __LP64__ -#if defined(__hpux) && !defined(__ia64) - /* for static constructors */ - _main(); -#endif -#endif + ns_thrpool_t *tp = NULL; + #ifdef MEMPOOL_EXPERIMENTAL /* to use LDAP C SDK lber functions seemlessly with slapi_ch_malloc funcs, * setting the slapi_ch_malloc funcs to lber option here. */ @@ -774,14 +843,6 @@ main( int argc, char **argv) raise_process_limits(); /* should be done ASAP once config file read */ -#ifdef PUMPKIN_HOUR - if ( time( NULL ) > (PUMPKIN_HOUR - 10) ) { - slapi_log_err(SLAPI_LOG_ERR, "main", - "ERROR: ** This beta software has expired **\n"); - exit( 1 ); - } -#endif - /* Set entry points in libslapd */ set_entry_points(); @@ -854,15 +915,22 @@ main( int argc, char **argv) exit(1); } - /* Do NSS and/or SSL init for those modes other than listening modes */ - if ((slapd_exemode != SLAPD_EXEMODE_REFERRAL) && - (slapd_exemode != SLAPD_EXEMODE_SLAPD)) { - if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, - s_port, &ports_info)) { - return_value = 1; - goto cleanup; - } - } + /* + * Detach ourselves from the terminal (unless running in debug mode). + * We must detach before we start any threads since detach forks() on + * UNIX. + * Have to detach after ssl_init - the user may be prompted for the PIN + * on the terminal, so it must be open. + */ + if (detach(slapd_exemode, importexport_encrypt, s_port, &ports_info)) { + return_value = 1; + goto cleanup; + } + + /* + * 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 @@ -954,18 +1022,6 @@ main( int argc, char **argv) ndn_cache_init(); global_backend_lock_init(); - /* - * Detach ourselves from the terminal (unless running in debug mode). - * We must detach before we start any threads since detach forks() on - * UNIX. - * Have to detach after ssl_init - the user may be prompted for the PIN - * on the terminal, so it must be open. - */ - if (detach(slapd_exemode, importexport_encrypt, - s_port, &ports_info)) { - return_value = 1; - goto cleanup; - } /* * Now write our PID to the startup PID file. @@ -1141,7 +1197,7 @@ main( int argc, char **argv) { time( &starttime ); - slapd_daemon(&ports_info); + slapd_daemon(&ports_info, tp); } slapi_log_err(SLAPI_LOG_INFO, "main", "slapd stopped.\n"); reslimit_cleanup(); @@ -1153,12 +1209,9 @@ cleanup: SSL_ClearSessionCache(); ndn_cache_destroy(); NSS_Shutdown(); + main_stop_ns(tp); PR_Cleanup(); -#if defined( hpux ) - exit( return_value ); -#else return return_value; -#endif } @@ -1410,7 +1463,6 @@ process_command_line(int argc, char **argv, char **extraname) long_opts = long_options_archive2db; break; case SLAPD_EXEMODE_DB2ARCHIVE: - init_cmd_shutdown_detect(); opts = opts_db2archive; long_opts = long_options_db2archive; break; @@ -1419,6 +1471,8 @@ process_command_line(int argc, char **argv, char **extraname) long_opts = long_options_db2index; break; case SLAPD_EXEMODE_REFERRAL: + /* Default to not detaching, but if REFERRAL, turn it on. */ + should_detach = 1; opts = opts_referral; long_opts = long_options_referral; break; @@ -1439,6 +1493,8 @@ process_command_line(int argc, char **argv, char **extraname) long_opts = long_options_dbverify; break; default: /* SLAPD_EXEMODE_SLAPD */ + /* Default to not detaching, but if SLAPD, turn it on. */ + should_detach = 1; opts = opts_slapd; long_opts = long_options_slapd; } @@ -2104,7 +2160,7 @@ slapd_exemode_ldif2db(void) slapi_pblock_set(pb, SLAPI_LDIF2DB_EXCLUDE, db2ldif_exclude); int32_t task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; slapi_pblock_set(pb, SLAPI_TASK_FLAGS, &task_flags); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); if ( plugin->plg_ldif2db != NULL ) { return_value = (*plugin->plg_ldif2db)( pb ); } else { @@ -2174,7 +2230,7 @@ slapd_exemode_db2ldif(int argc, char** argv) /* [622984] db2lidf -r changes database file ownership * should call setuid before "db2ldif_dump_replica" */ - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); for (instp = cmd_line_instance_names; instp && *instp; instp++) { int release_me = 0; @@ -2420,7 +2476,7 @@ static int slapd_exemode_db2index(void) slapi_pblock_set(pb, SLAPI_BACKEND_INSTANCE_NAME, cmd_line_instance_name); int32_t task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; slapi_pblock_set(pb, SLAPI_TASK_FLAGS, &task_flags); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); return_value = (*plugin->plg_db2index)( pb ); slapi_pblock_destroy(pb); @@ -2475,7 +2531,7 @@ slapd_exemode_db2archive(void) slapi_pblock_set(pb, SLAPI_SEQ_VAL, archive_name); int32_t task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; slapi_pblock_set(pb, SLAPI_TASK_FLAGS, &task_flags); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); return_value = (backend_plugin->plg_db2archive)( pb ); slapi_pblock_destroy(pb); return return_value; @@ -2529,7 +2585,7 @@ slapd_exemode_archive2db(void) int32_t task_flags = SLAPI_TASK_RUNNING_FROM_COMMANDLINE; slapi_pblock_set(pb, SLAPI_TASK_FLAGS, &task_flags); slapi_pblock_set(pb, SLAPI_BACKEND_INSTANCE_NAME, cmd_line_instance_name); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); return_value = (backend_plugin->plg_archive2db)( pb ); slapi_pblock_destroy(pb); return return_value; @@ -2590,7 +2646,7 @@ slapd_exemode_upgradedb(void) /* borrowing import code, so need to set up the import variables */ slapi_pblock_set(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &ldif2db_generate_uniqueid); slapi_pblock_set(pb, SLAPI_LDIF2DB_NAMESPACEID, &ldif2db_namespaceid); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); if ( backend_plugin->plg_upgradedb != NULL ) { return_value = (*backend_plugin->plg_upgradedb)( pb ); } else { @@ -2665,7 +2721,7 @@ slapd_exemode_upgradednformat(void) /* borrowing import code, so need to set up the import variables */ slapi_pblock_set(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &ldif2db_generate_uniqueid); slapi_pblock_set(pb, SLAPI_LDIF2DB_NAMESPACEID, &ldif2db_namespaceid); - main_setuid(slapdFrontendConfig->localuser); + // main_setuid(slapdFrontendConfig->localuser); if ( backend_plugin->plg_upgradednformat != NULL ) { rc = (*backend_plugin->plg_upgradednformat)( pb ); } else { diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 9696ead..0439915 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -575,10 +575,8 @@ int config_set_dynamic_plugins(const char *attrname, char *value, char *errorbuf int config_get_dynamic_plugins(void); int config_set_cn_uses_dn_syntax_in_dns(const char *attrname, char *value, char *errorbuf, int apply); int config_get_cn_uses_dn_syntax_in_dns(void); -#ifdef ENABLE_NUNC_STANS int config_get_enable_nunc_stans(void); int config_set_enable_nunc_stans(const char *attrname, char *value, char *errorbuf, int apply); -#endif int config_set_extract_pem(const char *attrname, char *value, char *errorbuf, int apply); PLHashNumber hashNocaseString(const void *key); @@ -1495,9 +1493,7 @@ void slapd_do_nothing(int); #endif void slapd_wait4child (int); -#ifdef ENABLE_NUNC_STANS void ns_handle_pr_read_ready(struct ns_job_t *job); -#endif void ns_connection_post_io_or_closing(Connection *conn); /* diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 2f84d27..2064d4a 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -118,9 +118,7 @@ typedef struct symbol_t { */ #include -#ifdef ENABLE_NUNC_STANS #include -#endif #ifdef WITH_SYSTEMD #ifdef HAVE_JOURNALD @@ -1619,11 +1617,9 @@ typedef struct conn { Conn_IO_Layer_cb c_push_io_layer_cb; /* callback to push an IO layer on the conn->c_prfd */ Conn_IO_Layer_cb c_pop_io_layer_cb; /* callback to pop an IO layer off of the conn->c_prfd */ void *c_io_layer_cb_data; /* callback data */ -#ifdef ENABLE_NUNC_STANS struct connection_table *c_ct; /* connection table that this connection belongs to */ ns_thrpool_t *c_tp; /* thread pool for this connection */ int c_ns_close_jobs; /* number of current close jobs */ -#endif } Connection; #define CONN_FLAG_SSL 1 /* Is this connection an SSL connection or not ? * Used to direct I/O code when SSL is handled differently @@ -2102,9 +2098,7 @@ typedef struct _slapdEntryPoints { #define CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE "nsslapd-plugin-binddn-tracking" #define CONFIG_MODDN_ACI_ATTRIBUTE "nsslapd-moddn-aci" #define CONFIG_GLOBAL_BACKEND_LOCK "nsslapd-global-backend-lock" -#ifdef ENABLE_NUNC_STANS #define CONFIG_ENABLE_NUNC_STANS "nsslapd-enable-nunc-stans" -#endif #define CONFIG_CONFIG_ATTRIBUTE "nsslapd-config" #define CONFIG_INSTDIR_ATTRIBUTE "nsslapd-instancedir" #define CONFIG_SCHEMADIR_ATTRIBUTE "nsslapd-schemadir" @@ -2445,9 +2439,7 @@ typedef struct _slapdFrontendConfig { 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 */ -#ifdef ENABLE_NUNC_STANS slapi_onoff_t enable_nunc_stans; -#endif #if defined(LINUX) int malloc_mxfast; /* mallopt M_MXFAST */ int malloc_trim_threshold; /* mallopt M_TRIM_THRESHOLD */ diff --git a/src/nunc-stans/ns/ns_thrpool.c b/src/nunc-stans/ns/ns_thrpool.c index 41f5342..435aeb9 100644 --- a/src/nunc-stans/ns/ns_thrpool.c +++ b/src/nunc-stans/ns/ns_thrpool.c @@ -841,10 +841,12 @@ ns_add_io_job(ns_thrpool_t *tp, PRFileDesc *fd, ns_job_type_t job_type, return PR_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 */ @@ -880,10 +882,12 @@ ns_add_timeout_job(ns_thrpool_t *tp, struct timeval *tv, ns_job_type_t job_type, return PR_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 */ @@ -934,12 +938,14 @@ ns_add_io_timeout_job(ns_thrpool_t *tp, PRFileDesc *fd, struct timeval *tv, if (!_job) { return PR_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 */ @@ -971,10 +977,12 @@ ns_add_signal_job(ns_thrpool_t *tp, PRInt32 signum, ns_job_type_t job_type, return PR_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 */ @@ -1024,7 +1032,9 @@ ns_add_shutdown_job(ns_thrpool_t *tp) { if (!_job) { return PR_FAILURE; } + pthread_mutex_lock(_job->monitor); _job->state = NS_JOB_NEEDS_ARM; + pthread_mutex_unlock(_job->monitor); internal_ns_job_rearm(_job); return PR_SUCCESS; } @@ -1533,7 +1543,10 @@ ns_thrpool_shutdown(struct ns_thrpool_t *tp) PRStatus result = ns_add_shutdown_job(tp); PR_ASSERT(result == PR_SUCCESS); } - + /* 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)); } PRStatus @@ -1547,12 +1560,6 @@ ns_thrpool_wait(ns_thrpool_t *tp) while (sds_queue_dequeue(tp->thread_stack, (void **)&thr) == SDS_SUCCESS) { - - /* 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)); - /* void *thread_retval = NULL; */ int32_t rc = pthread_join(thr->thr, NULL); #ifdef DEBUG diff --git a/src/nunc-stans/test/test_nuncstans.c b/src/nunc-stans/test/test_nuncstans.c index 2795302..74ce57d 100644 --- a/src/nunc-stans/test/test_nuncstans.c +++ b/src/nunc-stans/test/test_nuncstans.c @@ -402,6 +402,74 @@ ns_job_neg_timeout_test(void **state) } +/* + * Test that a timeout job fires a within a time window + */ + +static void +ns_timer_job_cb(struct ns_job_t *job) +{ + cb_check += 1; + ns_job_done(job); + PR_Lock(cb_lock); + PR_NotifyCondVar(cb_cond); + /* Disarm ourselves */ + PR_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 = { 2, 0 }; + + PR_Lock(cb_lock); + assert_true(ns_add_timeout_job(tp, &tv, NS_JOB_THREAD, ns_timer_job_cb, NULL, &job) == PR_SUCCESS); + + PR_WaitCondVar(cb_cond, PR_SecondsToInterval(1)); + assert_int_equal(cb_check, 0); + + PR_WaitCondVar(cb_cond, PR_SecondsToInterval(2)); + PR_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) +{ + cb_check += 1; + 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 }; + + PR_Lock(cb_lock); + assert_true(ns_add_timeout_job(tp, &tv, NS_JOB_THREAD, ns_timer_persist_job_cb, NULL, &job) == PR_SUCCESS); + + PR_Sleep(PR_SecondsToInterval(5)); + + assert_true(cb_check <= 6); + + PR_Sleep(PR_SecondsToInterval(6)); + + assert_int_equal(cb_check, 10); +} + int main(void) { @@ -430,6 +498,12 @@ main(void) 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.8.3.1