ipc: Fix error code returned by mutex_lock().
[dss.git] / sig.c
1 /*
2  * Copyright (C) 2004-2010 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 #include <string.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <dirent.h>
13 #include <assert.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <stdlib.h>
18 #include <sys/select.h>
19
20
21 #include "gcc-compat.h"
22 #include "err.h"
23 #include "log.h"
24 #include "str.h"
25 #include "file.h"
26 #include "sig.h"
27
28 static int signal_pipe[2];
29
30 /**
31  * Initialize the signal subsystem.
32  *
33  * This function creates a pipe, the signal pipe, to deliver pending signals to
34  * the application (Bernstein's trick). It should be called during the
35  * application's startup part, followed by subsequent calls to
36  * install_sighandler() for each signal that should be caught.
37  *
38  * signal_init() installs a generic signal handler which is used for all
39  * signals simultaneously. When a signal arrives, this generic signal handler
40  * writes the corresponding signal number to the signal pipe so that the
41  * application can test for pending signals simply by checking the signal pipe
42  * for reading, e.g. by using the select(2) system call.
43  *
44  * \return This function either succeeds or calls exit(2) to terminate
45  * the current process. On success, the file descriptor of the signal pipe is
46  * returned.
47  */
48 int signal_init(void)
49 {
50         int ret;
51         if (pipe(signal_pipe) < 0) {
52                 ret = -ERRNO_TO_DSS_ERROR(errno);
53                 goto err_out;
54         }
55         ret = mark_fd_nonblocking(signal_pipe[0]);
56         if (ret < 0)
57                 goto err_out;
58         ret = mark_fd_nonblocking(signal_pipe[1]);
59         if (ret < 0)
60                 goto err_out;
61         return signal_pipe[0];
62 err_out:
63         DSS_EMERG_LOG(("%s\n", dss_strerror(-ret)));
64         exit(EXIT_FAILURE);
65 }
66
67 /* Write the signal number to the signal pipe, abort on errors. */
68 static void generic_signal_handler(int s)
69 {
70         /*
71          * Signal handlers that make system calls must save a copy of errno on
72          * entry to the handler and restore it on exit, to prevent the
73          * possibility of overwriting a errno value that had previously been
74          * set in the main program.
75          */
76         int save_errno = errno;
77         ssize_t ret = write(signal_pipe[1], &s, sizeof(int));
78
79         if (ret == sizeof(int)) {
80                 errno = save_errno;
81                 return;
82         }
83         if (ret < 0)
84                 DSS_EMERG_LOG(("%s\n", strerror(errno)));
85         else
86                 DSS_EMERG_LOG(("short write to signal pipe\n"));
87         exit(EXIT_FAILURE);
88 }
89
90 /**
91  * Reap one child.
92  *
93  * \param pid In case a child died, its pid is returned here.
94  *
95  * Call waitpid() and print a log message containing the pid and the cause of
96  * the child's death.
97  *
98  * \return A (negative) error code on errors, zero, if no child died, one
99  * otherwise. If and only if the function returns one, the content of \a pid is
100  * meaningful.
101  *
102  * \sa waitpid(2)
103  */
104 int reap_child(pid_t *pid, int *status)
105 {
106         *pid = waitpid(-1, status, WNOHANG);
107
108         if (!*pid)
109                 return 0;
110         if (*pid < 0)
111                 return -ERRNO_TO_DSS_ERROR(errno);
112         if (WIFEXITED(*status))
113                 DSS_DEBUG_LOG(("child %i exited. Exit status: %i\n", (int)*pid,
114                         WEXITSTATUS(*status)));
115         else if (WIFSIGNALED(*status))
116                 DSS_DEBUG_LOG(("child %i was killed by signal %i\n", (int)*pid,
117                         WTERMSIG(*status)));
118         else
119                 DSS_WARNING_LOG(("child %i terminated abormally\n", (int)*pid));
120         return 1;
121 }
122
123 /**
124  * Wrapper around signal(2)
125  *
126  * \param sig The number of the signal to catch.
127  *
128  * This installs the generic signal handler for the given signal.
129  *
130  * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors.
131  * \sa signal(2)
132  */
133 int install_sighandler(int sig)
134 {
135         DSS_DEBUG_LOG(("catching signal %d\n", sig));
136         if (signal(sig, &generic_signal_handler) != SIG_ERR)
137                 return 1;
138         return -E_SIGNAL_SIG_ERR;
139 }
140
141 /**
142  * Return number of next pending signal.
143  *
144  * This should be called if the fd for the signal pipe is ready for reading.
145  *
146  * \return On success, the number of the received signal is returned.
147  * If the read was interrupted by another signal the function returns 0.
148  * Otherwise a negative error code is returned.
149  */
150 int next_signal(void)
151 {
152         int s, err;
153         ssize_t r;
154
155         r = read(signal_pipe[0], &s, sizeof(s));
156         if (r == sizeof(s)) {
157                 DSS_DEBUG_LOG(("next signal: %d\n", s));
158                 return s;
159         }
160         err = errno;
161         assert(r < 0);
162         if (err == EAGAIN)
163                 return 0;
164         DSS_ERROR_LOG(("failed to read from signal pipe\n"));
165         return -ERRNO_TO_DSS_ERROR(err);
166 }
167
168 /**
169  * Close the signal pipe.
170  */
171 void signal_shutdown(void)
172 {
173         close(signal_pipe[1]);
174 }