From 69af412d42acccac660037e1f4026a6a6717634c Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Thu, 17 Dec 2020 15:25:42 -0500 Subject: [PATCH 2/2] Issue 4384 - Separate eventq into REALTIME and MONOTONIC Description: The recent changes to the eventq "when" time changed internally from REALTIME to MONOTONIC, and this broke the API. Create a new API for MONOTONIC clocks, and keep the original API intact for REALTIME clocks. Relates: https://github.com/389ds/389-ds-base/issues/4384 Reviewed by: firstyear(Thanks!) --- Makefile.am | 1 + docs/slapi.doxy.in | 1 - ldap/servers/plugins/chainingdb/cb_instance.c | 6 +- ldap/servers/plugins/dna/dna.c | 4 +- .../plugins/replication/repl5_backoff.c | 12 +- .../plugins/replication/repl5_connection.c | 10 +- .../plugins/replication/repl5_mtnode_ext.c | 4 +- .../plugins/replication/repl5_replica.c | 24 +- .../plugins/replication/repl5_schedule.c | 4 +- .../plugins/replication/windows_connection.c | 12 +- .../replication/windows_inc_protocol.c | 7 +- ldap/servers/plugins/retrocl/retrocl_trim.c | 10 +- ldap/servers/slapd/daemon.c | 3 +- ldap/servers/slapd/eventq-deprecated.c | 483 ++++++++++++++++++ ldap/servers/slapd/eventq.c | 236 ++++----- ldap/servers/slapd/main.c | 18 +- ldap/servers/slapd/proto-slap.h | 6 +- ldap/servers/slapd/slapi-plugin.h | 62 ++- ldap/servers/slapd/slapi2runtime.c | 23 +- ldap/servers/slapd/snmp_collator.c | 7 +- ldap/servers/slapd/task.c | 2 +- ldap/servers/slapd/uuid.c | 3 +- 22 files changed, 750 insertions(+), 188 deletions(-) create mode 100644 ldap/servers/slapd/eventq-deprecated.c diff --git a/Makefile.am b/Makefile.am index f7bf1c44c..ece1ad41a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1408,6 +1408,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/entrywsi.c \ ldap/servers/slapd/errormap.c \ ldap/servers/slapd/eventq.c \ + ldap/servers/slapd/eventq-deprecated.c \ ldap/servers/slapd/factory.c \ ldap/servers/slapd/features.c \ ldap/servers/slapd/fileio.c \ diff --git a/docs/slapi.doxy.in b/docs/slapi.doxy.in index b1e4810ab..1cafc50ce 100644 --- a/docs/slapi.doxy.in +++ b/docs/slapi.doxy.in @@ -759,7 +759,6 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = src/libsds/include/sds.h \ - docs/job-safety.md \ # ldap/servers/slapd/slapi-plugin.h \ # This tag can be used to specify the character encoding of the source files diff --git a/ldap/servers/plugins/chainingdb/cb_instance.c b/ldap/servers/plugins/chainingdb/cb_instance.c index bc1864c1a..7fd85deb0 100644 --- a/ldap/servers/plugins/chainingdb/cb_instance.c +++ b/ldap/servers/plugins/chainingdb/cb_instance.c @@ -217,7 +217,7 @@ cb_instance_free(cb_backend_instance *inst) slapi_rwlock_wrlock(inst->rwl_config_lock); if (inst->eq_ctx != NULL) { - slapi_eq_cancel(inst->eq_ctx); + slapi_eq_cancel_rel(inst->eq_ctx); inst->eq_ctx = NULL; } @@ -1947,8 +1947,8 @@ cb_instance_add_config_callback(Slapi_PBlock *pb __attribute__((unused)), * we can't call recursively into the DSE to do more adds, they'll * silently fail. instead, schedule the adds to happen in 1 second. */ - inst->eq_ctx = slapi_eq_once(cb_instance_add_monitor_later, (void *)inst, - slapi_current_rel_time_t() + 1); + inst->eq_ctx = slapi_eq_once_rel(cb_instance_add_monitor_later, (void *)inst, + slapi_current_rel_time_t() + 1); } /* Get the list of operational attrs defined in the schema */ diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c index 1cb54580b..b46edfcbb 100644 --- a/ldap/servers/plugins/dna/dna.c +++ b/ldap/servers/plugins/dna/dna.c @@ -688,7 +688,7 @@ dna_close(Slapi_PBlock *pb __attribute__((unused))) slapi_log_err(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, "--> dna_close\n"); - slapi_eq_cancel(eq_ctx); + slapi_eq_cancel_rel(eq_ctx); dna_delete_config(NULL); slapi_ch_free((void **)&dna_global_config); slapi_destroy_rwlock(g_dna_cache_lock); @@ -908,7 +908,7 @@ dna_load_plugin_config(Slapi_PBlock *pb, int use_eventq) * starting up would cause the change to not * get changelogged. */ now = slapi_current_rel_time_t(); - eq_ctx = slapi_eq_once(dna_update_config_event, NULL, now + 30); + eq_ctx = slapi_eq_once_rel(dna_update_config_event, NULL, now + 30); } else { dna_update_config_event(0, NULL); } diff --git a/ldap/servers/plugins/replication/repl5_backoff.c b/ldap/servers/plugins/replication/repl5_backoff.c index 40ec75dd7..8c851beb2 100644 --- a/ldap/servers/plugins/replication/repl5_backoff.c +++ b/ldap/servers/plugins/replication/repl5_backoff.c @@ -99,7 +99,7 @@ backoff_reset(Backoff_Timer *bt, slapi_eq_fn_t callback, void *callback_data) bt->callback_arg = callback_data; /* Cancel any pending events in the event queue */ if (NULL != bt->pending_event) { - slapi_eq_cancel(bt->pending_event); + slapi_eq_cancel_rel(bt->pending_event); bt->pending_event = NULL; } /* Compute the first fire time */ @@ -112,8 +112,8 @@ backoff_reset(Backoff_Timer *bt, slapi_eq_fn_t callback, void *callback_data) /* Schedule the callback */ bt->last_fire_time = slapi_current_rel_time_t(); return_value = bt->last_fire_time + bt->next_interval; - bt->pending_event = slapi_eq_once(bt->callback, bt->callback_arg, - return_value); + bt->pending_event = slapi_eq_once_rel(bt->callback, bt->callback_arg, + return_value); PR_Unlock(bt->lock); return return_value; } @@ -159,8 +159,8 @@ backoff_step(Backoff_Timer *bt) /* Schedule the callback, if any */ bt->last_fire_time += previous_interval; return_value = bt->last_fire_time + bt->next_interval; - bt->pending_event = slapi_eq_once(bt->callback, bt->callback_arg, - return_value); + bt->pending_event = slapi_eq_once_rel(bt->callback, bt->callback_arg, + return_value); } PR_Unlock(bt->lock); return return_value; @@ -196,7 +196,7 @@ backoff_delete(Backoff_Timer **btp) PR_Lock(bt->lock); /* Cancel any pending events in the event queue */ if (NULL != bt->pending_event) { - slapi_eq_cancel(bt->pending_event); + slapi_eq_cancel_rel(bt->pending_event); } PR_Unlock(bt->lock); PR_DestroyLock(bt->lock); diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c index bc9ca424b..2dd74f9e7 100644 --- a/ldap/servers/plugins/replication/repl5_connection.c +++ b/ldap/servers/plugins/replication/repl5_connection.c @@ -272,7 +272,7 @@ conn_delete(Repl_Connection *conn) PR_ASSERT(NULL != conn); PR_Lock(conn->lock); if (conn->linger_active) { - if (slapi_eq_cancel(conn->linger_event) == 1) { + if (slapi_eq_cancel_rel(conn->linger_event) == 1) { /* Event was found and cancelled. Destroy the connection object. */ destroy_it = PR_TRUE; } else { @@ -961,7 +961,7 @@ conn_cancel_linger(Repl_Connection *conn) "conn_cancel_linger - %s - Canceling linger on the connection\n", agmt_get_long_name(conn->agmt)); conn->linger_active = PR_FALSE; - if (slapi_eq_cancel(conn->linger_event) == 1) { + if (slapi_eq_cancel_rel(conn->linger_event) == 1) { conn->refcnt--; } conn->linger_event = NULL; @@ -1030,7 +1030,7 @@ conn_start_linger(Repl_Connection *conn) agmt_get_long_name(conn->agmt)); } else { conn->linger_active = PR_TRUE; - conn->linger_event = slapi_eq_once(linger_timeout, conn, now + conn->linger_time); + conn->linger_event = slapi_eq_once_rel(linger_timeout, conn, now + conn->linger_time); conn->status = STATUS_LINGERING; } PR_Unlock(conn->lock); @@ -1990,7 +1990,7 @@ repl5_start_debug_timeout(int *setlevel) Slapi_Eq_Context eqctx = 0; if (s_debug_timeout && s_debug_level) { time_t now = slapi_current_rel_time_t(); - eqctx = slapi_eq_once(repl5_debug_timeout_callback, setlevel, + eqctx = slapi_eq_once_rel(repl5_debug_timeout_callback, setlevel, s_debug_timeout + now); } return eqctx; @@ -2002,7 +2002,7 @@ repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel) char buf[20]; if (eqctx && !*setlevel) { - (void)slapi_eq_cancel(eqctx); + (void)slapi_eq_cancel_rel(eqctx); } if (s_debug_timeout && s_debug_level && *setlevel) { diff --git a/ldap/servers/plugins/replication/repl5_mtnode_ext.c b/ldap/servers/plugins/replication/repl5_mtnode_ext.c index 82e230958..2967a47f8 100644 --- a/ldap/servers/plugins/replication/repl5_mtnode_ext.c +++ b/ldap/servers/plugins/replication/repl5_mtnode_ext.c @@ -82,8 +82,8 @@ multimaster_mtnode_construct_replicas() } } /* Wait a few seconds for everything to startup before resuming any replication tasks */ - slapi_eq_once(replica_check_for_tasks, (void *)replica_get_root(r), - slapi_current_rel_time_t() + 5); + slapi_eq_once_rel(replica_check_for_tasks, (void *)replica_get_root(r), + slapi_current_rel_time_t() + 5); } } } diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c index c1d376c72..7102e0606 100644 --- a/ldap/servers/plugins/replication/repl5_replica.c +++ b/ldap/servers/plugins/replication/repl5_replica.c @@ -231,17 +231,17 @@ replica_new_from_entry(Slapi_Entry *e, char *errortext, PRBool is_add_operation, /* ONREPL - the state update can occur before the entry is added to the DIT. In that case the updated would fail but nothing bad would happen. The next scheduled update would save the state */ - r->repl_eqcxt_rs = slapi_eq_repeat(replica_update_state, r->repl_name, - slapi_current_rel_time_t() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL); + r->repl_eqcxt_rs = slapi_eq_repeat_rel(replica_update_state, r->repl_name, + slapi_current_rel_time_t() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL); if (r->tombstone_reap_interval > 0) { /* * Reap Tombstone should be started some time after the plugin started. * This will allow the server to fully start before consuming resources. */ - r->repl_eqcxt_tr = slapi_eq_repeat(eq_cb_reap_tombstones, r->repl_name, - slapi_current_rel_time_t() + r->tombstone_reap_interval, - 1000 * r->tombstone_reap_interval); + r->repl_eqcxt_tr = slapi_eq_repeat_rel(eq_cb_reap_tombstones, r->repl_name, + slapi_current_rel_time_t() + r->tombstone_reap_interval, + 1000 * r->tombstone_reap_interval); } done: @@ -303,12 +303,12 @@ replica_destroy(void **arg) */ if (r->repl_eqcxt_rs) { - slapi_eq_cancel(r->repl_eqcxt_rs); + slapi_eq_cancel_rel(r->repl_eqcxt_rs); r->repl_eqcxt_rs = NULL; } if (r->repl_eqcxt_tr) { - slapi_eq_cancel(r->repl_eqcxt_tr); + slapi_eq_cancel_rel(r->repl_eqcxt_tr); r->repl_eqcxt_tr = NULL; } @@ -1511,14 +1511,14 @@ replica_set_enabled(Replica *r, PRBool enable) if (enable) { if (r->repl_eqcxt_rs == NULL) /* event is not already registered */ { - r->repl_eqcxt_rs = slapi_eq_repeat(replica_update_state, r->repl_name, - slapi_current_rel_time_t() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL); + r->repl_eqcxt_rs = slapi_eq_repeat_rel(replica_update_state, r->repl_name, + slapi_current_rel_time_t() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL); } } else /* disable */ { if (r->repl_eqcxt_rs) /* event is still registerd */ { - slapi_eq_cancel(r->repl_eqcxt_rs); + slapi_eq_cancel_rel(r->repl_eqcxt_rs); r->repl_eqcxt_rs = NULL; } } @@ -3628,7 +3628,7 @@ replica_set_tombstone_reap_interval(Replica *r, long interval) if (interval > 0 && r->repl_eqcxt_tr && r->tombstone_reap_interval != interval) { int found; - found = slapi_eq_cancel(r->repl_eqcxt_tr); + found = slapi_eq_cancel_rel(r->repl_eqcxt_tr); slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "replica_set_tombstone_reap_interval - tombstone_reap event (interval=%" PRId64 ") was %s\n", r->tombstone_reap_interval, (found ? "cancelled" : "not found")); @@ -3636,7 +3636,7 @@ replica_set_tombstone_reap_interval(Replica *r, long interval) } r->tombstone_reap_interval = interval; if (interval > 0 && r->repl_eqcxt_tr == NULL) { - r->repl_eqcxt_tr = slapi_eq_repeat(eq_cb_reap_tombstones, r->repl_name, + r->repl_eqcxt_tr = slapi_eq_repeat_rel(eq_cb_reap_tombstones, r->repl_name, slapi_current_rel_time_t() + r->tombstone_reap_interval, 1000 * r->tombstone_reap_interval); slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, diff --git a/ldap/servers/plugins/replication/repl5_schedule.c b/ldap/servers/plugins/replication/repl5_schedule.c index 9539f4031..ca42df561 100644 --- a/ldap/servers/plugins/replication/repl5_schedule.c +++ b/ldap/servers/plugins/replication/repl5_schedule.c @@ -550,7 +550,7 @@ schedule_window_state_change_event(Schedule *sch) wakeup_time = PRTime2time_t(tm); /* schedule the event */ - sch->pending_event = slapi_eq_once(window_state_changed, sch, wakeup_time); + sch->pending_event = slapi_eq_once_rel(window_state_changed, sch, wakeup_time); timestr = get_timestring(&wakeup_time); slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "%s: Update window will %s at %s\n", @@ -593,7 +593,7 @@ static void unschedule_window_state_change_event(Schedule *sch) { if (sch->pending_event) { - slapi_eq_cancel(sch->pending_event); + slapi_eq_cancel_rel(sch->pending_event); sch->pending_event = NULL; } } diff --git a/ldap/servers/plugins/replication/windows_connection.c b/ldap/servers/plugins/replication/windows_connection.c index ce0662544..5eca5fad1 100644 --- a/ldap/servers/plugins/replication/windows_connection.c +++ b/ldap/servers/plugins/replication/windows_connection.c @@ -204,7 +204,7 @@ windows_conn_delete(Repl_Connection *conn) PR_ASSERT(NULL != conn); PR_Lock(conn->lock); if (conn->linger_active) { - if (slapi_eq_cancel(conn->linger_event) == 1) { + if (slapi_eq_cancel_rel(conn->linger_event) == 1) { /* Event was found and cancelled. Destroy the connection object. */ PR_Unlock(conn->lock); destroy_it = PR_TRUE; @@ -1052,7 +1052,7 @@ windows_conn_cancel_linger(Repl_Connection *conn) "windows_conn_cancel_linger - %s: Cancelling linger on the connection\n", agmt_get_long_name(conn->agmt)); conn->linger_active = PR_FALSE; - if (slapi_eq_cancel(conn->linger_event) == 1) { + if (slapi_eq_cancel_rel(conn->linger_event) == 1) { conn->refcnt--; } conn->linger_event = NULL; @@ -1129,7 +1129,7 @@ windows_conn_start_linger(Repl_Connection *conn) agmt_get_long_name(conn->agmt)); } else { conn->linger_active = PR_TRUE; - conn->linger_event = slapi_eq_once(linger_timeout, conn, now + conn->linger_time); + conn->linger_event = slapi_eq_once_rel(linger_timeout, conn, now + conn->linger_time); conn->status = STATUS_LINGERING; } PR_Unlock(conn->lock); @@ -1822,8 +1822,8 @@ repl5_start_debug_timeout(int *setlevel) if (s_debug_timeout && s_debug_level) { time_t now = time(NULL); - eqctx = slapi_eq_once(repl5_debug_timeout_callback, setlevel, - s_debug_timeout + now); + eqctx = slapi_eq_once_rel(repl5_debug_timeout_callback, setlevel, + s_debug_timeout + now); } slapi_log_err(SLAPI_LOG_TRACE, windows_repl_plugin_name, "<= repl5_start_debug_timeout\n"); return eqctx; @@ -1837,7 +1837,7 @@ repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel) slapi_log_err(SLAPI_LOG_TRACE, windows_repl_plugin_name, "=> repl5_stop_debug_timeout\n"); if (eqctx && !*setlevel) { - (void)slapi_eq_cancel(eqctx); + (void)slapi_eq_cancel_rel(eqctx); } if (s_debug_timeout && s_debug_level && *setlevel) { diff --git a/ldap/servers/plugins/replication/windows_inc_protocol.c b/ldap/servers/plugins/replication/windows_inc_protocol.c index 3d548e5ed..c07a8180a 100644 --- a/ldap/servers/plugins/replication/windows_inc_protocol.c +++ b/ldap/servers/plugins/replication/windows_inc_protocol.c @@ -132,7 +132,7 @@ windows_inc_delete(Private_Repl_Protocol **prpp) slapi_log_err(SLAPI_LOG_TRACE, windows_repl_plugin_name, "=> windows_inc_delete\n"); /* First, stop the protocol if it isn't already stopped */ /* Then, delete all resources used by the protocol */ - rc = slapi_eq_cancel(dirsync); + rc = slapi_eq_cancel_rel(dirsync); slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, "windows_inc_delete - dirsync: %p, rval: %d\n", dirsync, rc); /* if backoff is set, delete it (from EQ, as well) */ @@ -324,12 +324,13 @@ windows_inc_run(Private_Repl_Protocol *prp) if (interval != current_interval) { current_interval = interval; if (dirsync) { - int rc = slapi_eq_cancel(dirsync); + int rc = slapi_eq_cancel_rel(dirsync); slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, "windows_inc_run - Cancelled dirsync: %p, rval: %d\n", dirsync, rc); } - dirsync = slapi_eq_repeat(periodic_dirsync, (void *)prp, (time_t)0, interval); + dirsync = slapi_eq_repeat_rel(periodic_dirsync, (void *)prp, + slapi_current_rel_time_t(), interval); slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, "windows_inc_run - New dirsync: %p\n", dirsync); } diff --git a/ldap/servers/plugins/retrocl/retrocl_trim.c b/ldap/servers/plugins/retrocl/retrocl_trim.c index a3e16c4e1..12a395210 100644 --- a/ldap/servers/plugins/retrocl/retrocl_trim.c +++ b/ldap/servers/plugins/retrocl/retrocl_trim.c @@ -460,10 +460,10 @@ retrocl_init_trimming(void) ts.ts_s_initialized = 1; retrocl_trimming = 1; - retrocl_trim_ctx = slapi_eq_repeat(retrocl_housekeeping, - NULL, (time_t)0, - /* in milliseconds */ - trim_interval * 1000); + retrocl_trim_ctx = slapi_eq_repeat_rel(retrocl_housekeeping, + NULL, (time_t)0, + /* in milliseconds */ + trim_interval * 1000); } /* @@ -487,7 +487,7 @@ retrocl_stop_trimming(void) */ retrocl_trimming = 0; if (retrocl_trim_ctx) { - slapi_eq_cancel(retrocl_trim_ctx); + slapi_eq_cancel_rel(retrocl_trim_ctx); retrocl_trim_ctx = NULL; } PR_DestroyLock(ts.ts_s_trim_mutex); diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c index 0071ed86a..7681e88ea 100644 --- a/ldap/servers/slapd/daemon.c +++ b/ldap/servers/slapd/daemon.c @@ -1240,7 +1240,8 @@ slapd_daemon(daemon_ports_t *ports) slapi_log_err(SLAPI_LOG_TRACE, "slapd_daemon", "slapd shutting down - waiting for backends to close down\n"); - eq_stop(); + eq_stop(); /* deprecated */ + eq_stop_rel(); if (!in_referral_mode) { task_shutdown(); uniqueIDGenCleanup(); diff --git a/ldap/servers/slapd/eventq-deprecated.c b/ldap/servers/slapd/eventq-deprecated.c new file mode 100644 index 000000000..71a7bf8f5 --- /dev/null +++ b/ldap/servers/slapd/eventq-deprecated.c @@ -0,0 +1,483 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. + * Copyright (C) 2020 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 +#endif + + +/* ******************************************************** +eventq-deprecated.c - Event queue/scheduling system. + +There are 3 publicly-accessible entry points: + +slapi_eq_once(): cause an event to happen exactly once +slapi_eq_repeat(): cause an event to happen repeatedly +slapi_eq_cancel(): cancel a pending event + +There is also an initialization point which must be +called by the server to initialize the event queue system: +eq_start(), and an entry point used to shut down the system: +eq_stop(). + +These functions are now deprecated in favor of the functions +in eventq.c which use MONOTONIC clocks instead of REALTIME +clocks. +*********************************************************** */ + +#include "slap.h" +#include "prlock.h" +#include "prcvar.h" +#include "prinit.h" + +/* + * Private definition of slapi_eq_context. Only this + * module (eventq.c) should know about the layout of + * this structure. + */ +typedef struct _slapi_eq_context +{ + time_t ec_when; + time_t ec_interval; + slapi_eq_fn_t ec_fn; + void *ec_arg; + Slapi_Eq_Context ec_id; + struct _slapi_eq_context *ec_next; +} slapi_eq_context; + +/* + * Definition of the event queue. + */ +typedef struct _event_queue +{ + PRLock *eq_lock; + PRCondVar *eq_cv; + slapi_eq_context *eq_queue; +} event_queue; + +/* + * The event queue itself. + */ +static event_queue eqs = {0}; +static event_queue *eq = &eqs; + +/* + * Thread ID of the main thread loop + */ +static PRThread *eq_loop_tid = NULL; + +/* + * Flags used to control startup/shutdown of the event queue + */ +static int eq_running = 0; +static int eq_stopped = 0; +static int eq_initialized = 0; +PRLock *ss_lock = NULL; +PRCondVar *ss_cv = NULL; +PRCallOnceType init_once = {0}; + +/* Forward declarations */ +static slapi_eq_context *eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval); +static void eq_enqueue(slapi_eq_context *newec); +static slapi_eq_context *eq_dequeue(time_t now); +static PRStatus eq_create(void); + + +/* ******************************************************** */ + + +/* + * slapi_eq_once: cause an event to happen exactly once. + * + * Arguments: + * fn: the function to call + * arg: an argument to pass to the called function + * when: the time that the function should be called + * Returns: + * slapi_eq_context - a handle to an opaque object which + * the caller can use to refer to this particular scheduled + * event. + */ +Slapi_Eq_Context +slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when) +{ + slapi_eq_context *tmp; + PR_ASSERT(eq_initialized); + if (!eq_stopped) { + + Slapi_Eq_Context id; + + tmp = eq_new(fn, arg, when, 0UL); + id = tmp->ec_id; + + eq_enqueue(tmp); + + /* After this point, may have */ + /* been freed, depending on the thread */ + /* scheduling. Too bad */ + + slapi_log_err(SLAPI_LOG_HOUSE, NULL, + "added one-time event id %p at time %ld\n", + id, when); + return (id); + } + return NULL; /* JCM - Not sure if this should be 0 or something else. */ +} + + +/* + * slapi_eq_repeat: cause an event to happen repeatedly. + * + * Arguments: + * fn: the function to call + * arg: an argument to pass to the called function + * when: the time that the function should first be called + * interval: the amount of time (in milliseconds) between + * successive calls to the function + * Returns: + * slapi_eq_context - a handle to an opaque object which + * the caller can use to refer to this particular scheduled + */ +Slapi_Eq_Context +slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) +{ + slapi_eq_context *tmp; + PR_ASSERT(eq_initialized); + if (!eq_stopped) { + tmp = eq_new(fn, arg, when, interval); + eq_enqueue(tmp); + slapi_log_err(SLAPI_LOG_HOUSE, NULL, + "added repeating event id %p at time %ld, interval %lu\n", + tmp->ec_id, when, interval); + return (tmp->ec_id); + } + return NULL; /* JCM - Not sure if this should be 0 or something else. */ +} + + +/* + * slapi_eq_cancel: cancel a pending event. + * Arguments: + * ctx: the context of the event which should be de-scheduled + */ +int +slapi_eq_cancel(Slapi_Eq_Context ctx) +{ + slapi_eq_context **p, *tmp = NULL; + int found = 0; + + PR_ASSERT(eq_initialized); + if (!eq_stopped) { + PR_Lock(eq->eq_lock); + p = &(eq->eq_queue); + while (!found && *p != NULL) { + if ((*p)->ec_id == ctx) { + tmp = *p; + *p = (*p)->ec_next; + slapi_ch_free((void **)&tmp); + found = 1; + } else { + p = &((*p)->ec_next); + } + } + PR_Unlock(eq->eq_lock); + } + slapi_log_err(SLAPI_LOG_HOUSE, NULL, + "cancellation of event id %p requested: %s\n", + ctx, found ? "cancellation succeeded" : "event not found"); + return found; +} + + +/* + * Construct a new ec structure + */ +static slapi_eq_context * +eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) +{ + slapi_eq_context *retptr = (slapi_eq_context *)slapi_ch_calloc(1, sizeof(slapi_eq_context)); + + retptr->ec_fn = fn; + retptr->ec_arg = arg; + /* + * retptr->ec_when = when < now ? now : when; + * we used to amke this check, but it make no sense: when queued, if when + * has expired, we'll be executed anyway. save the cycles, and just set + * ec_when. + */ + retptr->ec_when = when; + retptr->ec_interval = interval == 0UL ? 0UL : (interval + 999) / 1000; + retptr->ec_id = (Slapi_Eq_Context)retptr; + return retptr; +} + + +/* + * Add a new event to the event queue. + */ +static void +eq_enqueue(slapi_eq_context *newec) +{ + slapi_eq_context **p; + + PR_ASSERT(NULL != newec); + PR_Lock(eq->eq_lock); + /* Insert in order (sorted by start time) in the list */ + for (p = &(eq->eq_queue); *p != NULL; p = &((*p)->ec_next)) { + if ((*p)->ec_when > newec->ec_when) { + break; + } + } + if (NULL != *p) { + newec->ec_next = *p; + } else { + newec->ec_next = NULL; + } + *p = newec; + PR_NotifyCondVar(eq->eq_cv); /* wake up scheduler thread */ + PR_Unlock(eq->eq_lock); +} + + +/* + * If there is an event in the queue scheduled at time + * or before, dequeue it and return a pointer + * to it. Otherwise, return NULL. + */ +static slapi_eq_context * +eq_dequeue(time_t now) +{ + slapi_eq_context *retptr = NULL; + + PR_Lock(eq->eq_lock); + if (NULL != eq->eq_queue && eq->eq_queue->ec_when <= now) { + retptr = eq->eq_queue; + eq->eq_queue = retptr->ec_next; + } + PR_Unlock(eq->eq_lock); + return retptr; +} + + +/* + * Call all events which are due to run. + * Note that if we've missed a schedule + * opportunity, we don't try to catch up + * by calling the function repeatedly. + */ +static void +eq_call_all(void) +{ + slapi_eq_context *p; + time_t curtime = slapi_current_utc_time(); + + while ((p = eq_dequeue(curtime)) != NULL) { + /* Call the scheduled function */ + p->ec_fn(p->ec_when, p->ec_arg); + slapi_log_err(SLAPI_LOG_HOUSE, NULL, + "Event id %p called at %ld (scheduled for %ld)\n", + p->ec_id, curtime, p->ec_when); + if (0UL != p->ec_interval) { + /* This is a repeating event. Requeue it. */ + do { + p->ec_when += p->ec_interval; + } while (p->ec_when < curtime); + eq_enqueue(p); + } else { + slapi_ch_free((void **)&p); + } + } +} + + +/* + * The main event queue loop. + */ +static void +eq_loop(void *arg __attribute__((unused))) +{ + while (eq_running) { + time_t curtime = slapi_current_utc_time(); + PRIntervalTime timeout; + int until; + PR_Lock(eq->eq_lock); + while (!((NULL != eq->eq_queue) && (eq->eq_queue->ec_when <= curtime))) { + if (!eq_running) { + PR_Unlock(eq->eq_lock); + goto bye; + } + /* Compute new timeout */ + if (NULL != eq->eq_queue) { + until = eq->eq_queue->ec_when - curtime; + timeout = PR_SecondsToInterval(until); + } else { + timeout = PR_INTERVAL_NO_TIMEOUT; + } + PR_WaitCondVar(eq->eq_cv, timeout); + curtime = slapi_current_utc_time(); + } + /* There is some work to do */ + PR_Unlock(eq->eq_lock); + eq_call_all(); + } +bye: + eq_stopped = 1; + PR_Lock(ss_lock); + PR_NotifyAllCondVar(ss_cv); + PR_Unlock(ss_lock); +} + + +/* + * Allocate and initialize the event queue structures. + */ +static PRStatus +eq_create(void) +{ + PR_ASSERT(NULL == eq->eq_lock); + if ((eq->eq_lock = PR_NewLock()) == NULL) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create", "PR_NewLock failed\n"); + exit(1); + } + if ((eq->eq_cv = PR_NewCondVar(eq->eq_lock)) == NULL) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create", "PR_NewCondVar failed\n"); + exit(1); + } + if ((ss_lock = PR_NewLock()) == NULL) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create", "PR_NewLock failed\n"); + exit(1); + } + if ((ss_cv = PR_NewCondVar(ss_lock)) == NULL) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create", "PR_NewCondVar failed\n"); + exit(1); + } + eq->eq_queue = NULL; + eq_initialized = 1; + return PR_SUCCESS; +} + + +/* + * eq_start: start the event queue system. + * + * This should be called exactly once. It will start a + * thread which wakes up periodically and schedules events. + */ +void +eq_start() +{ + PR_ASSERT(eq_initialized); + eq_running = 1; + if ((eq_loop_tid = PR_CreateThread(PR_USER_THREAD, (VFP)eq_loop, + NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, + SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL) { + slapi_log_err(SLAPI_LOG_ERR, "eq_start", "eq_loop PR_CreateThread failed\n"); + exit(1); + } + slapi_log_err(SLAPI_LOG_HOUSE, NULL, "event queue services have started\n"); +} + + +/* + * eq_init: initialize the event queue system. + * + * This function should be called early in server startup. + * Once it has been called, the event queue will queue + * events, but will not fire any events. Once all of the + * server plugins have been started, the eq_start() + * function should be called, and events will then start + * to fire. + */ +void +eq_init() +{ + if (!eq_initialized) { + if (PR_SUCCESS != PR_CallOnce(&init_once, eq_create)) { + slapi_log_err(SLAPI_LOG_ERR, "eq_init", "eq_create failed\n"); + } + } +} + + +/* + * eq_stop: shut down the event queue system. + * Does not return until event queue is fully + * shut down. + */ +void +eq_stop() +{ + slapi_eq_context *p, *q; + + if (NULL == eq || NULL == eq->eq_lock) { /* never started */ + eq_stopped = 1; + return; + } + + eq_stopped = 0; + eq_running = 0; + /* + * Signal the eq thread function to stop, and wait until + * it acknowledges by setting eq_stopped. + */ + while (!eq_stopped) { + PR_Lock(eq->eq_lock); + PR_NotifyAllCondVar(eq->eq_cv); + PR_Unlock(eq->eq_lock); + PR_Lock(ss_lock); + PR_WaitCondVar(ss_cv, PR_MillisecondsToInterval(100)); + PR_Unlock(ss_lock); + } + (void)PR_JoinThread(eq_loop_tid); + /* + * XXXggood we don't free the actual event queue data structures. + * This is intentional, to allow enqueueing/cancellation of events + * even after event queue services have shut down (these are no-ops). + * The downside is that the event queue can't be stopped and restarted + * easily. + */ + PR_Lock(eq->eq_lock); + p = eq->eq_queue; + while (p != NULL) { + q = p->ec_next; + slapi_ch_free((void **)&p); + /* Some ec_arg could get leaked here in shutdown (e.g., replica_name) + * This can be fixed by specifying a flag when the context is queued. + * [After 6.2] + */ + p = q; + } + PR_Unlock(eq->eq_lock); + slapi_log_err(SLAPI_LOG_HOUSE, NULL, "event queue services have shut down\n"); +} + +/* + * return arg (ec_arg) only if the context is in the event queue + */ +void * +slapi_eq_get_arg(Slapi_Eq_Context ctx) +{ + slapi_eq_context **p; + + PR_ASSERT(eq_initialized); + if (eq && !eq_stopped) { + PR_Lock(eq->eq_lock); + p = &(eq->eq_queue); + while (p && *p != NULL) { + if ((*p)->ec_id == ctx) { + PR_Unlock(eq->eq_lock); + return (*p)->ec_arg; + } else { + p = &((*p)->ec_next); + } + } + PR_Unlock(eq->eq_lock); + } + return NULL; +} diff --git a/ldap/servers/slapd/eventq.c b/ldap/servers/slapd/eventq.c index e1900724f..4c39e08cf 100644 --- a/ldap/servers/slapd/eventq.c +++ b/ldap/servers/slapd/eventq.c @@ -17,14 +17,14 @@ eventq.c - Event queue/scheduling system. There are 3 publicly-accessible entry points: -slapi_eq_once(): cause an event to happen exactly once -slapi_eq_repeat(): cause an event to happen repeatedly -slapi_eq_cancel(): cancel a pending event +slapi_eq_once_rel(): cause an event to happen exactly once +slapi_eq_repeat_rel(): cause an event to happen repeatedly +slapi_eq_cancel_rel(): cancel a pending event There is also an initialization point which must be called by the server to initialize the event queue system: -eq_start(), and an entry point used to shut down the system: -eq_stop(). +eq_start_rel(), and an entry point used to shut down the system: +eq_stop_rel(). *********************************************************** */ #include "slap.h" @@ -60,36 +60,36 @@ typedef struct _event_queue /* * The event queue itself. */ -static event_queue eqs = {0}; -static event_queue *eq = &eqs; +static event_queue eqs_rel = {0}; +static event_queue *eq_rel = &eqs_rel; /* * Thread ID of the main thread loop */ -static PRThread *eq_loop_tid = NULL; +static PRThread *eq_loop_rel_tid = NULL; /* * Flags used to control startup/shutdown of the event queue */ -static int eq_running = 0; -static int eq_stopped = 0; -static int eq_initialized = 0; -static pthread_mutex_t ss_lock; -static pthread_cond_t ss_cv; -PRCallOnceType init_once = {0}; +static int eq_rel_running = 0; +static int eq_rel_stopped = 0; +static int eq_rel_initialized = 0; +static pthread_mutex_t ss_rel_lock; +static pthread_cond_t ss_rel_cv; +PRCallOnceType init_once_rel = {0}; /* Forward declarations */ -static slapi_eq_context *eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval); -static void eq_enqueue(slapi_eq_context *newec); -static slapi_eq_context *eq_dequeue(time_t now); -static PRStatus eq_create(void); +static slapi_eq_context *eq_new_rel(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval); +static void eq_enqueue_rel(slapi_eq_context *newec); +static slapi_eq_context *eq_dequeue_rel(time_t now); +static PRStatus eq_create_rel(void); /* ******************************************************** */ /* - * slapi_eq_once: cause an event to happen exactly once. + * slapi_eq_once_rel: cause an event to happen exactly once. * * Arguments: * fn: the function to call @@ -101,18 +101,18 @@ static PRStatus eq_create(void); * event. */ Slapi_Eq_Context -slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when) +slapi_eq_once_rel(slapi_eq_fn_t fn, void *arg, time_t when) { slapi_eq_context *tmp; - PR_ASSERT(eq_initialized); - if (!eq_stopped) { + PR_ASSERT(eq_rel_initialized); + if (!eq_rel_stopped) { Slapi_Eq_Context id; - tmp = eq_new(fn, arg, when, 0UL); + tmp = eq_new_rel(fn, arg, when, 0UL); id = tmp->ec_id; - eq_enqueue(tmp); + eq_enqueue_rel(tmp); /* After this point, may have */ /* been freed, depending on the thread */ @@ -128,7 +128,7 @@ slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when) /* - * slapi_eq_repeat: cause an event to happen repeatedly. + * slapi_eq_repeat_rel: cause an event to happen repeatedly. * * Arguments: * fn: the function to call @@ -141,13 +141,13 @@ slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when) * the caller can use to refer to this particular scheduled */ Slapi_Eq_Context -slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) +slapi_eq_repeat_rel(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) { slapi_eq_context *tmp; - PR_ASSERT(eq_initialized); - if (!eq_stopped) { - tmp = eq_new(fn, arg, when, interval); - eq_enqueue(tmp); + PR_ASSERT(eq_rel_initialized); + if (!eq_rel_stopped) { + tmp = eq_new_rel(fn, arg, when, interval); + eq_enqueue_rel(tmp); slapi_log_err(SLAPI_LOG_HOUSE, NULL, "added repeating event id %p at time %ld, interval %lu\n", tmp->ec_id, when, interval); @@ -158,20 +158,20 @@ slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval /* - * slapi_eq_cancel: cancel a pending event. + * slapi_eq_cancel_rel: cancel a pending event. * Arguments: * ctx: the context of the event which should be de-scheduled */ int -slapi_eq_cancel(Slapi_Eq_Context ctx) +slapi_eq_cancel_rel(Slapi_Eq_Context ctx) { slapi_eq_context **p, *tmp = NULL; int found = 0; - PR_ASSERT(eq_initialized); - if (!eq_stopped) { - pthread_mutex_lock(&(eq->eq_lock)); - p = &(eq->eq_queue); + PR_ASSERT(eq_rel_initialized); + if (!eq_rel_stopped) { + pthread_mutex_lock(&(eq_rel->eq_lock)); + p = &(eq_rel->eq_queue); while (!found && *p != NULL) { if ((*p)->ec_id == ctx) { tmp = *p; @@ -182,7 +182,7 @@ slapi_eq_cancel(Slapi_Eq_Context ctx) p = &((*p)->ec_next); } } - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); } slapi_log_err(SLAPI_LOG_HOUSE, NULL, "cancellation of event id %p requested: %s\n", @@ -195,7 +195,7 @@ slapi_eq_cancel(Slapi_Eq_Context ctx) * Construct a new ec structure */ static slapi_eq_context * -eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) +eq_new_rel(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) { slapi_eq_context *retptr = (slapi_eq_context *)slapi_ch_calloc(1, sizeof(slapi_eq_context)); @@ -218,14 +218,14 @@ eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) * Add a new event to the event queue. */ static void -eq_enqueue(slapi_eq_context *newec) +eq_enqueue_rel(slapi_eq_context *newec) { slapi_eq_context **p; PR_ASSERT(NULL != newec); - pthread_mutex_lock(&(eq->eq_lock)); + pthread_mutex_lock(&(eq_rel->eq_lock)); /* Insert in order (sorted by start time) in the list */ - for (p = &(eq->eq_queue); *p != NULL; p = &((*p)->ec_next)) { + for (p = &(eq_rel->eq_queue); *p != NULL; p = &((*p)->ec_next)) { if ((*p)->ec_when > newec->ec_when) { break; } @@ -236,8 +236,8 @@ eq_enqueue(slapi_eq_context *newec) newec->ec_next = NULL; } *p = newec; - pthread_cond_signal(&(eq->eq_cv)); /* wake up scheduler thread */ - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_cond_signal(&(eq_rel->eq_cv)); /* wake up scheduler thread */ + pthread_mutex_unlock(&(eq_rel->eq_lock)); } @@ -247,16 +247,16 @@ eq_enqueue(slapi_eq_context *newec) * to it. Otherwise, return NULL. */ static slapi_eq_context * -eq_dequeue(time_t now) +eq_dequeue_rel(time_t now) { slapi_eq_context *retptr = NULL; - pthread_mutex_lock(&(eq->eq_lock)); - if (NULL != eq->eq_queue && eq->eq_queue->ec_when <= now) { - retptr = eq->eq_queue; - eq->eq_queue = retptr->ec_next; + pthread_mutex_lock(&(eq_rel->eq_lock)); + if (NULL != eq_rel->eq_queue && eq_rel->eq_queue->ec_when <= now) { + retptr = eq_rel->eq_queue; + eq_rel->eq_queue = retptr->ec_next; } - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); return retptr; } @@ -268,12 +268,12 @@ eq_dequeue(time_t now) * by calling the function repeatedly. */ static void -eq_call_all(void) +eq_call_all_rel(void) { slapi_eq_context *p; time_t curtime = slapi_current_rel_time_t(); - while ((p = eq_dequeue(curtime)) != NULL) { + while ((p = eq_dequeue_rel(curtime)) != NULL) { /* Call the scheduled function */ p->ec_fn(p->ec_when, p->ec_arg); slapi_log_err(SLAPI_LOG_HOUSE, NULL, @@ -284,7 +284,7 @@ eq_call_all(void) do { p->ec_when += p->ec_interval; } while (p->ec_when < curtime); - eq_enqueue(p); + eq_enqueue_rel(p); } else { slapi_ch_free((void **)&p); } @@ -296,38 +296,38 @@ eq_call_all(void) * The main event queue loop. */ static void -eq_loop(void *arg __attribute__((unused))) +eq_loop_rel(void *arg __attribute__((unused))) { - while (eq_running) { + while (eq_rel_running) { time_t curtime = slapi_current_rel_time_t(); int until; - pthread_mutex_lock(&(eq->eq_lock)); - while (!((NULL != eq->eq_queue) && (eq->eq_queue->ec_when <= curtime))) { - if (!eq_running) { - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_lock(&(eq_rel->eq_lock)); + while (!((NULL != eq_rel->eq_queue) && (eq_rel->eq_queue->ec_when <= curtime))) { + if (!eq_rel_running) { + pthread_mutex_unlock(&(eq_rel->eq_lock)); goto bye; } /* Compute new timeout */ - if (NULL != eq->eq_queue) { + if (NULL != eq_rel->eq_queue) { struct timespec current_time = slapi_current_rel_time_hr(); - until = eq->eq_queue->ec_when - curtime; + until = eq_rel->eq_queue->ec_when - curtime; current_time.tv_sec += until; - pthread_cond_timedwait(&eq->eq_cv, &eq->eq_lock, ¤t_time); + pthread_cond_timedwait(&eq_rel->eq_cv, &eq_rel->eq_lock, ¤t_time); } else { - pthread_cond_wait(&eq->eq_cv, &eq->eq_lock); + pthread_cond_wait(&eq_rel->eq_cv, &eq_rel->eq_lock); } curtime = slapi_current_rel_time_t(); } /* There is some work to do */ - pthread_mutex_unlock(&(eq->eq_lock)); - eq_call_all(); + pthread_mutex_unlock(&(eq_rel->eq_lock)); + eq_call_all_rel(); } bye: - eq_stopped = 1; - pthread_mutex_lock(&ss_lock); - pthread_cond_broadcast(&ss_cv); - pthread_mutex_unlock(&ss_lock); + eq_rel_stopped = 1; + pthread_mutex_lock(&ss_rel_lock); + pthread_cond_broadcast(&ss_rel_cv); + pthread_mutex_unlock(&ss_rel_lock); } @@ -335,73 +335,73 @@ bye: * Allocate and initialize the event queue structures. */ static PRStatus -eq_create(void) +eq_create_rel(void) { pthread_condattr_t condAttr; int rc = 0; /* Init the eventq mutex and cond var */ - if (pthread_mutex_init(&eq->eq_lock, NULL) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + if (pthread_mutex_init(&eq_rel->eq_lock, NULL) != 0) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Failed to create lock: error %d (%s)\n", rc, strerror(rc)); exit(1); } if ((rc = pthread_condattr_init(&condAttr)) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Failed to create new condition attribute variable. error %d (%s)\n", rc, strerror(rc)); exit(1); } if ((rc = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC)) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Cannot set condition attr clock. error %d (%s)\n", rc, strerror(rc)); exit(1); } - if ((rc = pthread_cond_init(&eq->eq_cv, &condAttr)) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + if ((rc = pthread_cond_init(&eq_rel->eq_cv, &condAttr)) != 0) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Failed to create new condition variable. error %d (%s)\n", rc, strerror(rc)); exit(1); } /* Init the "ss" mutex and condition var */ - if (pthread_mutex_init(&ss_lock, NULL) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + if (pthread_mutex_init(&ss_rel_lock, NULL) != 0) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Failed to create ss lock: error %d (%s)\n", rc, strerror(rc)); exit(1); } - if ((rc = pthread_cond_init(&ss_cv, &condAttr)) != 0) { - slapi_log_err(SLAPI_LOG_ERR, "eq_create", + if ((rc = pthread_cond_init(&ss_rel_cv, &condAttr)) != 0) { + slapi_log_err(SLAPI_LOG_ERR, "eq_create_rel", "Failed to create new ss condition variable. error %d (%s)\n", rc, strerror(rc)); exit(1); } pthread_condattr_destroy(&condAttr); /* no longer needed */ - eq->eq_queue = NULL; - eq_initialized = 1; + eq_rel->eq_queue = NULL; + eq_rel_initialized = 1; return PR_SUCCESS; } /* - * eq_start: start the event queue system. + * eq_start_rel: start the event queue system. * * This should be called exactly once. It will start a * thread which wakes up periodically and schedules events. */ void -eq_start() +eq_start_rel() { - PR_ASSERT(eq_initialized); - eq_running = 1; - if ((eq_loop_tid = PR_CreateThread(PR_USER_THREAD, (VFP)eq_loop, + PR_ASSERT(eq_rel_initialized); + eq_rel_running = 1; + if ((eq_loop_rel_tid = PR_CreateThread(PR_USER_THREAD, (VFP)eq_loop_rel, NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL) { - slapi_log_err(SLAPI_LOG_ERR, "eq_start", "eq_loop PR_CreateThread failed\n"); + slapi_log_err(SLAPI_LOG_ERR, "eq_start_rel", "eq_loop_rel PR_CreateThread failed\n"); exit(1); } slapi_log_err(SLAPI_LOG_HOUSE, NULL, "event queue services have started\n"); @@ -409,55 +409,55 @@ eq_start() /* - * eq_init: initialize the event queue system. + * eq_init_rel: initialize the event queue system. * * This function should be called early in server startup. * Once it has been called, the event queue will queue * events, but will not fire any events. Once all of the - * server plugins have been started, the eq_start() + * server plugins have been started, the eq_start_rel() * function should be called, and events will then start * to fire. */ void -eq_init() +eq_init_rel() { - if (!eq_initialized) { - if (PR_SUCCESS != PR_CallOnce(&init_once, eq_create)) { - slapi_log_err(SLAPI_LOG_ERR, "eq_init", "eq_create failed\n"); + if (!eq_rel_initialized) { + if (PR_SUCCESS != PR_CallOnce(&init_once_rel, eq_create_rel)) { + slapi_log_err(SLAPI_LOG_ERR, "eq_init_rel", "eq_create_rel failed\n"); } } } /* - * eq_stop: shut down the event queue system. + * eq_stop_rel: shut down the event queue system. * Does not return until event queue is fully * shut down. */ void -eq_stop() +eq_stop_rel() { slapi_eq_context *p, *q; - if (NULL == eq) { /* never started */ - eq_stopped = 1; + if (NULL == eq_rel) { /* never started */ + eq_rel_stopped = 1; return; } - eq_stopped = 0; - eq_running = 0; + eq_rel_stopped = 0; + eq_rel_running = 0; /* * Signal the eq thread function to stop, and wait until - * it acknowledges by setting eq_stopped. + * it acknowledges by setting eq_rel_stopped. */ - while (!eq_stopped) { + while (!eq_rel_stopped) { struct timespec current_time = {0}; - pthread_mutex_lock(&(eq->eq_lock)); - pthread_cond_broadcast(&(eq->eq_cv)); - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_lock(&(eq_rel->eq_lock)); + pthread_cond_broadcast(&(eq_rel->eq_cv)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); - pthread_mutex_lock(&ss_lock); + pthread_mutex_lock(&ss_rel_lock); clock_gettime(CLOCK_MONOTONIC, ¤t_time); if (current_time.tv_nsec + 100000000 > 1000000000) { /* nanoseconds will overflow, adjust the seconds and nanoseconds */ @@ -467,10 +467,10 @@ eq_stop() } else { current_time.tv_nsec += 100000000; /* 100 ms */ } - pthread_cond_timedwait(&ss_cv, &ss_lock, ¤t_time); - pthread_mutex_unlock(&ss_lock); + pthread_cond_timedwait(&ss_rel_cv, &ss_rel_lock, ¤t_time); + pthread_mutex_unlock(&ss_rel_lock); } - (void)PR_JoinThread(eq_loop_tid); + (void)PR_JoinThread(eq_loop_rel_tid); /* * XXXggood we don't free the actual event queue data structures. * This is intentional, to allow enqueueing/cancellation of events @@ -478,8 +478,8 @@ eq_stop() * The downside is that the event queue can't be stopped and restarted * easily. */ - pthread_mutex_lock(&(eq->eq_lock)); - p = eq->eq_queue; + pthread_mutex_lock(&(eq_rel->eq_lock)); + p = eq_rel->eq_queue; while (p != NULL) { q = p->ec_next; slapi_ch_free((void **)&p); @@ -489,7 +489,7 @@ eq_stop() */ p = q; } - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); slapi_log_err(SLAPI_LOG_HOUSE, NULL, "event queue services have shut down\n"); } @@ -497,23 +497,23 @@ eq_stop() * return arg (ec_arg) only if the context is in the event queue */ void * -slapi_eq_get_arg(Slapi_Eq_Context ctx) +slapi_eq_get_arg_rel(Slapi_Eq_Context ctx) { slapi_eq_context **p; - PR_ASSERT(eq_initialized); - if (eq && !eq_stopped) { - pthread_mutex_lock(&(eq->eq_lock)); - p = &(eq->eq_queue); + PR_ASSERT(eq_rel_initialized); + if (eq_rel && !eq_rel_stopped) { + pthread_mutex_lock(&(eq_rel->eq_lock)); + p = &(eq_rel->eq_queue); while (p && *p != NULL) { if ((*p)->ec_id == ctx) { - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); return (*p)->ec_arg; } else { p = &((*p)->ec_next); } } - pthread_mutex_unlock(&(eq->eq_lock)); + pthread_mutex_unlock(&(eq_rel->eq_lock)); } return NULL; } diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index 104f6826c..dbc8cec15 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -979,7 +979,8 @@ main(int argc, char **argv) fedse_create_startOK(DSE_FILENAME, DSE_STARTOKFILE, slapdFrontendConfig->configdir); - eq_init(); /* must be done before plugins started */ + eq_init(); /* DEPRECATED */ + eq_init_rel(); /* must be done before plugins started */ /* Start the SNMP collator if counters are enabled. */ if (config_get_slapi_counters()) { @@ -1035,7 +1036,8 @@ main(int argc, char **argv) goto cleanup; } - eq_start(); /* must be done after plugins started */ + eq_start(); /* must be done after plugins started - DEPRECATED */ + eq_start_rel(); /* must be done after plugins started */ #ifdef HPUX10 /* HPUX linker voodoo */ @@ -2205,10 +2207,13 @@ slapd_exemode_db2ldif(int argc, char **argv, struct main_config *mcfg) */ plugin_get_plugin_dependencies(repl_plg_name, &plugin_list); - eq_init(); /* must be done before plugins started */ + eq_init(); /* must be done before plugins started - DEPRECATED */ + eq_init_rel(); /* must be done before plugins started */ + ps_init_psearch_system(); /* must come before plugin_startall() */ plugin_startall(argc, argv, plugin_list); - eq_start(); /* must be done after plugins started */ + eq_start(); /* must be done after plugins started - DEPRECATED*/ + eq_start_rel(); /* must be done after plugins started */ charray_free(plugin_list); } @@ -2263,8 +2268,9 @@ slapd_exemode_db2ldif(int argc, char **argv, struct main_config *mcfg) charray_free(mcfg->cmd_line_instance_names); charray_free(mcfg->db2ldif_include); if (mcfg->db2ldif_dump_replica) { - eq_stop(); /* event queue should be shutdown before closing - all plugins (especailly, replication plugin) */ + eq_stop(); /* DEPRECATED*/ + eq_stop_rel(); /* event queue should be shutdown before closing + all plugins (especially, replication plugin) */ plugin_closeall(1 /* Close Backends */, 1 /* Close Globals */); } return (return_value); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 3acc24f03..87080dd82 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -1322,7 +1322,6 @@ void factory_destroy_extension(int type, void *object, void *parent, void **exte /* * auditlog.c */ - void write_audit_log_entry(Slapi_PBlock *pb); void auditlog_hide_unhashed_pw(void); void auditlog_expose_unhashed_pw(void); @@ -1334,10 +1333,15 @@ void auditfaillog_expose_unhashed_pw(void); /* * eventq.c */ +void eq_init_rel(void); +void eq_start_rel(void); +void eq_stop_rel(void); +/* Deprecated eventq that uses REALTIME clock instead of MONOTONIC */ void eq_init(void); void eq_start(void); void eq_stop(void); + /* * uniqueidgen.c */ diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 55ded5eb8..f76b86e3c 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -6084,7 +6084,7 @@ void slapi_lock_mutex(Slapi_Mutex *mutex); int slapi_unlock_mutex(Slapi_Mutex *mutex); Slapi_CondVar *slapi_new_condvar(Slapi_Mutex *mutex); void slapi_destroy_condvar(Slapi_CondVar *cvar); -int slapi_wait_condvar(Slapi_CondVar *cvar, struct timeval *timeout); +int slapi_wait_condvar(Slapi_CondVar *cvar, struct timeval *timeout) __attribute__((deprecated)); int slapi_notify_condvar(Slapi_CondVar *cvar, int notify_all); int slapi_wait_condvar_pt(Slapi_CondVar *cvar, Slapi_Mutex *mutex, struct timeval *timeout); @@ -8059,24 +8059,24 @@ typedef void (*slapi_eq_fn_t)(time_t when, void *arg); * * \param fn The function to call when the event is triggered. * \param arg An argument to pass to the called function. - * \param when The time that the function should be called. + * \param when The time that the function should be called(MONOTONIC clock). * * \return slapi_eq_context */ -Slapi_Eq_Context slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when); +Slapi_Eq_Context slapi_eq_once_rel(slapi_eq_fn_t fn, void *arg, time_t when); /** * Cause an event to happen repeatedly. * * \param fn The function to call when the vent is triggered. * \param arg An argument to pass to the called function. - * \param when The time that the function should be called. + * \param when The time that the function should be called(MONOTONIC clock). * \param interval The amount of time (in milliseconds) between * successive calls to the function. * * \return slapi_eq_context */ -Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval); +Slapi_Eq_Context slapi_eq_repeat_rel(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval); /** * Cause a scheduled event to be canceled. @@ -8086,7 +8086,7 @@ Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsig * \return 1 If event was found and canceled. * \return 0 If event was not found in the queue. */ -int slapi_eq_cancel(Slapi_Eq_Context ctx); +int slapi_eq_cancel_rel(Slapi_Eq_Context ctx); /** * Return the event's argument. @@ -8095,7 +8095,55 @@ int slapi_eq_cancel(Slapi_Eq_Context ctx); * * \return A pointer to the event argument. */ -void *slapi_eq_get_arg(Slapi_Eq_Context ctx); +void *slapi_eq_get_arg_rel(Slapi_Eq_Context ctx); + +/* + * These event queue functions are now DEPRECATED as they REALTIME clocks + * instead of the preferred MONOTONIC clocks. + */ + +/** + * Cause an event to happen exactly once. + * + * \param fn The function to call when the event is triggered. + * \param arg An argument to pass to the called function. + * \param when The time that the function should be called(REALTIME clock). + * + * \return slapi_eq_context + */ +Slapi_Eq_Context slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when) __attribute__((deprecated)); + +/** + * Cause an event to happen repeatedly. + * + * \param fn The function to call when the vent is triggered. + * \param arg An argument to pass to the called function. + * \param when The time that the function should be called(REALTIME clock). + * \param interval The amount of time (in milliseconds) between + * successive calls to the function. + * + * \return slapi_eq_context + */ +Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval) __attribute__((deprecated)); + +/** + * Cause a scheduled event to be canceled. + * + * \param ctx The event object to cancel + * + * \return 1 If event was found and canceled. + * \return 0 If event was not found in the queue. + */ +int slapi_eq_cancel(Slapi_Eq_Context ctx) __attribute__((deprecated)); + +/** + * Return the event's argument. + * + * \param ctx The event object + * + * \return A pointer to the event argument. + */ +void *slapi_eq_get_arg(Slapi_Eq_Context ctx) __attribute__((deprecated)); /** * Construct a full path and name of a plugin. diff --git a/ldap/servers/slapd/slapi2runtime.c b/ldap/servers/slapd/slapi2runtime.c index 85dc4c9a8..53927934a 100644 --- a/ldap/servers/slapd/slapi2runtime.c +++ b/ldap/servers/slapd/slapi2runtime.c @@ -133,7 +133,7 @@ slapi_destroy_condvar(Slapi_CondVar *cvar) /* - * Function: slapi_wait_condvar + * Function: slapi_wait_condvar (DEPRECATED) * Description: behaves just like PR_WaitCondVar() except timeout is * in seconds and microseconds instead of PRIntervalTime units. * If timeout is NULL, this call blocks indefinitely. @@ -145,9 +145,26 @@ slapi_destroy_condvar(Slapi_CondVar *cvar) int slapi_wait_condvar(Slapi_CondVar *cvar, struct timeval *timeout) { - /* deprecated in favor of slapi_wait_condvar_pt() which requires that the + /* Deprecated in favor of slapi_wait_condvar_pt() which requires that the * mutex be passed in */ - return (0); + PRIntervalTime prit; + + if (cvar == NULL) { + return (0); + } + + if (timeout == NULL) { + prit = PR_INTERVAL_NO_TIMEOUT; + } else { + prit = PR_SecondsToInterval(timeout->tv_sec) + PR_MicrosecondsToInterval(timeout->tv_usec); + } + + if (PR_WaitCondVar((PRCondVar *)cvar, prit) != PR_SUCCESS) { + return (0); + } + + return (1); + } int diff --git a/ldap/servers/slapd/snmp_collator.c b/ldap/servers/slapd/snmp_collator.c index 3dd3af657..d760515f4 100644 --- a/ldap/servers/slapd/snmp_collator.c +++ b/ldap/servers/slapd/snmp_collator.c @@ -385,8 +385,9 @@ snmp_collator_start() snmp_collator_init(); /* Arrange to be called back periodically to update the mmap'd stats file. */ - snmp_eq_ctx = slapi_eq_repeat(snmp_collator_update, NULL, (time_t)0, - SLAPD_SNMP_UPDATE_INTERVAL); + snmp_eq_ctx = slapi_eq_repeat_rel(snmp_collator_update, NULL, + slapi_current_rel_time_t(), + SLAPD_SNMP_UPDATE_INTERVAL); return 0; } @@ -411,7 +412,7 @@ snmp_collator_stop() } /* Abort any pending events */ - slapi_eq_cancel(snmp_eq_ctx); + slapi_eq_cancel_rel(snmp_eq_ctx); snmp_collator_stopped = 1; /* acquire the semaphore */ diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c index 26f281cba..bded287c6 100644 --- a/ldap/servers/slapd/task.c +++ b/ldap/servers/slapd/task.c @@ -387,7 +387,7 @@ slapi_task_status_changed(Slapi_Task *task) ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */ task->task_flags |= SLAPI_TASK_DESTROYING; /* queue an event to destroy the state info */ - slapi_eq_once(destroy_task, (void *)task, slapi_current_rel_time_t() + ttl); + slapi_eq_once_rel(destroy_task, (void *)task, slapi_current_rel_time_t() + ttl); } slapi_free_search_results_internal(pb); slapi_pblock_destroy(pb); diff --git a/ldap/servers/slapd/uuid.c b/ldap/servers/slapd/uuid.c index a8bd6ee6c..31384a544 100644 --- a/ldap/servers/slapd/uuid.c +++ b/ldap/servers/slapd/uuid.c @@ -186,7 +186,8 @@ uuid_init(const char *configDir, const Slapi_DN *configDN, PRBool mtGen) /* schedule update task for multithreaded generation */ if (_state.mtGen) - slapi_eq_repeat(uuid_update_state, NULL, (time_t)0, UPDATE_INTERVAL); + slapi_eq_repeat_rel(uuid_update_state, NULL, slapi_current_rel_time_t(), + UPDATE_INTERVAL); _state.initialized = PR_TRUE; return UUID_SUCCESS; -- 2.26.2