snap.h: Fix HSA_ITEM.
[dss.git] / signal.c
1 /*
2  * Copyright (C) 2004-2010 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6 /** \file signal.c Signal handling functions. */
7
8 #include <string.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <dirent.h>
14 #include <assert.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <sys/select.h>
20
21
22 #include "gcc-compat.h"
23 #include "error.h"
24 #include "log.h"
25 #include "string.h"
26 #include "fd.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 /*
68  * just write one integer to signal pipe
69  */
70 static void generic_signal_handler(int s)
71 {
72         write(signal_pipe[1], &s, sizeof(int));
73         //fprintf(stderr, "got sig %i\n", s);
74 }
75
76 /**
77  * Reap one child.
78  *
79  * \param pid In case a child died, its pid is returned here.
80  *
81  * Call waitpid() and print a log message containing the pid and the cause of
82  * the child's death.
83  *
84  * \return A (negative) error code on errors, zero, if no child died, one
85  * otherwise. If and only if the function returns one, the content of \a pid is
86  * meaningful.
87  *
88  * \sa waitpid(2)
89  */
90 int reap_child(pid_t *pid, int *status)
91 {
92         *pid = waitpid(-1, status, WNOHANG);
93
94         if (!*pid)
95                 return 0;
96         if (*pid < 0)
97                 return -ERRNO_TO_DSS_ERROR(errno);
98         if (WIFEXITED(*status))
99                 DSS_DEBUG_LOG("child %i exited. Exit status: %i\n", (int)*pid,
100                         WEXITSTATUS(*status));
101         else if (WIFSIGNALED(*status))
102                 DSS_DEBUG_LOG("child %i was killed by signal %i\n", (int)*pid,
103                         WTERMSIG(*status));
104         else
105                 DSS_WARNING_LOG("child %i terminated abormally\n", (int)*pid);
106         return 1;
107 }
108
109 /**
110  * Wrapper around signal(2)
111  *
112  * \param sig The number of the signal to catch.
113  *
114  * This installs the generic signal handler for the given signal.
115  *
116  * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors.
117  * \sa signal(2)
118  */
119 int install_sighandler(int sig)
120 {
121         DSS_DEBUG_LOG("catching signal %d\n", sig);
122         if (signal(sig, &generic_signal_handler) != SIG_ERR)
123                 return 1;
124         return -E_SIGNAL_SIG_ERR;
125 }
126
127 /**
128  * Return number of next pending signal.
129  *
130  * This should be called if the fd for the signal pipe is ready for reading.
131  *
132  * \return On success, the number of the received signal is returned.
133  * If the read was interrupted by another signal the function returns 0.
134  * Otherwise a negative error code is returned.
135  */
136 int next_signal(void)
137 {
138         int s, err;
139         ssize_t r;
140
141         r = read(signal_pipe[0], &s, sizeof(s));
142         if (r == sizeof(s)) {
143                 DSS_DEBUG_LOG("next signal: %d\n", s);
144                 return s;
145         }
146         err = errno;
147         assert(r < 0);
148         if (err == EAGAIN)
149                 return 0;
150         DSS_ERROR_LOG("failed to read from signal pipe\n");
151         return -ERRNO_TO_DSS_ERROR(err);
152 }
153
154 /**
155  * Close the signal pipe.
156  */
157 void signal_shutdown(void)
158 {
159         close(signal_pipe[1]);
160 }