📄 app.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 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 ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC 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: app.c,v 1.43.2.3.8.5 2004/03/08 02:08:05 marka Exp $ */#include <config.h>#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */#include <sys/types.h>#include <stddef.h>#include <stdlib.h>#include <errno.h>#include <unistd.h>#include <signal.h>#include <sys/time.h>#include <isc/app.h>#include <isc/boolean.h>#include <isc/condition.h>#include <isc/msgs.h>#include <isc/mutex.h>#include <isc/event.h>#include <isc/platform.h>#include <isc/strerror.h>#include <isc/string.h>#include <isc/task.h>#include <isc/time.h>#include <isc/util.h>#ifdef ISC_PLATFORM_USETHREADS#include <pthread.h>#else /* ISC_PLATFORM_USETHREADS */#include "../timer_p.h"#include "../task_p.h"#include "socket_p.h"#endif /* ISC_PLATFORM_USETHREADS */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;/* * We assume that 'want_shutdown' can be read and written atomically. */static isc_boolean_t want_shutdown = ISC_FALSE;/* * We assume that 'want_reload' can be read and written atomically. */static isc_boolean_t want_reload = ISC_FALSE;static isc_boolean_t blocked = ISC_FALSE;#ifdef ISC_PLATFORM_USETHREADSstatic pthread_t blockedthread;#endif /* ISC_PLATFORM_USETHREADS */#ifdef HAVE_LINUXTHREADS/* * Linux has sigwait(), but it appears to prevent signal handlers from * running, even if they're not in the set being waited for. This makes * it impossible to get the default actions for SIGILL, SIGSEGV, etc. * Instead of messing with it, we just use sigsuspend() instead. */#undef HAVE_SIGWAIT/* * We need to remember which thread is the main thread... */static pthread_t main_thread;#endif#ifndef HAVE_SIGWAITstatic voidexit_action(int arg) { UNUSED(arg); want_shutdown = ISC_TRUE;}static voidreload_action(int arg) { UNUSED(arg); want_reload = ISC_TRUE;}#endifstatic isc_result_thandle_signal(int sig, void (*handler)(int)) { struct sigaction sa; char strbuf[ISC_STRERRORSIZE]; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; if (sigfillset(&sa.sa_mask) != 0 || sigaction(sig, &sa, NULL) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP, ISC_MSG_SIGNALSETUP, "handle_signal() %d setup: %s"), sig, strbuf); return (ISC_R_UNEXPECTED); } return (ISC_R_SUCCESS);}isc_result_tisc_app_start(void) { isc_result_t result; int presult; sigset_t sset; char strbuf[ISC_STRERRORSIZE]; /* * Start an ISC library application. */#ifdef NEED_PTHREAD_INIT /* * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this. */ presult = pthread_init(); if (presult != 0) { isc__strerror(presult, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() pthread_init: %s", strbuf); return (ISC_R_UNEXPECTED); }#endif#ifdef HAVE_LINUXTHREADS main_thread = pthread_self();#endif result = isc_mutex_init(&lock); if (result != ISC_R_SUCCESS) return (result);#ifndef HAVE_SIGWAIT /* * Install do-nothing handlers for SIGINT and SIGTERM. * * We install them now because BSDI 3.1 won't block * the default actions, regardless of what we do with * pthread_sigmask(). */ result = handle_signal(SIGINT, exit_action); if (result != ISC_R_SUCCESS) return (result); result = handle_signal(SIGTERM, exit_action); if (result != ISC_R_SUCCESS) return (result);#endif /* * Always ignore SIGPIPE. */ result = handle_signal(SIGPIPE, SIG_IGN); if (result != ISC_R_SUCCESS) return (result); /* * On Solaris 2, delivery of a signal whose action is SIG_IGN * will not cause sigwait() to return. We may have inherited * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent * process (e.g, Solaris cron). Set an action of SIG_DFL to make * sure sigwait() works as expected. Only do this for SIGTERM and * SIGINT if we don't have sigwait(), since a different handler is * installed above. */ result = handle_signal(SIGHUP, SIG_DFL); if (result != ISC_R_SUCCESS) return (result);#ifdef HAVE_SIGWAIT result = handle_signal(SIGTERM, SIG_DFL); if (result != ISC_R_SUCCESS) return (result); result = handle_signal(SIGINT, SIG_DFL); if (result != ISC_R_SUCCESS) return (result);#endif#ifdef ISC_PLATFORM_USETHREADS /* * Block SIGHUP, SIGINT, SIGTERM. * * If isc_app_start() is called from the main thread before any other * threads have been created, then the pthread_sigmask() call below * will result in all threads having SIGHUP, SIGINT and SIGTERM * blocked by default, ensuring that only the thread that calls * sigwait() for them will get those signals. */ if (sigemptyset(&sset) != 0 || sigaddset(&sset, SIGHUP) != 0 || sigaddset(&sset, SIGINT) != 0 || sigaddset(&sset, SIGTERM) != 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigsetops: %s", strbuf); return (ISC_R_UNEXPECTED); } presult = pthread_sigmask(SIG_BLOCK, &sset, NULL); if (presult != 0) { isc__strerror(presult, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() pthread_sigmask: %s", strbuf); return (ISC_R_UNEXPECTED); }#else /* ISC_PLATFORM_USETHREADS */ /* * Unblock SIGHUP, SIGINT, SIGTERM. * * If we're not using threads, we need to make sure that SIGHUP, * SIGINT and SIGTERM are not inherited as blocked from the parent * process. */ if (sigemptyset(&sset) != 0 || sigaddset(&sset, SIGHUP) != 0 || sigaddset(&sset, SIGINT) != 0 || sigaddset(&sset, SIGTERM) != 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigsetops: %s", strbuf); return (ISC_R_UNEXPECTED); } presult = sigprocmask(SIG_UNBLOCK, &sset, NULL); if (presult != 0) { isc__strerror(presult, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_start() sigprocmask: %s", strbuf); return (ISC_R_UNEXPECTED); }#endif /* ISC_PLATFORM_USETHREADS */ ISC_LIST_INIT(on_run); return (ISC_R_SUCCESS);}isc_result_tisc_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; 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, ev_link); result = ISC_R_SUCCESS; unlock: UNLOCK(&lock); return (result);}#ifndef ISC_PLATFORM_USETHREADS/* * Event loop for nonthreaded programs. */static isc_result_tevloop() { isc_result_t result; while (!want_shutdown) { int n; isc_time_t when, now; struct timeval tv, *tvp; fd_set readfds, writefds; int maxfd; isc_boolean_t readytasks; isc_boolean_t call_timer_dispatch = ISC_FALSE; readytasks = isc__taskmgr_ready(); if (readytasks) { tv.tv_sec = 0; tv.tv_usec = 0; tvp = &tv; call_timer_dispatch = ISC_TRUE; } else { result = isc__timermgr_nextevent(&when); if (result != ISC_R_SUCCESS) tvp = NULL; else { isc_uint64_t us; TIME_NOW(&now); us = isc_time_microdiff(&when, &now); if (us == 0) call_timer_dispatch = ISC_TRUE; tv.tv_sec = us / 1000000; tv.tv_usec = us % 1000000; tvp = &tv; } } isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd); n = select(maxfd, &readfds, &writefds, NULL, tvp); if (n == 0 || call_timer_dispatch) { /* * We call isc__timermgr_dispatch() only when * necessary, in order to reduce overhead. If the * select() call indicates a timeout, we need the * dispatch. Even if not, if we set the 0-timeout * for the select() call, we need to check the timer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -