00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/app.h>
00025 #include <isc/condition.h>
00026 #include <isc/heap.h>
00027 #include <isc/log.h>
00028 #include <isc/magic.h>
00029 #include <isc/mem.h>
00030 #include <isc/msgs.h>
00031 #include <isc/once.h>
00032 #include <isc/platform.h>
00033 #include <isc/task.h>
00034 #include <isc/thread.h>
00035 #include <isc/time.h>
00036 #include <isc/timer.h>
00037 #include <isc/util.h>
00038
00039 #ifdef OPENSSL_LEAKS
00040 #include <openssl/err.h>
00041 #endif
00042
00043
00044 #ifdef ISC_PLATFORM_USETHREADS
00045 #define USE_TIMER_THREAD
00046 #else
00047 #define USE_SHARED_MANAGER
00048 #endif
00049
00050 #ifndef USE_TIMER_THREAD
00051 #include "timer_p.h"
00052 #endif
00053
00054 #ifdef ISC_TIMER_TRACE
00055 #define XTRACE(s) fprintf(stderr, "%s\n", (s))
00056 #define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
00057 #define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
00058 (d).seconds, (d).nanoseconds)
00059 #define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
00060 (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
00061 #define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
00062 (d).seconds, (d).nanoseconds)
00063 #else
00064 #define XTRACE(s)
00065 #define XTRACEID(s, t)
00066 #define XTRACETIME(s, d)
00067 #define XTRACETIME2(s, d, n)
00068 #define XTRACETIMER(s, t, d)
00069 #endif
00070
00071 #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
00072 #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
00073
00074 typedef struct isc__timer isc__timer_t;
00075 typedef struct isc__timermgr isc__timermgr_t;
00076
00077 struct isc__timer {
00078
00079 isc_timer_t common;
00080 isc__timermgr_t * manager;
00081 isc_mutex_t lock;
00082
00083 unsigned int references;
00084 isc_time_t idle;
00085
00086 isc_timertype_t type;
00087 isc_time_t expires;
00088 isc_interval_t interval;
00089 isc_task_t * task;
00090 isc_taskaction_t action;
00091 void * arg;
00092 unsigned int index;
00093 isc_time_t due;
00094 LINK(isc__timer_t) link;
00095 };
00096
00097 #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
00098 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
00099
00100 struct isc__timermgr {
00101
00102 isc_timermgr_t common;
00103 isc_mem_t * mctx;
00104 isc_mutex_t lock;
00105
00106 isc_boolean_t done;
00107 LIST(isc__timer_t) timers;
00108 unsigned int nscheduled;
00109 isc_time_t due;
00110 #ifdef USE_TIMER_THREAD
00111 isc_condition_t wakeup;
00112 isc_thread_t thread;
00113 #endif
00114 #ifdef USE_SHARED_MANAGER
00115 unsigned int refs;
00116 #endif
00117 isc_heap_t * heap;
00118 };
00119
00120
00121
00122
00123
00124
00125
00126 isc_result_t
00127 isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type,
00128 const isc_time_t *expires, const isc_interval_t *interval,
00129 isc_task_t *task, isc_taskaction_t action, void *arg,
00130 isc_timer_t **timerp);
00131 isc_result_t
00132 isc__timer_reset(isc_timer_t *timer, isc_timertype_t type,
00133 const isc_time_t *expires, const isc_interval_t *interval,
00134 isc_boolean_t purge);
00135 isc_timertype_t
00136 isc_timer_gettype(isc_timer_t *timer);
00137 isc_result_t
00138 isc__timer_touch(isc_timer_t *timer);
00139 void
00140 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp);
00141 void
00142 isc__timer_detach(isc_timer_t **timerp);
00143 isc_result_t
00144 isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
00145 void
00146 isc_timermgr_poke(isc_timermgr_t *manager0);
00147 void
00148 isc__timermgr_destroy(isc_timermgr_t **managerp);
00149
00150 static struct isc__timermethods {
00151 isc_timermethods_t methods;
00152
00153
00154
00155
00156 void *gettype;
00157 } timermethods = {
00158 {
00159 isc__timer_attach,
00160 isc__timer_detach,
00161 isc__timer_reset,
00162 isc__timer_touch
00163 },
00164 (void *)isc_timer_gettype
00165 };
00166
00167 static struct isc__timermgrmethods {
00168 isc_timermgrmethods_t methods;
00169 void *poke;
00170 } timermgrmethods = {
00171 {
00172 isc__timermgr_destroy,
00173 isc__timer_create
00174 },
00175 (void *)isc_timermgr_poke
00176 };
00177
00178 #ifdef USE_SHARED_MANAGER
00179
00180
00181
00182 static isc__timermgr_t *timermgr = NULL;
00183 #endif
00184
00185 static inline isc_result_t
00186 schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) {
00187 isc_result_t result;
00188 isc__timermgr_t *manager;
00189 isc_time_t due;
00190 int cmp;
00191 #ifdef USE_TIMER_THREAD
00192 isc_boolean_t timedwait;
00193 #endif
00194
00195
00196
00197
00198
00199 REQUIRE(timer->type != isc_timertype_inactive);
00200
00201 #ifndef USE_TIMER_THREAD
00202 UNUSED(signal_ok);
00203 #endif
00204
00205 manager = timer->manager;
00206
00207 #ifdef USE_TIMER_THREAD
00208
00209
00210
00211
00212 timedwait = ISC_TF(manager->nscheduled > 0 &&
00213 isc_time_seconds(&manager->due) != 0);
00214 #endif
00215
00216
00217
00218
00219 if (timer->type != isc_timertype_once) {
00220 result = isc_time_add(now, &timer->interval, &due);
00221 if (result != ISC_R_SUCCESS)
00222 return (result);
00223 if (timer->type == isc_timertype_limited &&
00224 isc_time_compare(&timer->expires, &due) < 0)
00225 due = timer->expires;
00226 } else {
00227 if (isc_time_isepoch(&timer->idle))
00228 due = timer->expires;
00229 else if (isc_time_isepoch(&timer->expires))
00230 due = timer->idle;
00231 else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
00232 due = timer->idle;
00233 else
00234 due = timer->expires;
00235 }
00236
00237
00238
00239
00240
00241 if (timer->index > 0) {
00242
00243
00244
00245 cmp = isc_time_compare(&due, &timer->due);
00246 timer->due = due;
00247 switch (cmp) {
00248 case -1:
00249 isc_heap_increased(manager->heap, timer->index);
00250 break;
00251 case 1:
00252 isc_heap_decreased(manager->heap, timer->index);
00253 break;
00254 case 0:
00255
00256 break;
00257 }
00258 } else {
00259 timer->due = due;
00260 result = isc_heap_insert(manager->heap, timer);
00261 if (result != ISC_R_SUCCESS) {
00262 INSIST(result == ISC_R_NOMEMORY);
00263 return (ISC_R_NOMEMORY);
00264 }
00265 manager->nscheduled++;
00266 }
00267
00268 XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
00269 ISC_MSG_SCHEDULE, "schedule"), timer, due);
00270
00271
00272
00273
00274
00275
00276
00277 #ifdef USE_TIMER_THREAD
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 if (signal_ok && timedwait) {
00288 isc_interval_t fifteen;
00289 isc_time_t then;
00290
00291 isc_interval_set(&fifteen, 15, 0);
00292 result = isc_time_add(&manager->due, &fifteen, &then);
00293
00294 if (result == ISC_R_SUCCESS &&
00295 isc_time_compare(&then, now) < 0) {
00296 SIGNAL(&manager->wakeup);
00297 signal_ok = ISC_FALSE;
00298 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00299 ISC_LOGMODULE_TIMER, ISC_LOG_WARNING,
00300 "*** POKED TIMER ***");
00301 }
00302 }
00303
00304 if (timer->index == 1 && signal_ok) {
00305 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
00306 ISC_MSG_SIGNALSCHED,
00307 "signal (schedule)"));
00308 SIGNAL(&manager->wakeup);
00309 }
00310 #else
00311 if (timer->index == 1 &&
00312 isc_time_compare(&timer->due, &manager->due) < 0)
00313 manager->due = timer->due;
00314 #endif
00315
00316 return (ISC_R_SUCCESS);
00317 }
00318
00319 static inline void
00320 deschedule(isc__timer_t *timer) {
00321 #ifdef USE_TIMER_THREAD
00322 isc_boolean_t need_wakeup = ISC_FALSE;
00323 #endif
00324 isc__timermgr_t *manager;
00325
00326
00327
00328
00329
00330 manager = timer->manager;
00331 if (timer->index > 0) {
00332 #ifdef USE_TIMER_THREAD
00333 if (timer->index == 1)
00334 need_wakeup = ISC_TRUE;
00335 #endif
00336 isc_heap_delete(manager->heap, timer->index);
00337 timer->index = 0;
00338 INSIST(manager->nscheduled > 0);
00339 manager->nscheduled--;
00340 #ifdef USE_TIMER_THREAD
00341 if (need_wakeup) {
00342 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
00343 ISC_MSG_SIGNALDESCHED,
00344 "signal (deschedule)"));
00345 SIGNAL(&manager->wakeup);
00346 }
00347 #endif
00348 }
00349 }
00350
00351 static void
00352 destroy(isc__timer_t *timer) {
00353 isc__timermgr_t *manager = timer->manager;
00354
00355
00356
00357
00358
00359 LOCK(&manager->lock);
00360
00361 (void)isc_task_purgerange(timer->task,
00362 timer,
00363 ISC_TIMEREVENT_FIRSTEVENT,
00364 ISC_TIMEREVENT_LASTEVENT,
00365 NULL);
00366 deschedule(timer);
00367 UNLINK(manager->timers, timer, link);
00368
00369 UNLOCK(&manager->lock);
00370
00371 isc_task_detach(&timer->task);
00372 DESTROYLOCK(&timer->lock);
00373 timer->common.impmagic = 0;
00374 timer->common.magic = 0;
00375 isc_mem_put(manager->mctx, timer, sizeof(*timer));
00376 }
00377
00378 isc_result_t
00379 isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type,
00380 const isc_time_t *expires, const isc_interval_t *interval,
00381 isc_task_t *task, isc_taskaction_t action, void *arg,
00382 isc_timer_t **timerp)
00383 {
00384 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
00385 isc__timer_t *timer;
00386 isc_result_t result;
00387 isc_time_t now;
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 REQUIRE(VALID_MANAGER(manager));
00398 REQUIRE(task != NULL);
00399 REQUIRE(action != NULL);
00400 if (expires == NULL)
00401 expires = isc_time_epoch;
00402 if (interval == NULL)
00403 interval = isc_interval_zero;
00404 REQUIRE(type == isc_timertype_inactive ||
00405 !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
00406 REQUIRE(timerp != NULL && *timerp == NULL);
00407 REQUIRE(type != isc_timertype_limited ||
00408 !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
00409
00410
00411
00412
00413 if (type != isc_timertype_inactive) {
00414 TIME_NOW(&now);
00415 } else {
00416
00417
00418
00419
00420
00421 isc_time_settoepoch(&now);
00422 }
00423
00424
00425 timer = isc_mem_get(manager->mctx, sizeof(*timer));
00426 if (timer == NULL)
00427 return (ISC_R_NOMEMORY);
00428
00429 timer->manager = manager;
00430 timer->references = 1;
00431
00432 if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
00433 result = isc_time_add(&now, interval, &timer->idle);
00434 if (result != ISC_R_SUCCESS) {
00435 isc_mem_put(manager->mctx, timer, sizeof(*timer));
00436 return (result);
00437 }
00438 } else
00439 isc_time_settoepoch(&timer->idle);
00440
00441 timer->type = type;
00442 timer->expires = *expires;
00443 timer->interval = *interval;
00444 timer->task = NULL;
00445 isc_task_attach(task, &timer->task);
00446 timer->action = action;
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 DE_CONST(arg, timer->arg);
00458 timer->index = 0;
00459 result = isc_mutex_init(&timer->lock);
00460 if (result != ISC_R_SUCCESS) {
00461 isc_task_detach(&timer->task);
00462 isc_mem_put(manager->mctx, timer, sizeof(*timer));
00463 return (result);
00464 }
00465 ISC_LINK_INIT(timer, link);
00466 timer->common.impmagic = TIMER_MAGIC;
00467 timer->common.magic = ISCAPI_TIMER_MAGIC;
00468 timer->common.methods = (isc_timermethods_t *)&timermethods;
00469
00470 LOCK(&manager->lock);
00471
00472
00473
00474
00475
00476
00477 if (type != isc_timertype_inactive)
00478 result = schedule(timer, &now, ISC_TRUE);
00479 else
00480 result = ISC_R_SUCCESS;
00481 if (result == ISC_R_SUCCESS)
00482 APPEND(manager->timers, timer, link);
00483
00484 UNLOCK(&manager->lock);
00485
00486 if (result != ISC_R_SUCCESS) {
00487 timer->common.impmagic = 0;
00488 timer->common.magic = 0;
00489 DESTROYLOCK(&timer->lock);
00490 isc_task_detach(&timer->task);
00491 isc_mem_put(manager->mctx, timer, sizeof(*timer));
00492 return (result);
00493 }
00494
00495 *timerp = (isc_timer_t *)timer;
00496
00497 return (ISC_R_SUCCESS);
00498 }
00499
00500 isc_result_t
00501 isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type,
00502 const isc_time_t *expires, const isc_interval_t *interval,
00503 isc_boolean_t purge)
00504 {
00505 isc__timer_t *timer = (isc__timer_t *)timer0;
00506 isc_time_t now;
00507 isc__timermgr_t *manager;
00508 isc_result_t result;
00509
00510
00511
00512
00513
00514
00515
00516 REQUIRE(VALID_TIMER(timer));
00517 manager = timer->manager;
00518 REQUIRE(VALID_MANAGER(manager));
00519
00520 if (expires == NULL)
00521 expires = isc_time_epoch;
00522 if (interval == NULL)
00523 interval = isc_interval_zero;
00524 REQUIRE(type == isc_timertype_inactive ||
00525 !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
00526 REQUIRE(type != isc_timertype_limited ||
00527 !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
00528
00529
00530
00531
00532 if (type != isc_timertype_inactive) {
00533 TIME_NOW(&now);
00534 } else {
00535
00536
00537
00538
00539
00540 isc_time_settoepoch(&now);
00541 }
00542
00543 LOCK(&manager->lock);
00544 LOCK(&timer->lock);
00545
00546 if (purge)
00547 (void)isc_task_purgerange(timer->task,
00548 timer,
00549 ISC_TIMEREVENT_FIRSTEVENT,
00550 ISC_TIMEREVENT_LASTEVENT,
00551 NULL);
00552 timer->type = type;
00553 timer->expires = *expires;
00554 timer->interval = *interval;
00555 if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
00556 result = isc_time_add(&now, interval, &timer->idle);
00557 } else {
00558 isc_time_settoepoch(&timer->idle);
00559 result = ISC_R_SUCCESS;
00560 }
00561
00562 if (result == ISC_R_SUCCESS) {
00563 if (type == isc_timertype_inactive) {
00564 deschedule(timer);
00565 result = ISC_R_SUCCESS;
00566 } else
00567 result = schedule(timer, &now, ISC_TRUE);
00568 }
00569
00570 UNLOCK(&timer->lock);
00571 UNLOCK(&manager->lock);
00572
00573 return (result);
00574 }
00575
00576 isc_timertype_t
00577 isc_timer_gettype(isc_timer_t *timer0) {
00578 isc__timer_t *timer = (isc__timer_t *)timer0;
00579 isc_timertype_t t;
00580
00581 REQUIRE(VALID_TIMER(timer));
00582
00583 LOCK(&timer->lock);
00584 t = timer->type;
00585 UNLOCK(&timer->lock);
00586
00587 return (t);
00588 }
00589
00590 isc_result_t
00591 isc__timer_touch(isc_timer_t *timer0) {
00592 isc__timer_t *timer = (isc__timer_t *)timer0;
00593 isc_result_t result;
00594 isc_time_t now;
00595
00596
00597
00598
00599
00600 REQUIRE(VALID_TIMER(timer));
00601
00602 LOCK(&timer->lock);
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 TIME_NOW(&now);
00614 result = isc_time_add(&now, &timer->interval, &timer->idle);
00615
00616 UNLOCK(&timer->lock);
00617
00618 return (result);
00619 }
00620
00621 void
00622 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) {
00623 isc__timer_t *timer = (isc__timer_t *)timer0;
00624
00625
00626
00627
00628
00629 REQUIRE(VALID_TIMER(timer));
00630 REQUIRE(timerp != NULL && *timerp == NULL);
00631
00632 LOCK(&timer->lock);
00633 timer->references++;
00634 UNLOCK(&timer->lock);
00635
00636 *timerp = (isc_timer_t *)timer;
00637 }
00638
00639 void
00640 isc__timer_detach(isc_timer_t **timerp) {
00641 isc__timer_t *timer;
00642 isc_boolean_t free_timer = ISC_FALSE;
00643
00644
00645
00646
00647
00648 REQUIRE(timerp != NULL);
00649 timer = (isc__timer_t *)*timerp;
00650 REQUIRE(VALID_TIMER(timer));
00651
00652 LOCK(&timer->lock);
00653 REQUIRE(timer->references > 0);
00654 timer->references--;
00655 if (timer->references == 0)
00656 free_timer = ISC_TRUE;
00657 UNLOCK(&timer->lock);
00658
00659 if (free_timer)
00660 destroy(timer);
00661
00662 *timerp = NULL;
00663 }
00664
00665 static void
00666 dispatch(isc__timermgr_t *manager, isc_time_t *now) {
00667 isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
00668 isc_timerevent_t *event;
00669 isc_eventtype_t type = 0;
00670 isc__timer_t *timer;
00671 isc_result_t result;
00672 isc_boolean_t idle;
00673
00674
00675
00676
00677
00678 while (manager->nscheduled > 0 && !done) {
00679 timer = isc_heap_element(manager->heap, 1);
00680 INSIST(timer != NULL && timer->type != isc_timertype_inactive);
00681 if (isc_time_compare(now, &timer->due) >= 0) {
00682 if (timer->type == isc_timertype_ticker) {
00683 type = ISC_TIMEREVENT_TICK;
00684 post_event = ISC_TRUE;
00685 need_schedule = ISC_TRUE;
00686 } else if (timer->type == isc_timertype_limited) {
00687 int cmp;
00688 cmp = isc_time_compare(now, &timer->expires);
00689 if (cmp >= 0) {
00690 type = ISC_TIMEREVENT_LIFE;
00691 post_event = ISC_TRUE;
00692 need_schedule = ISC_FALSE;
00693 } else {
00694 type = ISC_TIMEREVENT_TICK;
00695 post_event = ISC_TRUE;
00696 need_schedule = ISC_TRUE;
00697 }
00698 } else if (!isc_time_isepoch(&timer->expires) &&
00699 isc_time_compare(now,
00700 &timer->expires) >= 0) {
00701 type = ISC_TIMEREVENT_LIFE;
00702 post_event = ISC_TRUE;
00703 need_schedule = ISC_FALSE;
00704 } else {
00705 idle = ISC_FALSE;
00706
00707 LOCK(&timer->lock);
00708 if (!isc_time_isepoch(&timer->idle) &&
00709 isc_time_compare(now,
00710 &timer->idle) >= 0) {
00711 idle = ISC_TRUE;
00712 }
00713 UNLOCK(&timer->lock);
00714 if (idle) {
00715 type = ISC_TIMEREVENT_IDLE;
00716 post_event = ISC_TRUE;
00717 need_schedule = ISC_FALSE;
00718 } else {
00719
00720
00721
00722
00723 XTRACEID(isc_msgcat_get(isc_msgcat,
00724 ISC_MSGSET_TIMER,
00725 ISC_MSG_IDLERESCHED,
00726 "idle reschedule"),
00727 timer);
00728 post_event = ISC_FALSE;
00729 need_schedule = ISC_TRUE;
00730 }
00731 }
00732
00733 if (post_event) {
00734 XTRACEID(isc_msgcat_get(isc_msgcat,
00735 ISC_MSGSET_TIMER,
00736 ISC_MSG_POSTING,
00737 "posting"), timer);
00738
00739
00740
00741 event = (isc_timerevent_t *)isc_event_allocate(manager->mctx,
00742 timer,
00743 type,
00744 timer->action,
00745 timer->arg,
00746 sizeof(*event));
00747
00748 if (event != NULL) {
00749 event->due = timer->due;
00750 isc_task_send(timer->task,
00751 ISC_EVENT_PTR(&event));
00752 } else
00753 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
00754 isc_msgcat_get(isc_msgcat,
00755 ISC_MSGSET_TIMER,
00756 ISC_MSG_EVENTNOTALLOC,
00757 "couldn't "
00758 "allocate event"));
00759 }
00760
00761 timer->index = 0;
00762 isc_heap_delete(manager->heap, 1);
00763 manager->nscheduled--;
00764
00765 if (need_schedule) {
00766 result = schedule(timer, now, ISC_FALSE);
00767 if (result != ISC_R_SUCCESS)
00768 UNEXPECTED_ERROR(__FILE__, __LINE__,
00769 "%s: %u",
00770 isc_msgcat_get(isc_msgcat,
00771 ISC_MSGSET_TIMER,
00772 ISC_MSG_SCHEDFAIL,
00773 "couldn't schedule "
00774 "timer"),
00775 result);
00776 }
00777 } else {
00778 manager->due = timer->due;
00779 done = ISC_TRUE;
00780 }
00781 }
00782 }
00783
00784 #ifdef USE_TIMER_THREAD
00785 static isc_threadresult_t
00786 #ifdef _WIN32
00787 WINAPI
00788 #endif
00789 run(void *uap) {
00790 isc__timermgr_t *manager = uap;
00791 isc_time_t now;
00792 isc_result_t result;
00793
00794 LOCK(&manager->lock);
00795 while (!manager->done) {
00796 TIME_NOW(&now);
00797
00798 XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00799 ISC_MSG_RUNNING,
00800 "running"), now);
00801
00802 dispatch(manager, &now);
00803
00804 if (manager->nscheduled > 0) {
00805 XTRACETIME2(isc_msgcat_get(isc_msgcat,
00806 ISC_MSGSET_GENERAL,
00807 ISC_MSG_WAITUNTIL,
00808 "waituntil"),
00809 manager->due, now);
00810 result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due);
00811 INSIST(result == ISC_R_SUCCESS ||
00812 result == ISC_R_TIMEDOUT);
00813 } else {
00814 XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00815 ISC_MSG_WAIT, "wait"), now);
00816 WAIT(&manager->wakeup, &manager->lock);
00817 }
00818 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
00819 ISC_MSG_WAKEUP, "wakeup"));
00820 }
00821 UNLOCK(&manager->lock);
00822
00823 #ifdef OPENSSL_LEAKS
00824 ERR_remove_state(0);
00825 #endif
00826
00827 return ((isc_threadresult_t)0);
00828 }
00829 #endif
00830
00831 static isc_boolean_t
00832 sooner(void *v1, void *v2) {
00833 isc__timer_t *t1, *t2;
00834
00835 t1 = v1;
00836 t2 = v2;
00837 REQUIRE(VALID_TIMER(t1));
00838 REQUIRE(VALID_TIMER(t2));
00839
00840 if (isc_time_compare(&t1->due, &t2->due) < 0)
00841 return (ISC_TRUE);
00842 return (ISC_FALSE);
00843 }
00844
00845 static void
00846 set_index(void *what, unsigned int index) {
00847 isc__timer_t *timer;
00848
00849 timer = what;
00850 REQUIRE(VALID_TIMER(timer));
00851
00852 timer->index = index;
00853 }
00854
00855 isc_result_t
00856 isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
00857 isc__timermgr_t *manager;
00858 isc_result_t result;
00859
00860
00861
00862
00863
00864 REQUIRE(managerp != NULL && *managerp == NULL);
00865
00866 #ifdef USE_SHARED_MANAGER
00867 if (timermgr != NULL) {
00868 timermgr->refs++;
00869 *managerp = (isc_timermgr_t *)timermgr;
00870 return (ISC_R_SUCCESS);
00871 }
00872 #endif
00873
00874 manager = isc_mem_get(mctx, sizeof(*manager));
00875 if (manager == NULL)
00876 return (ISC_R_NOMEMORY);
00877
00878 manager->common.impmagic = TIMER_MANAGER_MAGIC;
00879 manager->common.magic = ISCAPI_TIMERMGR_MAGIC;
00880 manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods;
00881 manager->mctx = NULL;
00882 manager->done = ISC_FALSE;
00883 INIT_LIST(manager->timers);
00884 manager->nscheduled = 0;
00885 isc_time_settoepoch(&manager->due);
00886 manager->heap = NULL;
00887 result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
00888 if (result != ISC_R_SUCCESS) {
00889 INSIST(result == ISC_R_NOMEMORY);
00890 isc_mem_put(mctx, manager, sizeof(*manager));
00891 return (ISC_R_NOMEMORY);
00892 }
00893 result = isc_mutex_init(&manager->lock);
00894 if (result != ISC_R_SUCCESS) {
00895 isc_heap_destroy(&manager->heap);
00896 isc_mem_put(mctx, manager, sizeof(*manager));
00897 return (result);
00898 }
00899 isc_mem_attach(mctx, &manager->mctx);
00900 #ifdef USE_TIMER_THREAD
00901 if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
00902 isc_mem_detach(&manager->mctx);
00903 DESTROYLOCK(&manager->lock);
00904 isc_heap_destroy(&manager->heap);
00905 isc_mem_put(mctx, manager, sizeof(*manager));
00906 UNEXPECTED_ERROR(__FILE__, __LINE__,
00907 "isc_condition_init() %s",
00908 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00909 ISC_MSG_FAILED, "failed"));
00910 return (ISC_R_UNEXPECTED);
00911 }
00912 if (isc_thread_create(run, manager, &manager->thread) !=
00913 ISC_R_SUCCESS) {
00914 isc_mem_detach(&manager->mctx);
00915 (void)isc_condition_destroy(&manager->wakeup);
00916 DESTROYLOCK(&manager->lock);
00917 isc_heap_destroy(&manager->heap);
00918 isc_mem_put(mctx, manager, sizeof(*manager));
00919 UNEXPECTED_ERROR(__FILE__, __LINE__,
00920 "isc_thread_create() %s",
00921 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00922 ISC_MSG_FAILED, "failed"));
00923 return (ISC_R_UNEXPECTED);
00924 }
00925 #endif
00926 #ifdef USE_SHARED_MANAGER
00927 manager->refs = 1;
00928 timermgr = manager;
00929 #endif
00930
00931 *managerp = (isc_timermgr_t *)manager;
00932
00933 return (ISC_R_SUCCESS);
00934 }
00935
00936 void
00937 isc_timermgr_poke(isc_timermgr_t *manager0) {
00938 #ifdef USE_TIMER_THREAD
00939 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
00940
00941 REQUIRE(VALID_MANAGER(manager));
00942
00943 SIGNAL(&manager->wakeup);
00944 #else
00945 UNUSED(manager0);
00946 #endif
00947 }
00948
00949 void
00950 isc__timermgr_destroy(isc_timermgr_t **managerp) {
00951 isc__timermgr_t *manager;
00952 isc_mem_t *mctx;
00953
00954
00955
00956
00957
00958 REQUIRE(managerp != NULL);
00959 manager = (isc__timermgr_t *)*managerp;
00960 REQUIRE(VALID_MANAGER(manager));
00961
00962 LOCK(&manager->lock);
00963
00964 #ifdef USE_SHARED_MANAGER
00965 manager->refs--;
00966 if (manager->refs > 0) {
00967 UNLOCK(&manager->lock);
00968 *managerp = NULL;
00969 return;
00970 }
00971 timermgr = NULL;
00972 #endif
00973
00974 #ifndef USE_TIMER_THREAD
00975 isc__timermgr_dispatch((isc_timermgr_t *)manager);
00976 #endif
00977
00978 REQUIRE(EMPTY(manager->timers));
00979 manager->done = ISC_TRUE;
00980
00981 #ifdef USE_TIMER_THREAD
00982 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
00983 ISC_MSG_SIGNALDESTROY, "signal (destroy)"));
00984 SIGNAL(&manager->wakeup);
00985 #endif
00986
00987 UNLOCK(&manager->lock);
00988
00989 #ifdef USE_TIMER_THREAD
00990
00991
00992
00993 if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS)
00994 UNEXPECTED_ERROR(__FILE__, __LINE__,
00995 "isc_thread_join() %s",
00996 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00997 ISC_MSG_FAILED, "failed"));
00998 #endif
00999
01000
01001
01002
01003 #ifdef USE_TIMER_THREAD
01004 (void)isc_condition_destroy(&manager->wakeup);
01005 #endif
01006 DESTROYLOCK(&manager->lock);
01007 isc_heap_destroy(&manager->heap);
01008 manager->common.impmagic = 0;
01009 manager->common.magic = 0;
01010 mctx = manager->mctx;
01011 isc_mem_put(mctx, manager, sizeof(*manager));
01012 isc_mem_detach(&mctx);
01013
01014 *managerp = NULL;
01015
01016 #ifdef USE_SHARED_MANAGER
01017 timermgr = NULL;
01018 #endif
01019 }
01020
01021 #ifndef USE_TIMER_THREAD
01022 isc_result_t
01023 isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) {
01024 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
01025
01026 #ifdef USE_SHARED_MANAGER
01027 if (manager == NULL)
01028 manager = timermgr;
01029 #endif
01030 if (manager == NULL || manager->nscheduled == 0)
01031 return (ISC_R_NOTFOUND);
01032 *when = manager->due;
01033 return (ISC_R_SUCCESS);
01034 }
01035
01036 void
01037 isc__timermgr_dispatch(isc_timermgr_t *manager0) {
01038 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
01039 isc_time_t now;
01040
01041 #ifdef USE_SHARED_MANAGER
01042 if (manager == NULL)
01043 manager = timermgr;
01044 #endif
01045 if (manager == NULL)
01046 return;
01047 TIME_NOW(&now);
01048 dispatch(manager, &now);
01049 }
01050 #endif
01051
01052 isc_result_t
01053 isc__timer_register(void) {
01054 return (isc_timer_register(isc__timermgr_create));
01055 }
01056
01057 static isc_mutex_t createlock;
01058 static isc_once_t once = ISC_ONCE_INIT;
01059 static isc_timermgrcreatefunc_t timermgr_createfunc = NULL;
01060
01061 static void
01062 initialize(void) {
01063 RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
01064 }
01065
01066 isc_result_t
01067 isc_timer_register(isc_timermgrcreatefunc_t createfunc) {
01068 isc_result_t result = ISC_R_SUCCESS;
01069
01070 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
01071
01072 LOCK(&createlock);
01073 if (timermgr_createfunc == NULL)
01074 timermgr_createfunc = createfunc;
01075 else
01076 result = ISC_R_EXISTS;
01077 UNLOCK(&createlock);
01078
01079 return (result);
01080 }
01081
01082 isc_result_t
01083 isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
01084 isc_timermgr_t **managerp)
01085 {
01086 isc_result_t result;
01087
01088 LOCK(&createlock);
01089
01090 REQUIRE(timermgr_createfunc != NULL);
01091 result = (*timermgr_createfunc)(mctx, managerp);
01092
01093 UNLOCK(&createlock);
01094
01095 if (result == ISC_R_SUCCESS)
01096 isc_appctx_settimermgr(actx, *managerp);
01097
01098 return (result);
01099 }
01100
01101 isc_result_t
01102 isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
01103 isc_result_t result;
01104
01105 if (isc_bind9)
01106 return (isc__timermgr_create(mctx, managerp));
01107
01108 LOCK(&createlock);
01109
01110 REQUIRE(timermgr_createfunc != NULL);
01111 result = (*timermgr_createfunc)(mctx, managerp);
01112
01113 UNLOCK(&createlock);
01114
01115 return (result);
01116 }
01117
01118 void
01119 isc_timermgr_destroy(isc_timermgr_t **managerp) {
01120 REQUIRE(*managerp != NULL && ISCAPI_TIMERMGR_VALID(*managerp));
01121
01122 if (isc_bind9)
01123 isc__timermgr_destroy(managerp);
01124 else
01125 (*managerp)->methods->destroy(managerp);
01126
01127 ENSURE(*managerp == NULL);
01128 }
01129
01130 isc_result_t
01131 isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
01132 const isc_time_t *expires, const isc_interval_t *interval,
01133 isc_task_t *task, isc_taskaction_t action, void *arg,
01134 isc_timer_t **timerp)
01135 {
01136 REQUIRE(ISCAPI_TIMERMGR_VALID(manager));
01137
01138 if (isc_bind9)
01139 return (isc__timer_create(manager, type, expires, interval,
01140 task, action, arg, timerp));
01141
01142 return (manager->methods->timercreate(manager, type, expires,
01143 interval, task, action, arg,
01144 timerp));
01145 }
01146
01147 void
01148 isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) {
01149 REQUIRE(ISCAPI_TIMER_VALID(timer));
01150 REQUIRE(timerp != NULL && *timerp == NULL);
01151
01152 if (isc_bind9)
01153 isc__timer_attach(timer, timerp);
01154 else
01155 timer->methods->attach(timer, timerp);
01156
01157 ENSURE(*timerp == timer);
01158 }
01159
01160 void
01161 isc_timer_detach(isc_timer_t **timerp) {
01162 REQUIRE(timerp != NULL && ISCAPI_TIMER_VALID(*timerp));
01163
01164 if (isc_bind9)
01165 isc__timer_detach(timerp);
01166 else
01167 (*timerp)->methods->detach(timerp);
01168
01169 ENSURE(*timerp == NULL);
01170 }
01171
01172 isc_result_t
01173 isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
01174 const isc_time_t *expires, const isc_interval_t *interval,
01175 isc_boolean_t purge)
01176 {
01177 REQUIRE(ISCAPI_TIMER_VALID(timer));
01178
01179 if (isc_bind9)
01180 return (isc__timer_reset(timer, type, expires,
01181 interval, purge));
01182
01183 return (timer->methods->reset(timer, type, expires, interval, purge));
01184 }
01185
01186 isc_result_t
01187 isc_timer_touch(isc_timer_t *timer) {
01188 REQUIRE(ISCAPI_TIMER_VALID(timer));
01189
01190 if (isc_bind9)
01191 return (isc__timer_touch(timer));
01192
01193 return (timer->methods->touch(timer));
01194 }