From 8ec174ad4e570842495b2f1f3836160af90f69af Mon Sep 17 00:00:00 2001 From: Brian Wellington Date: Tue, 29 Aug 2000 21:30:03 +0000 Subject: [PATCH] Allow the timer code to run without threads. --- lib/isc/timer.c | 93 ++++++++++++++++++++++++++++++++++++++++++++--- lib/isc/timer_p.h | 29 +++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 lib/isc/timer_p.h diff --git a/lib/isc/timer.c b/lib/isc/timer.c index 16d1f2a5d1..0b9b3552ad 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -15,19 +15,24 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer.c,v 1.55 2000/08/26 01:42:29 bwelling Exp $ */ +/* $Id: timer.c,v 1.56 2000/08/29 21:30:02 bwelling Exp $ */ #include #include #include #include +#include #include #include #include #include #include +#ifndef ISC_PLATFORM_USETHREADS +#include "timer_p.h" +#endif + #ifdef ISC_TIMER_TRACE #define XTRACE(s) printf("%s\n", (s)) #define XTRACEID(s, t) printf("%s %p\n", (s), (t)) @@ -80,11 +85,22 @@ struct isc_timermgr { LIST(isc_timer_t) timers; unsigned int nscheduled; isc_time_t due; +#ifdef ISC_PLATFORM_USETHREADS isc_condition_t wakeup; isc_thread_t thread; +#else + unsigned int refs; +#endif isc_heap_t * heap; }; +#ifndef ISC_PLATFORM_USETHREADS +/* + * If threads are not in use, there can be only one. + */ +static isc_timermgr_t *timermgr = NULL; +#endif + static inline isc_result_t schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { isc_result_t result; @@ -98,6 +114,10 @@ schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { REQUIRE(timer->type != isc_timertype_inactive); +#ifndef ISC_PLATFORM_USETHREADS + UNUSED(signal_ok); +#endif + /* * Compute the new due time. */ @@ -150,15 +170,21 @@ schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { XTRACETIMER("schedule", timer, due); /* - * If this timer is at the head of the queue, we wake up the run - * thread. We do this, because we likely have set a more recent - * due time than the one the run thread is sleeping on, and we don't - * want it to oversleep. + * If this timer is at the head of the queue, we need to ensure + * that we won't miss it if it has a more recent due time than + * the current "next" timer. We do this either by waking up the + * run thread, or explicitly setting the value in the manager. */ +#ifdef ISC_PLATFORM_USETHREADS if (timer->index == 1 && signal_ok) { XTRACE("signal (schedule)"); SIGNAL(&manager->wakeup); } +#else + if (timer->index == 1 && + isc_time_compare(&timer->due, &manager->due) < 0) + manager->due = timer->due; +#endif return (ISC_R_SUCCESS); } @@ -180,10 +206,12 @@ deschedule(isc_timer_t *timer) { timer->index = 0; INSIST(manager->nscheduled > 0); manager->nscheduled--; +#ifdef ISC_PLATFORM_USETHREADS if (need_wakeup) { XTRACE("signal (deschedule)"); SIGNAL(&manager->wakeup); } +#endif } } @@ -569,6 +597,7 @@ dispatch(isc_timermgr_t *manager, isc_time_t *now) { } } +#ifdef ISC_PLATFORM_USETHREADS static isc_threadresult_t #ifdef _WIN32 /* XXXDCL */ WINAPI @@ -602,6 +631,7 @@ run(void *uap) { return ((isc_threadresult_t)0); } +#endif static isc_boolean_t sooner(void *v1, void *v2) { @@ -638,6 +668,14 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { REQUIRE(managerp != NULL && *managerp == NULL); +#ifndef ISC_PLATFORM_USETHREADS + if (timermgr != NULL) { + timermgr->refs++; + *managerp = timermgr; + return (ISC_R_SUCCESS); + } +#endif + manager = isc_mem_get(mctx, sizeof *manager); if (manager == NULL) return (ISC_R_NOMEMORY); @@ -662,7 +700,10 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { "isc_mutex_init() failed"); return (ISC_R_UNEXPECTED); } + isc_mem_attach(mctx, &manager->mctx); +#ifdef ISC_PLATFORM_USETHREADS if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) { + isc_mem_detach(&manager->mctx); DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof *manager); @@ -670,7 +711,6 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { "isc_condition_init() failed"); return (ISC_R_UNEXPECTED); } - isc_mem_attach(mctx, &manager->mctx); if (isc_thread_create(run, manager, &manager->thread) != ISC_R_SUCCESS) { isc_mem_detach(&manager->mctx); @@ -682,6 +722,10 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { "isc_thread_create() failed"); return (ISC_R_UNEXPECTED); } +#else + manager->refs = 1; + timermgr = manager; +#endif *managerp = manager; @@ -703,25 +747,42 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) { LOCK(&manager->lock); +#ifndef ISC_PLATFORM_USETHREADS + if (manager->refs > 1) { + manager->refs--; + UNLOCK(&manager->lock); + *managerp = NULL; + return; + } + + isc__timermgr_dispatch(); +#endif + REQUIRE(EMPTY(manager->timers)); manager->done = ISC_TRUE; +#ifdef ISC_PLATFORM_USETHREADS XTRACE("signal (destroy)"); SIGNAL(&manager->wakeup); +#endif UNLOCK(&manager->lock); +#ifdef ISC_PLATFORM_USETHREADS /* * Wait for thread to exit. */ if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS) UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_join() failed"); +#endif /* * Clean up. */ +#ifdef ISC_PLATFORM_USETHREADS (void)isc_condition_destroy(&manager->wakeup); +#endif DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); manager->magic = 0; @@ -731,3 +792,23 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) { *managerp = NULL; } + +#ifndef ISC_PLATFORM_USETHREADS +isc_result_t +isc__timermgr_nextevent(isc_time_t *when) { + if (timermgr == NULL || timermgr->nscheduled == 0) + return (ISC_R_NOTFOUND); + *when = timermgr->due; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__timermgr_dispatch(void) { + isc_time_t now; + if (timermgr == NULL) + return (ISC_R_NOTFOUND); + isc_time_now(&now); + dispatch(timermgr, &now); + return (ISC_R_SUCCESS); +} +#endif diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h new file mode 100644 index 0000000000..69ea2ff875 --- /dev/null +++ b/lib/isc/timer_p.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2000 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: timer_p.h,v 1.1 2000/08/29 21:30:03 bwelling Exp $ */ + +#ifndef ISC_TIMER_P_H +#define ISC_TIMER_P_H + +isc_result_t +isc__timermgr_nextevent(isc_time_t *when); + +isc_result_t +isc__timermgr_dispatch(void); + +#endif /* ISC_TIMER_P_H */