📄 timer.c
字号:
timer, ISC_TIMEREVENT_FIRSTEVENT, ISC_TIMEREVENT_LASTEVENT, NULL); timer->type = type; timer->expires = *expires; timer->interval = *interval; if (type == isc_timertype_once && !isc_interval_iszero(interval)) { result = isc_time_add(&now, interval, &timer->idle); } else { isc_time_settoepoch(&timer->idle); result = ISC_R_SUCCESS; } if (result == ISC_R_SUCCESS) { if (type == isc_timertype_inactive) { deschedule(timer); result = ISC_R_SUCCESS; } else result = schedule(timer, &now, ISC_TRUE); } UNLOCK(&timer->lock); UNLOCK(&manager->lock); return (result);}isc_result_tisc_timer_gettype(isc_timer_t *timer) { isc_timertype_t t; REQUIRE(VALID_TIMER(timer)); LOCK(&timer->lock); t = timer->type; UNLOCK(&timer->lock); return (t);}isc_result_tisc_timer_touch(isc_timer_t *timer) { isc_result_t result; isc_time_t now; /* * Set the last-touched time of 'timer' to the current time. */ REQUIRE(VALID_TIMER(timer)); LOCK(&timer->lock); /* * We'd like to * * REQUIRE(timer->type == isc_timertype_once); * * but we cannot without locking the manager lock too, which we * don't want to do. */ TIME_NOW(&now); result = isc_time_add(&now, &timer->interval, &timer->idle); UNLOCK(&timer->lock); return (result);}voidisc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { /* * Attach *timerp to timer. */ REQUIRE(VALID_TIMER(timer)); REQUIRE(timerp != NULL && *timerp == NULL); LOCK(&timer->lock); timer->references++; UNLOCK(&timer->lock); *timerp = timer;}voidisc_timer_detach(isc_timer_t **timerp) { isc_timer_t *timer; isc_boolean_t free_timer = ISC_FALSE; /* * Detach *timerp from its timer. */ REQUIRE(timerp != NULL); timer = *timerp; REQUIRE(VALID_TIMER(timer)); LOCK(&timer->lock); REQUIRE(timer->references > 0); timer->references--; if (timer->references == 0) free_timer = ISC_TRUE; UNLOCK(&timer->lock); if (free_timer) destroy(timer); *timerp = NULL;}static voiddispatch(isc_timermgr_t *manager, isc_time_t *now) { isc_boolean_t done = ISC_FALSE, post_event, need_schedule; isc_event_t *event; isc_eventtype_t type = 0; isc_timer_t *timer; isc_result_t result; /* * The caller must be holding the manager lock. */ while (manager->nscheduled > 0 && !done) { timer = isc_heap_element(manager->heap, 1); INSIST(timer->type != isc_timertype_inactive); if (isc_time_compare(now, &timer->due) >= 0) { if (timer->type == isc_timertype_ticker) { type = ISC_TIMEREVENT_TICK; post_event = ISC_TRUE; need_schedule = ISC_TRUE; } else if (timer->type == isc_timertype_limited) { int cmp; cmp = isc_time_compare(now, &timer->expires); if (cmp >= 0) { type = ISC_TIMEREVENT_LIFE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else { type = ISC_TIMEREVENT_TICK; post_event = ISC_TRUE; need_schedule = ISC_TRUE; } } else if (!isc_time_isepoch(&timer->expires) && isc_time_compare(now, &timer->expires) >= 0) { type = ISC_TIMEREVENT_LIFE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else if (!isc_time_isepoch(&timer->idle) && isc_time_compare(now, &timer->idle) >= 0) { type = ISC_TIMEREVENT_IDLE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else { /* * Idle timer has been touched; reschedule. */ XTRACEID(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_IDLERESCHED, "idle reschedule"), timer); post_event = ISC_FALSE; need_schedule = ISC_TRUE; } if (post_event) { XTRACEID(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_POSTING, "posting"), timer); /* * XXX We could preallocate this event. */ event = isc_event_allocate(manager->mctx, timer, type, timer->action, timer->arg, sizeof(*event)); if (event != NULL) isc_task_send(timer->task, &event); else UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_EVENTNOTALLOC, "couldn't " "allocate event")); } timer->index = 0; isc_heap_delete(manager->heap, 1); manager->nscheduled--; if (need_schedule) { result = schedule(timer, now, ISC_FALSE); if (result != ISC_R_SUCCESS) UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SCHEDFAIL, "couldn't " "schedule timer: %u"), result); } } else { manager->due = timer->due; done = ISC_TRUE; } }}#ifdef ISC_PLATFORM_USETHREADSstatic isc_threadresult_t#ifdef _WIN32 /* XXXDCL */WINAPI#endifrun(void *uap) { isc_timermgr_t *manager = uap; isc_time_t now; isc_result_t result; LOCK(&manager->lock); while (!manager->done) { TIME_NOW(&now); XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_RUNNING, "running"), now); dispatch(manager, &now); if (manager->nscheduled > 0) { XTRACETIME2(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_WAITUNTIL, "waituntil"), manager->due, now); result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due); INSIST(result == ISC_R_SUCCESS || result == ISC_R_TIMEDOUT); } else { XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_WAIT, "wait"), now); WAIT(&manager->wakeup, &manager->lock); } XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_WAKEUP, "wakeup")); } UNLOCK(&manager->lock); return ((isc_threadresult_t)0);}#endif /* ISC_PLATFORM_USETHREADS */static isc_boolean_tsooner(void *v1, void *v2) { isc_timer_t *t1, *t2; t1 = v1; t2 = v2; REQUIRE(VALID_TIMER(t1)); REQUIRE(VALID_TIMER(t2)); if (isc_time_compare(&t1->due, &t2->due) < 0) return (ISC_TRUE); return (ISC_FALSE);}static voidset_index(void *what, unsigned int index) { isc_timer_t *timer; timer = what; REQUIRE(VALID_TIMER(timer)); timer->index = index;}isc_result_tisc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { isc_timermgr_t *manager; isc_result_t result; /* * Create a timer manager. */ REQUIRE(managerp != NULL && *managerp == NULL);#ifndef ISC_PLATFORM_USETHREADS if (timermgr != NULL) { timermgr->refs++; *managerp = timermgr; return (ISC_R_SUCCESS); }#endif /* ISC_PLATFORM_USETHREADS */ manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); manager->magic = TIMER_MANAGER_MAGIC; manager->mctx = NULL; manager->done = ISC_FALSE; INIT_LIST(manager->timers); manager->nscheduled = 0; isc_time_settoepoch(&manager->due); manager->heap = NULL; result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap); if (result != ISC_R_SUCCESS) { INSIST(result == ISC_R_NOMEMORY); isc_mem_put(mctx, manager, sizeof(*manager)); return (ISC_R_NOMEMORY); } if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) { isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "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)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); return (ISC_R_UNEXPECTED); } if (isc_thread_create(run, manager, &manager->thread) != ISC_R_SUCCESS) { isc_mem_detach(&manager->mctx); (void)isc_condition_destroy(&manager->wakeup); DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_create() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); return (ISC_R_UNEXPECTED); }#else /* ISC_PLATFORM_USETHREADS */ manager->refs = 1; timermgr = manager;#endif /* ISC_PLATFORM_USETHREADS */ *managerp = manager; return (ISC_R_SUCCESS);}voidisc_timermgr_poke(isc_timermgr_t *manager) {#ifdef ISC_PLATFORM_USETHREADS REQUIRE(VALID_MANAGER(manager)); SIGNAL(&manager->wakeup);#else UNUSED(manager);#endif}voidisc_timermgr_destroy(isc_timermgr_t **managerp) { isc_timermgr_t *manager; isc_mem_t *mctx; /* * Destroy a timer manager. */ REQUIRE(managerp != NULL); manager = *managerp; REQUIRE(VALID_MANAGER(manager)); LOCK(&manager->lock);#ifndef ISC_PLATFORM_USETHREADS if (manager->refs > 1) { manager->refs--; UNLOCK(&manager->lock); *managerp = NULL; return; } isc__timermgr_dispatch();#endif /* ISC_PLATFORM_USETHREADS */ REQUIRE(EMPTY(manager->timers)); manager->done = ISC_TRUE;#ifdef ISC_PLATFORM_USETHREADS XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALDESTROY, "signal (destroy)")); SIGNAL(&manager->wakeup);#endif /* ISC_PLATFORM_USETHREADS */ 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() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed"));#endif /* ISC_PLATFORM_USETHREADS */ /* * Clean up. */#ifdef ISC_PLATFORM_USETHREADS (void)isc_condition_destroy(&manager->wakeup);#endif /* ISC_PLATFORM_USETHREADS */ DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); manager->magic = 0; mctx = manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); *managerp = NULL;}#ifndef ISC_PLATFORM_USETHREADSisc_result_tisc__timermgr_nextevent(isc_time_t *when) { if (timermgr == NULL || timermgr->nscheduled == 0) return (ISC_R_NOTFOUND); *when = timermgr->due; return (ISC_R_SUCCESS);}voidisc__timermgr_dispatch(void) { isc_time_t now; if (timermgr == NULL) return; TIME_NOW(&now); dispatch(timermgr, &now);}#endif /* ISC_PLATFORM_USETHREADS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -