iostat - add read/write details to output
[dragonfly.git] / contrib / bind / lib / isc / unix / app.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: app.c,v 1.54.128.6 2008/10/15 03:41:17 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <sys/param.h>  /* Openserver 5.0.6A and FD_SETSIZE */
25 #include <sys/types.h>
26
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <sys/time.h>
33 #ifdef HAVE_EPOLL
34 #include <sys/epoll.h>
35 #endif
36
37 #include <isc/app.h>
38 #include <isc/boolean.h>
39 #include <isc/condition.h>
40 #include <isc/msgs.h>
41 #include <isc/mutex.h>
42 #include <isc/event.h>
43 #include <isc/platform.h>
44 #include <isc/strerror.h>
45 #include <isc/string.h>
46 #include <isc/task.h>
47 #include <isc/time.h>
48 #include <isc/util.h>
49
50 #ifdef ISC_PLATFORM_USETHREADS
51 #include <pthread.h>
52 #else /* ISC_PLATFORM_USETHREADS */
53 #include "../timer_p.h"
54 #include "../task_p.h"
55 #include "socket_p.h"
56 #endif /* ISC_PLATFORM_USETHREADS */
57
58 static isc_eventlist_t          on_run;
59 static isc_mutex_t              lock;
60 static isc_boolean_t            shutdown_requested = ISC_FALSE;
61 static isc_boolean_t            running = ISC_FALSE;
62 /*!
63  * We assume that 'want_shutdown' can be read and written atomically.
64  */
65 static volatile isc_boolean_t   want_shutdown = ISC_FALSE;
66 /*
67  * We assume that 'want_reload' can be read and written atomically.
68  */
69 static volatile isc_boolean_t   want_reload = ISC_FALSE;
70
71 static isc_boolean_t            blocked  = ISC_FALSE;
72 #ifdef ISC_PLATFORM_USETHREADS
73 static pthread_t                blockedthread;
74 #endif /* ISC_PLATFORM_USETHREADS */
75
76 #ifdef HAVE_LINUXTHREADS
77 /*!
78  * Linux has sigwait(), but it appears to prevent signal handlers from
79  * running, even if they're not in the set being waited for.  This makes
80  * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
81  * Instead of messing with it, we just use sigsuspend() instead.
82  */
83 #undef HAVE_SIGWAIT
84 /*!
85  * We need to remember which thread is the main thread...
86  */
87 static pthread_t                main_thread;
88 #endif
89
90 #ifndef HAVE_SIGWAIT
91 static void
92 exit_action(int arg) {
93         UNUSED(arg);
94         want_shutdown = ISC_TRUE;
95 }
96
97 static void
98 reload_action(int arg) {
99         UNUSED(arg);
100         want_reload = ISC_TRUE;
101 }
102 #endif
103
104 static isc_result_t
105 handle_signal(int sig, void (*handler)(int)) {
106         struct sigaction sa;
107         char strbuf[ISC_STRERRORSIZE];
108
109         memset(&sa, 0, sizeof(sa));
110         sa.sa_handler = handler;
111
112         if (sigfillset(&sa.sa_mask) != 0 ||
113             sigaction(sig, &sa, NULL) < 0) {
114                 isc__strerror(errno, strbuf, sizeof(strbuf));
115                 UNEXPECTED_ERROR(__FILE__, __LINE__,
116                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
117                                                ISC_MSG_SIGNALSETUP,
118                                                "handle_signal() %d setup: %s"),
119                                  sig, strbuf);
120                 return (ISC_R_UNEXPECTED);
121         }
122
123         return (ISC_R_SUCCESS);
124 }
125
126 isc_result_t
127 isc_app_start(void) {
128         isc_result_t result;
129         int presult;
130         sigset_t sset;
131         char strbuf[ISC_STRERRORSIZE];
132
133         /*
134          * Start an ISC library application.
135          */
136
137 #ifdef NEED_PTHREAD_INIT
138         /*
139          * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
140          */
141         presult = pthread_init();
142         if (presult != 0) {
143                 isc__strerror(presult, strbuf, sizeof(strbuf));
144                 UNEXPECTED_ERROR(__FILE__, __LINE__,
145                                  "isc_app_start() pthread_init: %s", strbuf);
146                 return (ISC_R_UNEXPECTED);
147         }
148 #endif
149
150 #ifdef HAVE_LINUXTHREADS
151         main_thread = pthread_self();
152 #endif
153
154         result = isc_mutex_init(&lock);
155         if (result != ISC_R_SUCCESS)
156                 return (result);
157
158 #ifndef HAVE_SIGWAIT
159         /*
160          * Install do-nothing handlers for SIGINT and SIGTERM.
161          *
162          * We install them now because BSDI 3.1 won't block
163          * the default actions, regardless of what we do with
164          * pthread_sigmask().
165          */
166         result = handle_signal(SIGINT, exit_action);
167         if (result != ISC_R_SUCCESS)
168                 return (result);
169         result = handle_signal(SIGTERM, exit_action);
170         if (result != ISC_R_SUCCESS)
171                 return (result);
172 #endif
173
174         /*
175          * Always ignore SIGPIPE.
176          */
177         result = handle_signal(SIGPIPE, SIG_IGN);
178         if (result != ISC_R_SUCCESS)
179                 return (result);
180
181         /*
182          * On Solaris 2, delivery of a signal whose action is SIG_IGN
183          * will not cause sigwait() to return. We may have inherited
184          * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
185          * process (e.g, Solaris cron).  Set an action of SIG_DFL to make
186          * sure sigwait() works as expected.  Only do this for SIGTERM and
187          * SIGINT if we don't have sigwait(), since a different handler is
188          * installed above.
189          */
190         result = handle_signal(SIGHUP, SIG_DFL);
191         if (result != ISC_R_SUCCESS)
192                 return (result);
193
194 #ifdef HAVE_SIGWAIT
195         result = handle_signal(SIGTERM, SIG_DFL);
196         if (result != ISC_R_SUCCESS)
197                 return (result);
198         result = handle_signal(SIGINT, SIG_DFL);
199         if (result != ISC_R_SUCCESS)
200                 return (result);
201 #endif
202
203 #ifdef ISC_PLATFORM_USETHREADS
204         /*
205          * Block SIGHUP, SIGINT, SIGTERM.
206          *
207          * If isc_app_start() is called from the main thread before any other
208          * threads have been created, then the pthread_sigmask() call below
209          * will result in all threads having SIGHUP, SIGINT and SIGTERM
210          * blocked by default, ensuring that only the thread that calls
211          * sigwait() for them will get those signals.
212          */
213         if (sigemptyset(&sset) != 0 ||
214             sigaddset(&sset, SIGHUP) != 0 ||
215             sigaddset(&sset, SIGINT) != 0 ||
216             sigaddset(&sset, SIGTERM) != 0) {
217                 isc__strerror(errno, strbuf, sizeof(strbuf));
218                 UNEXPECTED_ERROR(__FILE__, __LINE__,
219                                  "isc_app_start() sigsetops: %s", strbuf);
220                 return (ISC_R_UNEXPECTED);
221         }
222         presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
223         if (presult != 0) {
224                 isc__strerror(presult, strbuf, sizeof(strbuf));
225                 UNEXPECTED_ERROR(__FILE__, __LINE__,
226                                  "isc_app_start() pthread_sigmask: %s",
227                                  strbuf);
228                 return (ISC_R_UNEXPECTED);
229         }
230 #else /* ISC_PLATFORM_USETHREADS */
231         /*
232          * Unblock SIGHUP, SIGINT, SIGTERM.
233          *
234          * If we're not using threads, we need to make sure that SIGHUP,
235          * SIGINT and SIGTERM are not inherited as blocked from the parent
236          * process.
237          */
238         if (sigemptyset(&sset) != 0 ||
239             sigaddset(&sset, SIGHUP) != 0 ||
240             sigaddset(&sset, SIGINT) != 0 ||
241             sigaddset(&sset, SIGTERM) != 0) {
242                 isc__strerror(errno, strbuf, sizeof(strbuf));
243                 UNEXPECTED_ERROR(__FILE__, __LINE__,
244                                  "isc_app_start() sigsetops: %s", strbuf);
245                 return (ISC_R_UNEXPECTED);
246         }
247         presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
248         if (presult != 0) {
249                 isc__strerror(presult, strbuf, sizeof(strbuf));
250                 UNEXPECTED_ERROR(__FILE__, __LINE__,
251                                  "isc_app_start() sigprocmask: %s", strbuf);
252                 return (ISC_R_UNEXPECTED);
253         }
254 #endif /* ISC_PLATFORM_USETHREADS */
255
256         ISC_LIST_INIT(on_run);
257
258         return (ISC_R_SUCCESS);
259 }
260
261 isc_result_t
262 isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
263               void *arg)
264 {
265         isc_event_t *event;
266         isc_task_t *cloned_task = NULL;
267         isc_result_t result;
268
269         LOCK(&lock);
270
271         if (running) {
272                 result = ISC_R_ALREADYRUNNING;
273                 goto unlock;
274         }
275
276         /*
277          * Note that we store the task to which we're going to send the event
278          * in the event's "sender" field.
279          */
280         isc_task_attach(task, &cloned_task);
281         event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
282                                    action, arg, sizeof(*event));
283         if (event == NULL) {
284                 result = ISC_R_NOMEMORY;
285                 goto unlock;
286         }
287
288         ISC_LIST_APPEND(on_run, event, ev_link);
289
290         result = ISC_R_SUCCESS;
291
292  unlock:
293         UNLOCK(&lock);
294
295         return (result);
296 }
297
298 #ifndef ISC_PLATFORM_USETHREADS
299 /*!
300  * Event loop for nonthreaded programs.
301  */
302 static isc_result_t
303 evloop(void) {
304         isc_result_t result;
305         while (!want_shutdown) {
306                 int n;
307                 isc_time_t when, now;
308                 struct timeval tv, *tvp;
309                 isc_socketwait_t *swait;
310                 isc_boolean_t readytasks;
311                 isc_boolean_t call_timer_dispatch = ISC_FALSE;
312
313                 readytasks = isc__taskmgr_ready();
314                 if (readytasks) {
315                         tv.tv_sec = 0;
316                         tv.tv_usec = 0;
317                         tvp = &tv;
318                         call_timer_dispatch = ISC_TRUE;
319                 } else {
320                         result = isc__timermgr_nextevent(&when);
321                         if (result != ISC_R_SUCCESS)
322                                 tvp = NULL;
323                         else {
324                                 isc_uint64_t us;
325
326                                 TIME_NOW(&now);
327                                 us = isc_time_microdiff(&when, &now);
328                                 if (us == 0)
329                                         call_timer_dispatch = ISC_TRUE;
330                                 tv.tv_sec = us / 1000000;
331                                 tv.tv_usec = us % 1000000;
332                                 tvp = &tv;
333                         }
334                 }
335
336                 swait = NULL;
337                 n = isc__socketmgr_waitevents(tvp, &swait);
338
339                 if (n == 0 || call_timer_dispatch) {
340                         /*
341                          * We call isc__timermgr_dispatch() only when
342                          * necessary, in order to reduce overhead.  If the
343                          * select() call indicates a timeout, we need the
344                          * dispatch.  Even if not, if we set the 0-timeout
345                          * for the select() call, we need to check the timer
346                          * events.  In the 'readytasks' case, there may be no
347                          * timeout event actually, but there is no other way
348                          * to reduce the overhead.
349                          * Note that we do not have to worry about the case
350                          * where a new timer is inserted during the select()
351                          * call, since this loop only runs in the non-thread
352                          * mode.
353                          */
354                         isc__timermgr_dispatch();
355                 }
356                 if (n > 0)
357                         (void)isc__socketmgr_dispatch(swait);
358                 (void)isc__taskmgr_dispatch();
359
360                 if (want_reload) {
361                         want_reload = ISC_FALSE;
362                         return (ISC_R_RELOAD);
363                 }
364         }
365         return (ISC_R_SUCCESS);
366 }
367
368 /*
369  * This is a gross hack to support waiting for condition
370  * variables in nonthreaded programs in a limited way;
371  * see lib/isc/nothreads/include/isc/condition.h.
372  * We implement isc_condition_wait() by entering the
373  * event loop recursively until the want_shutdown flag
374  * is set by isc_condition_signal().
375  */
376
377 /*!
378  * \brief True if we are currently executing in the recursive
379  * event loop.
380  */
381 static isc_boolean_t in_recursive_evloop = ISC_FALSE;
382
383 /*!
384  * \brief True if we are exiting the event loop as the result of
385  * a call to isc_condition_signal() rather than a shutdown
386  * or reload.
387  */
388 static isc_boolean_t signalled = ISC_FALSE;
389
390 isc_result_t
391 isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
392         isc_result_t result;
393
394         UNUSED(cp);
395         UNUSED(mp);
396
397         INSIST(!in_recursive_evloop);
398         in_recursive_evloop = ISC_TRUE;
399
400         INSIST(*mp == 1); /* Mutex must be locked on entry. */
401         --*mp;
402
403         result = evloop();
404         if (result == ISC_R_RELOAD)
405                 want_reload = ISC_TRUE;
406         if (signalled) {
407                 want_shutdown = ISC_FALSE;
408                 signalled = ISC_FALSE;
409         }
410
411         ++*mp;
412         in_recursive_evloop = ISC_FALSE;
413         return (ISC_R_SUCCESS);
414 }
415
416 isc_result_t
417 isc__nothread_signal_hack(isc_condition_t *cp) {
418
419         UNUSED(cp);
420
421         INSIST(in_recursive_evloop);
422
423         want_shutdown = ISC_TRUE;
424         signalled = ISC_TRUE;
425         return (ISC_R_SUCCESS);
426 }
427
428 #endif /* ISC_PLATFORM_USETHREADS */
429
430 isc_result_t
431 isc_app_run(void) {
432         int result;
433         isc_event_t *event, *next_event;
434         isc_task_t *task;
435 #ifdef ISC_PLATFORM_USETHREADS
436         sigset_t sset;
437         char strbuf[ISC_STRERRORSIZE];
438 #ifdef HAVE_SIGWAIT
439         int sig;
440 #endif
441 #endif /* ISC_PLATFORM_USETHREADS */
442
443 #ifdef HAVE_LINUXTHREADS
444         REQUIRE(main_thread == pthread_self());
445 #endif
446
447         LOCK(&lock);
448
449         if (!running) {
450                 running = ISC_TRUE;
451
452                 /*
453                  * Post any on-run events (in FIFO order).
454                  */
455                 for (event = ISC_LIST_HEAD(on_run);
456                      event != NULL;
457                      event = next_event) {
458                         next_event = ISC_LIST_NEXT(event, ev_link);
459                         ISC_LIST_UNLINK(on_run, event, ev_link);
460                         task = event->ev_sender;
461                         event->ev_sender = NULL;
462                         isc_task_sendanddetach(&task, &event);
463                 }
464
465         }
466
467         UNLOCK(&lock);
468
469 #ifndef HAVE_SIGWAIT
470         /*
471          * Catch SIGHUP.
472          *
473          * We do this here to ensure that the signal handler is installed
474          * (i.e. that it wasn't a "one-shot" handler).
475          */
476         result = handle_signal(SIGHUP, reload_action);
477         if (result != ISC_R_SUCCESS)
478                 return (ISC_R_SUCCESS);
479 #endif
480
481 #ifdef ISC_PLATFORM_USETHREADS
482         /*
483          * There is no danger if isc_app_shutdown() is called before we wait
484          * for signals.  Signals are blocked, so any such signal will simply
485          * be made pending and we will get it when we call sigwait().
486          */
487
488         while (!want_shutdown) {
489 #ifdef HAVE_SIGWAIT
490                 /*
491                  * Wait for SIGHUP, SIGINT, or SIGTERM.
492                  */
493                 if (sigemptyset(&sset) != 0 ||
494                     sigaddset(&sset, SIGHUP) != 0 ||
495                     sigaddset(&sset, SIGINT) != 0 ||
496                     sigaddset(&sset, SIGTERM) != 0) {
497                         isc__strerror(errno, strbuf, sizeof(strbuf));
498                         UNEXPECTED_ERROR(__FILE__, __LINE__,
499                                          "isc_app_run() sigsetops: %s", strbuf);
500                         return (ISC_R_UNEXPECTED);
501                 }
502
503 #ifndef HAVE_UNIXWARE_SIGWAIT
504                 result = sigwait(&sset, &sig);
505                 if (result == 0) {
506                         if (sig == SIGINT ||
507                             sig == SIGTERM)
508                                 want_shutdown = ISC_TRUE;
509                         else if (sig == SIGHUP)
510                                 want_reload = ISC_TRUE;
511                 }
512
513 #else /* Using UnixWare sigwait semantics. */
514                 sig = sigwait(&sset);
515                 if (sig >= 0) {
516                         if (sig == SIGINT ||
517                             sig == SIGTERM)
518                                 want_shutdown = ISC_TRUE;
519                         else if (sig == SIGHUP)
520                                 want_reload = ISC_TRUE;
521                 }
522
523 #endif /* HAVE_UNIXWARE_SIGWAIT */
524 #else  /* Don't have sigwait(). */
525                 /*
526                  * Listen for all signals.
527                  */
528                 if (sigemptyset(&sset) != 0) {
529                         isc__strerror(errno, strbuf, sizeof(strbuf));
530                         UNEXPECTED_ERROR(__FILE__, __LINE__,
531                                          "isc_app_run() sigsetops: %s", strbuf);
532                         return (ISC_R_UNEXPECTED);
533                 }
534                 result = sigsuspend(&sset);
535 #endif /* HAVE_SIGWAIT */
536
537                 if (want_reload) {
538                         want_reload = ISC_FALSE;
539                         return (ISC_R_RELOAD);
540                 }
541
542                 if (want_shutdown && blocked)
543                         exit(1);
544         }
545
546 #else /* ISC_PLATFORM_USETHREADS */
547
548         (void)isc__taskmgr_dispatch();
549
550         result = evloop();
551         if (result != ISC_R_SUCCESS)
552                 return (result);
553
554 #endif /* ISC_PLATFORM_USETHREADS */
555
556         return (ISC_R_SUCCESS);
557 }
558
559 isc_result_t
560 isc_app_shutdown(void) {
561         isc_boolean_t want_kill = ISC_TRUE;
562         char strbuf[ISC_STRERRORSIZE];
563
564         LOCK(&lock);
565
566         REQUIRE(running);
567
568         if (shutdown_requested)
569                 want_kill = ISC_FALSE;
570         else
571                 shutdown_requested = ISC_TRUE;
572
573         UNLOCK(&lock);
574
575         if (want_kill) {
576 #ifdef HAVE_LINUXTHREADS
577                 int result;
578
579                 result = pthread_kill(main_thread, SIGTERM);
580                 if (result != 0) {
581                         isc__strerror(result, strbuf, sizeof(strbuf));
582                         UNEXPECTED_ERROR(__FILE__, __LINE__,
583                                          "isc_app_shutdown() pthread_kill: %s",
584                                          strbuf);
585                         return (ISC_R_UNEXPECTED);
586                 }
587 #else
588                 if (kill(getpid(), SIGTERM) < 0) {
589                         isc__strerror(errno, strbuf, sizeof(strbuf));
590                         UNEXPECTED_ERROR(__FILE__, __LINE__,
591                                          "isc_app_shutdown() kill: %s", strbuf);
592                         return (ISC_R_UNEXPECTED);
593                 }
594 #endif
595         }
596
597         return (ISC_R_SUCCESS);
598 }
599
600 isc_result_t
601 isc_app_reload(void) {
602         isc_boolean_t want_kill = ISC_TRUE;
603         char strbuf[ISC_STRERRORSIZE];
604
605         LOCK(&lock);
606
607         REQUIRE(running);
608
609         /*
610          * Don't send the reload signal if we're shutting down.
611          */
612         if (shutdown_requested)
613                 want_kill = ISC_FALSE;
614
615         UNLOCK(&lock);
616
617         if (want_kill) {
618 #ifdef HAVE_LINUXTHREADS
619                 int result;
620
621                 result = pthread_kill(main_thread, SIGHUP);
622                 if (result != 0) {
623                         isc__strerror(result, strbuf, sizeof(strbuf));
624                         UNEXPECTED_ERROR(__FILE__, __LINE__,
625                                          "isc_app_reload() pthread_kill: %s",
626                                          strbuf);
627                         return (ISC_R_UNEXPECTED);
628                 }
629 #else
630                 if (kill(getpid(), SIGHUP) < 0) {
631                         isc__strerror(errno, strbuf, sizeof(strbuf));
632                         UNEXPECTED_ERROR(__FILE__, __LINE__,
633                                          "isc_app_reload() kill: %s", strbuf);
634                         return (ISC_R_UNEXPECTED);
635                 }
636 #endif
637         }
638
639         return (ISC_R_SUCCESS);
640 }
641
642 void
643 isc_app_finish(void) {
644         DESTROYLOCK(&lock);
645 }
646
647 void
648 isc_app_block(void) {
649 #ifdef ISC_PLATFORM_USETHREADS
650         sigset_t sset;
651 #endif /* ISC_PLATFORM_USETHREADS */
652         REQUIRE(running);
653         REQUIRE(!blocked);
654
655         blocked = ISC_TRUE;
656 #ifdef ISC_PLATFORM_USETHREADS
657         blockedthread = pthread_self();
658         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
659                       sigaddset(&sset, SIGINT) == 0 &&
660                       sigaddset(&sset, SIGTERM) == 0);
661         RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
662 #endif /* ISC_PLATFORM_USETHREADS */
663 }
664
665 void
666 isc_app_unblock(void) {
667 #ifdef ISC_PLATFORM_USETHREADS
668         sigset_t sset;
669 #endif /* ISC_PLATFORM_USETHREADS */
670
671         REQUIRE(running);
672         REQUIRE(blocked);
673
674         blocked = ISC_FALSE;
675
676 #ifdef ISC_PLATFORM_USETHREADS
677         REQUIRE(blockedthread == pthread_self());
678
679         RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
680                       sigaddset(&sset, SIGINT) == 0 &&
681                       sigaddset(&sset, SIGTERM) == 0);
682         RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
683 #endif /* ISC_PLATFORM_USETHREADS */
684 }