]> git.tuebingen.mpg.de Git - paraslash.git/blob - signal.c
6de9adf817f1a7b1885133729cd741dcff72399f
[paraslash.git] / signal.c
1 /*
2  * Copyright (C) 2004-2006 Andre Noll <maan@systemlinux.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18 /** \file signal.c signal handling functions */
19
20 #include "para.h"
21 #include "fd.h"
22 #include "error.h"
23 static int signal_pipe[2];
24
25 /**
26  * initialize the paraslash signal subsystem
27  *
28  * This function creates a pipe, the signal pipe, to deliver pending
29  * signals to the application (Bernstein's trick). It should be called
30  * during the application's startup part, followed by subsequent calls
31  * to para_install_sighandler() for each signal that should be caught.
32  *
33  * para_signal_init() installs a generic signal handler which is used for all
34  * signals simultaneously. When a signal arrives, this generic signal handler
35  * writes the corresponding signal number to the signal pipe so that the
36  * application can test for pending signals simply by checking the signal pipe
37  * for reading, e.g. by using the select(2) system call.
38  *
39  * \return This function either succeeds or calls exit(2) to terminate
40  * the current process. On success, the file descriptor of the signal pipe is
41  * returned.
42  */
43 int para_signal_init(void)
44 {
45         int ret = -E_SIGNAL_PIPE;
46         if (pipe(signal_pipe))
47                 goto err_out;
48         ret = mark_fd_nonblock(signal_pipe[0]);
49         if (ret < 0)
50                 goto err_out;
51         ret = mark_fd_nonblock(signal_pipe[1]);
52         if (ret < 0)
53                 goto err_out;
54         return signal_pipe[0];
55 err_out:
56         PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
57         exit(EXIT_FAILURE);
58 }
59
60 /*
61  * just write one integer to signal pipe
62  */
63 static void generic_signal_handler(int s)
64 {
65         write(signal_pipe[1], &s, sizeof(int));
66         //fprintf(stderr, "got sig %i, write returned %d\n", s, ret);
67 }
68
69 /**
70  * reap one child
71  *
72  * call waitpid() and print a log message containing the pid
73  * and the cause of the child's death.
74  *
75  * \return Like \p waitpid(), this function returns the process ID of the
76  * terminated child; on error, \p -E_WAITPID is returned.
77  * \sa waitpid(2)
78  */
79 pid_t para_reap_child(void)
80 {
81         int status;
82         pid_t pid = waitpid(-1, &status, WNOHANG);
83
84         if (pid <= 0) {
85                 if (pid < 0)
86                         pid = -E_WAITPID;
87                 return 0;
88         }
89         if (WIFEXITED(status))
90                 PARA_DEBUG_LOG("child %i exited. Exit status: %i\n", pid,
91                         WEXITSTATUS(status));
92         else if (WIFSIGNALED(status))
93                 PARA_DEBUG_LOG("child %i was killed by signal %i\n", pid,
94                         WTERMSIG(status));
95         else
96                 PARA_WARNING_LOG("child %i terminated abormally\n", pid);
97         return pid;
98 }
99
100 /**
101  * paraslash's zombie killer
102  *
103  * It just calls \p para_reap_child() until there are no more children left to
104  * reap.
105  */
106 void para_reap_children(void)
107 {
108         while (para_reap_child() > 0)
109                 ; /* nothing */
110 }
111
112 /**
113  * wrapper around signal(2)
114  * \param sig the number of the signal to catch
115  *
116  * This installs the generic signal handler for the given signal.
117  * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors.
118  * \sa signal(2)
119  */
120 int para_install_sighandler(int sig)
121 {
122         PARA_DEBUG_LOG("catching signal %d\n", sig);
123         return signal(sig, &generic_signal_handler) == SIG_ERR?  -E_SIGNAL_SIG_ERR : 1;
124 }
125
126 /**
127  * return number of next pending signal
128  *
129  * This should be called if the fd for the signal pipe is ready for reading.
130  *
131  * \return On success, the number of the received signal is returned. \p
132  * -E_SIGNAL_READ is returned if a read error occured while reading the signal
133  * pipe.  If the read was interrupted by another signal the function returns 0.
134  */
135 int para_next_signal(void)
136 {
137         int s;
138         ssize_t r;
139
140         if ((r = read(signal_pipe[0], &s, sizeof(s)) == sizeof(s)) > 0) {
141                 PARA_DEBUG_LOG("next signal: %d\n", s);
142                 return s;
143         }
144         return r < 0 && (errno != EAGAIN)? 0 : -E_SIGNAL_READ;
145 }