]> code.delx.au - pulseaudio/blob - src/polyp/mainloop-signal.c
don't allow channel positions to be specified twice in the same channelmap
[pulseaudio] / src / polyp / mainloop-signal.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34
35 #ifdef HAVE_WINDOWS_H
36 #include <windows.h>
37 #endif
38
39 #include <polypcore/util.h>
40 #include <polypcore/xmalloc.h>
41 #include <polypcore/log.h>
42 #include <polypcore/gccmacro.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 (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata);
54 void *userdata;
55 void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata);
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_time_event *time_event = NULL;
63 static pa_signal_event *signals = NULL;
64
65 #ifdef OS_IS_WIN32
66 static unsigned int waiting_signals = 0;
67 static CRITICAL_SECTION crit;
68 #endif
69
70 static void signal_handler(int sig) {
71 #ifndef HAVE_SIGACTION
72 signal(sig, signal_handler);
73 #endif
74 write(signal_pipe[1], &sig, sizeof(sig));
75
76 #ifdef OS_IS_WIN32
77 EnterCriticalSection(&crit);
78 waiting_signals++;
79 LeaveCriticalSection(&crit);
80 #endif
81 }
82
83 static void dispatch(pa_mainloop_api*a, int sig) {
84 pa_signal_event*s;
85
86 for (s = signals; s; s = s->next)
87 if (s->sig == sig) {
88 assert(s->callback);
89 s->callback(a, s, sig, s->userdata);
90 break;
91 }
92 }
93
94 #ifdef OS_IS_WIN32
95 static void timer(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, PA_GCC_UNUSED void *userdata) {
96 ssize_t r;
97 int sig;
98 unsigned int sigs;
99 struct timeval tvnext;
100
101 EnterCriticalSection(&crit);
102 sigs = waiting_signals;
103 waiting_signals = 0;
104 LeaveCriticalSection(&crit);
105
106 while (sigs) {
107 if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
108 pa_log(__FILE__": read(): %s", strerror(errno));
109 return;
110 }
111
112 if (r != sizeof(sig)) {
113 pa_log(__FILE__": short read()");
114 return;
115 }
116
117 dispatch(a, sig);
118
119 sigs--;
120 }
121
122 pa_timeval_add(pa_gettimeofday(&tvnext), 100000);
123 a->time_restart(e, &tvnext);
124 }
125 #endif
126
127 static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) {
128 ssize_t r;
129 int sig;
130 assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
131
132
133 if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
134 if (errno == EAGAIN)
135 return;
136
137 pa_log(__FILE__": read(): %s", strerror(errno));
138 return;
139 }
140
141 if (r != sizeof(sig)) {
142 pa_log(__FILE__": short read()");
143 return;
144 }
145
146 dispatch(a, sig);
147 }
148
149 int pa_signal_init(pa_mainloop_api *a) {
150 #ifdef OS_IS_WIN32
151 struct timeval tv;
152 #endif
153
154 assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !time_event);
155
156 #ifdef OS_IS_WIN32
157 if (_pipe(signal_pipe, 200, _O_BINARY) < 0) {
158 #else
159 if (pipe(signal_pipe) < 0) {
160 #endif
161 pa_log(__FILE__": pipe() failed: %s", strerror(errno));
162 return -1;
163 }
164
165 pa_make_nonblock_fd(signal_pipe[0]);
166 pa_make_nonblock_fd(signal_pipe[1]);
167 pa_fd_set_cloexec(signal_pipe[0], 1);
168 pa_fd_set_cloexec(signal_pipe[1], 1);
169
170 api = a;
171
172 #ifndef OS_IS_WIN32
173 io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
174 assert(io_event);
175 #else
176 time_event = api->time_new(api, pa_gettimeofday(&tv), timer, NULL);
177 assert(time_event);
178
179 InitializeCriticalSection(&crit);
180 #endif
181
182 return 0;
183 }
184
185 void pa_signal_done(void) {
186 assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || time_event));
187
188 while (signals)
189 pa_signal_free(signals);
190
191 #ifndef OS_IS_WIN32
192 api->io_free(io_event);
193 io_event = NULL;
194 #else
195 api->time_free(time_event);
196 time_event = NULL;
197
198 DeleteCriticalSection(&crit);
199 #endif
200
201 close(signal_pipe[0]);
202 close(signal_pipe[1]);
203 signal_pipe[0] = signal_pipe[1] = -1;
204
205 api = NULL;
206 }
207
208 pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) {
209 pa_signal_event *e = NULL;
210
211 #ifdef HAVE_SIGACTION
212 struct sigaction sa;
213 #endif
214
215 assert(sig > 0 && _callback);
216
217 for (e = signals; e; e = e->next)
218 if (e->sig == sig)
219 goto fail;
220
221 e = pa_xmalloc(sizeof(pa_signal_event));
222 e->sig = sig;
223 e->callback = _callback;
224 e->userdata = userdata;
225 e->destroy_callback = NULL;
226
227 #ifdef HAVE_SIGACTION
228 memset(&sa, 0, sizeof(sa));
229 sa.sa_handler = signal_handler;
230 sigemptyset(&sa.sa_mask);
231 sa.sa_flags = SA_RESTART;
232
233 if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
234 #else
235 if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
236 #endif
237 goto fail;
238
239 e->previous = NULL;
240 e->next = signals;
241 signals = e;
242
243 return e;
244 fail:
245 if (e)
246 pa_xfree(e);
247 return NULL;
248 }
249
250 void pa_signal_free(pa_signal_event *e) {
251 assert(e);
252
253 if (e->next)
254 e->next->previous = e->previous;
255 if (e->previous)
256 e->previous->next = e->next;
257 else
258 signals = e->next;
259
260 #ifdef HAVE_SIGACTION
261 sigaction(e->sig, &e->saved_sigaction, NULL);
262 #else
263 signal(e->sig, e->saved_handler);
264 #endif
265
266 if (e->destroy_callback)
267 e->destroy_callback(api, e, e->userdata);
268
269 pa_xfree(e);
270 }
271
272 void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) {
273 assert(e);
274 e->destroy_callback = _callback;
275 }