diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c index 4adf3ad5d9..baeb01ed24 100644 --- a/lib/isc/unix/app.c +++ b/lib/isc/unix/app.c @@ -30,16 +30,16 @@ #include #include #include -#include -#include #include #include +#include #include "../util.h" /* XXX */ static isc_eventlist_t on_run; static isc_mutex_t lock; static isc_boolean_t shutdown_requested = ISC_FALSE; +static isc_boolean_t running = ISC_FALSE; #ifdef HAVE_LINUXTHREADS static pthread_t main_thread; @@ -153,13 +153,53 @@ isc_app_start(void) { return (ISC_R_SUCCESS); } +isc_result_t +isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, + void *arg) +{ + isc_event_t *event; + isc_task_t *cloned_task = NULL; + isc_result_t result; + + /* + * Request delivery of an event when the application is run. + */ + + LOCK(&lock); + + if (running) { + result = ISC_R_ALREADYRUNNING; + goto unlock; + } + + /* + * Note that we store the task to which we're going to send the event + * in the event's "sender" field. + */ + isc_task_attach(task, &cloned_task); + event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN, + action, arg, sizeof *event); + if (event == NULL) { + result = ISC_R_NOMEMORY; + goto unlock; + } + + ISC_LIST_APPEND(on_run, event, link); + + result = ISC_R_SUCCESS; + + unlock: + UNLOCK(&lock); + + return (result); +} + isc_result_t isc_app_run(void) { int result; sigset_t sset; -#if 0 isc_event_t *event, *next_event; -#endif + isc_task_t *task; #ifdef HAVE_SIGWAIT int sig; #endif @@ -172,19 +212,30 @@ isc_app_run(void) { REQUIRE(main_thread == pthread_self()); #endif -#if 0 + LOCK(&lock); + + running = ISC_TRUE; + /* - * Post any on-run events (in LIFO order). + * Post any on-run events (in FIFO order). */ for (event = ISC_LIST_HEAD(on_run); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, link); - ISC_LIST_DEQUEUE(task->on_run, event, link); - isc_task_send(task, &event); - isc_task_detach(&task); + ISC_LIST_UNLINK(on_run, event, link); + task = event->sender; + event->sender = (void *)&running; + isc_task_sendanddetach(&task, &event); } -#endif + + UNLOCK(&lock); + + /* + * There is no danger if isc_app_shutdown() is called before we wait + * for signals. Signals are blocked, so any such signal will simply + * be made pending and we will get it when we call sigwait(). + */ #ifdef HAVE_SIGWAIT /* @@ -231,6 +282,8 @@ isc_app_shutdown(void) { LOCK(&lock); + REQUIRE(running); + if (shutdown_requested) want_kill = ISC_FALSE; else diff --git a/lib/isc/unix/include/isc/app.h b/lib/isc/unix/include/isc/app.h index 57eb93d4c1..70c5ddf3d6 100644 --- a/lib/isc/unix/include/isc/app.h +++ b/lib/isc/unix/include/isc/app.h @@ -68,12 +68,16 @@ #include #include -#include +#include ISC_LANG_BEGINDECLS typedef isc_event_t isc_appevent_t; +#define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0) +#define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1) +#define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535) + isc_result_t isc_app_start(void); /* @@ -84,6 +88,20 @@ isc_app_start(void); * close to the beginning of the application as possible. */ +isc_result_t +isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, + void *arg); +/* + * Request delivery of an event when the application is run. + * + * Requires: + * isc_app_start() has been called. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + isc_result_t isc_app_run(void); /* @@ -93,6 +111,13 @@ isc_app_run(void); * The caller (typically the initial thread of an application) will * block until shutdown is requested. When the call returns, the * caller should start shutting down the application. + * + * Requires: + * isc_app_start() has been called. + * + * Ensures: + * Any events requested via isc_app_onrun() will have been posted (in + * FIFO order) before isc_app_run() blocks. */ isc_result_t @@ -104,7 +129,11 @@ isc_app_shutdown(void); * It is safe to call isc_app_shutdown() multiple times. * * Requires: - * isc_app_start() has been called. + * isc_app_run() has been called. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_UNEXPECTED */ void