-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / util / signal.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2006 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file util/signal.c
21  * @brief code for installing and uninstalling signal handlers
22  * @author Christian Grothoff
23  */
24
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27
28 #define LOG(kind,...) GNUNET_log_from (kind, "util-signal", __VA_ARGS__)
29
30
31 struct GNUNET_SIGNAL_Context
32 {
33
34   struct GNUNET_SIGNAL_Context *next;
35
36   struct GNUNET_SIGNAL_Context *prev;
37
38   int sig;
39
40   GNUNET_SIGNAL_Handler method;
41
42 #ifndef MINGW
43   struct sigaction oldsig;
44 #endif
45 };
46
47 static struct GNUNET_SIGNAL_Context *sc_head;
48
49 static struct GNUNET_SIGNAL_Context *sc_tail;
50
51
52 #ifdef WINDOWS
53 GNUNET_SIGNAL_Handler w32_sigchld_handler = NULL;
54 #endif
55
56 struct GNUNET_SIGNAL_Context *
57 GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler)
58 {
59   struct GNUNET_SIGNAL_Context *ret;
60
61 #ifndef MINGW
62   struct sigaction sig;
63 #endif
64
65   ret = GNUNET_new (struct GNUNET_SIGNAL_Context);
66   ret->sig = signum;
67   ret->method = handler;
68 #ifndef MINGW
69   memset (&sig, 0, sizeof (sig));
70   sig.sa_handler = (void *) handler;
71   sigemptyset (&sig.sa_mask);
72 #ifdef SA_INTERRUPT
73   sig.sa_flags = SA_INTERRUPT;  /* SunOS */
74 #else
75   sig.sa_flags = SA_RESTART;
76 #endif
77   sigaction (signum, &sig, &ret->oldsig);
78 #else
79   if (signum == GNUNET_SIGCHLD)
80     w32_sigchld_handler = handler;
81   else
82   {
83     __p_sig_fn_t sigret = signal (signum, (__p_sig_fn_t) handler);
84
85     if (sigret == SIG_ERR)
86     {
87       LOG (GNUNET_ERROR_TYPE_WARNING, _("signal (%d, %p) returned %d.\n"),
88            signum, handler, sigret);
89     }
90   }
91 #endif
92   GNUNET_CONTAINER_DLL_insert_tail (sc_head, sc_tail, ret);
93   return ret;
94 }
95
96 void
97 GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx)
98 {
99 #ifndef MINGW
100   struct sigaction sig;
101
102   sigemptyset (&sig.sa_mask);
103   sigaction (ctx->sig, &ctx->oldsig, &sig);
104 #endif
105   GNUNET_CONTAINER_DLL_remove (sc_head, sc_tail, ctx);
106   GNUNET_free (ctx);
107 }
108
109
110 /**
111  * Raise the given signal by calling the installed signal handlers.  This will
112  * not use the @em raise() system call but only calls the handlers registered
113  * through GNUNET_SIGNAL_handler_install().
114  *
115  * @param sig the signal to raise
116  */
117 void
118 GNUNET_SIGNAL_raise (const int sig)
119 {
120   struct GNUNET_SIGNAL_Context *ctx;
121
122   for (ctx = sc_head; NULL != ctx; ctx = ctx->next)
123   {
124     if (sig != ctx->sig)
125       continue;
126     if (NULL == ctx->method)
127       continue;
128     ctx->method ();
129   }
130 }