1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2008 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #ifdef HAVE_WINDOWS_H
33 #include <windows.h>
34 #endif
35
36 #include <pulse/xmalloc.h>
37
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/i18n.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/macro.h>
43
44 #include "mainloop-signal.h"
45
46 struct pa_signal_event {
47 int sig;
48 #ifdef HAVE_SIGACTION
49 struct sigaction saved_sigaction;
50 #else
51 void (*saved_handler)(int sig);
52 #endif
53 void *userdata;
54 pa_signal_cb_t callback;
55 pa_signal_destroy_cb_t destroy_callback;
56 pa_signal_event *previous, *next;
57 };
58
59 static pa_mainloop_api *api = NULL;
60 static int signal_pipe[2] = { -1, -1 };
61 static pa_io_event* io_event = NULL;
62 static pa_signal_event *signals = NULL;
63
signal_handler(int sig)64 static void signal_handler(int sig) {
65 int saved_errno;
66
67 saved_errno = errno;
68
69 #ifndef HAVE_SIGACTION
70 signal(sig, signal_handler);
71 #endif
72
73 /* XXX: If writing fails, there's nothing we can do? */
74 (void) pa_write(signal_pipe[1], &sig, sizeof(sig), NULL);
75
76 errno = saved_errno;
77 }
78
dispatch(pa_mainloop_api * a,int sig)79 static void dispatch(pa_mainloop_api*a, int sig) {
80 pa_signal_event *s;
81
82 for (s = signals; s; s = s->next)
83 if (s->sig == sig) {
84 pa_assert(s->callback);
85 s->callback(a, s, sig, s->userdata);
86 break;
87 }
88 }
89
callback(pa_mainloop_api * a,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)90 static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) {
91 ssize_t r;
92 int sig;
93
94 pa_assert(a);
95 pa_assert(e);
96 pa_assert(f == PA_IO_EVENT_INPUT);
97 pa_assert(e == io_event);
98 pa_assert(fd == signal_pipe[0]);
99
100 if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) {
101 if (errno == EAGAIN)
102 return;
103
104 pa_log("read(): %s", pa_cstrerror(errno));
105 return;
106 }
107
108 if (r != sizeof(sig)) {
109 pa_log("short read()");
110 return;
111 }
112
113 dispatch(a, sig);
114 }
115
pa_signal_init(pa_mainloop_api * a)116 int pa_signal_init(pa_mainloop_api *a) {
117
118 pa_assert(a);
119 pa_assert(!api);
120 pa_assert(signal_pipe[0] == -1);
121 pa_assert(signal_pipe[1] == -1);
122 pa_assert(!io_event);
123
124 if (pa_pipe_cloexec(signal_pipe) < 0) {
125 pa_log("pipe(): %s", pa_cstrerror(errno));
126 return -1;
127 }
128
129 pa_make_fd_nonblock(signal_pipe[0]);
130 pa_make_fd_nonblock(signal_pipe[1]);
131
132 api = a;
133
134 pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL));
135
136 return 0;
137 }
138
pa_signal_done(void)139 void pa_signal_done(void) {
140 while (signals)
141 pa_signal_free(signals);
142
143 if (io_event) {
144 pa_assert(api);
145 api->io_free(io_event);
146 io_event = NULL;
147 }
148
149 pa_close_pipe(signal_pipe);
150
151 api = NULL;
152 }
153
pa_signal_new(int sig,pa_signal_cb_t _callback,void * userdata)154 pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) {
155 pa_signal_event *e = NULL;
156
157 #ifdef HAVE_SIGACTION
158 struct sigaction sa;
159 #endif
160
161 pa_assert(sig > 0);
162 pa_assert(_callback);
163
164 pa_init_i18n();
165
166 for (e = signals; e; e = e->next)
167 if (e->sig == sig)
168 return NULL;
169
170 e = pa_xnew(pa_signal_event, 1);
171 e->sig = sig;
172 e->callback = _callback;
173 e->userdata = userdata;
174 e->destroy_callback = NULL;
175
176 #ifdef HAVE_SIGACTION
177 memset(&sa, 0, sizeof(sa));
178 sa.sa_handler = signal_handler;
179 sigemptyset(&sa.sa_mask);
180 sa.sa_flags = SA_RESTART;
181
182 if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
183 #else
184 if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
185 #endif
186 goto fail;
187
188 e->previous = NULL;
189 e->next = signals;
190 signals = e;
191
192 return e;
193 fail:
194 pa_xfree(e);
195 return NULL;
196 }
197
pa_signal_free(pa_signal_event * e)198 void pa_signal_free(pa_signal_event *e) {
199 pa_assert(e);
200
201 if (e->next)
202 e->next->previous = e->previous;
203 if (e->previous)
204 e->previous->next = e->next;
205 else
206 signals = e->next;
207
208 #ifdef HAVE_SIGACTION
209 pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0);
210 #else
211 pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler);
212 #endif
213
214 if (e->destroy_callback)
215 e->destroy_callback(api, e, e->userdata);
216
217 pa_xfree(e);
218 }
219
pa_signal_set_destroy(pa_signal_event * e,pa_signal_destroy_cb_t _callback)220 void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) {
221 pa_assert(e);
222
223 e->destroy_callback = _callback;
224 }
225