]> code.delx.au - pulseaudio/blob - src/pulse/mainloop-signal.c
libpulse: add new error code PA_ERR_BUSY
[pulseaudio] / src / pulse / mainloop-signal.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.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 <pulse/xmalloc.h>
40 #include <pulse/gccmacro.h>
41 #include <pulse/i18n.h>
42
43 #include <pulsecore/core-error.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/macro.h>
47
48 #include "mainloop-signal.h"
49
50 struct pa_signal_event {
51 int sig;
52 #ifdef HAVE_SIGACTION
53 struct sigaction saved_sigaction;
54 #else
55 void (*saved_handler)(int sig);
56 #endif
57 void *userdata;
58 pa_signal_cb_t callback;
59 pa_signal_destroy_cb_t destroy_callback;
60 pa_signal_event *previous, *next;
61 };
62
63 static pa_mainloop_api *api = NULL;
64 static int signal_pipe[2] = { -1, -1 };
65 static pa_io_event* io_event = NULL;
66 static pa_signal_event *signals = NULL;
67
68 static void signal_handler(int sig) {
69 int saved_errno;
70
71 saved_errno = errno;
72
73 #ifndef HAVE_SIGACTION
74 signal(sig, signal_handler);
75 #endif
76
77 pa_write(signal_pipe[1], &sig, sizeof(sig), NULL);
78
79 errno = saved_errno;
80 }
81
82 static void dispatch(pa_mainloop_api*a, int sig) {
83 pa_signal_event *s;
84
85 for (s = signals; s; s = s->next)
86 if (s->sig == sig) {
87 pa_assert(s->callback);
88 s->callback(a, s, sig, s->userdata);
89 break;
90 }
91 }
92
93 static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) {
94 ssize_t r;
95 int sig;
96
97 pa_assert(a);
98 pa_assert(e);
99 pa_assert(f == PA_IO_EVENT_INPUT);
100 pa_assert(e == io_event);
101 pa_assert(fd == signal_pipe[0]);
102
103 if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) {
104 if (errno == EAGAIN)
105 return;
106
107 pa_log("read(): %s", pa_cstrerror(errno));
108 return;
109 }
110
111 if (r != sizeof(sig)) {
112 pa_log("short read()");
113 return;
114 }
115
116 dispatch(a, sig);
117 }
118
119 int pa_signal_init(pa_mainloop_api *a) {
120
121 pa_assert(a);
122 pa_assert(!api);
123 pa_assert(signal_pipe[0] == -1);
124 pa_assert(signal_pipe[1] == -1);
125 pa_assert(!io_event);
126
127 if (pipe(signal_pipe) < 0) {
128 pa_log("pipe(): %s", pa_cstrerror(errno));
129 return -1;
130 }
131
132 pa_make_fd_nonblock(signal_pipe[0]);
133 pa_make_fd_nonblock(signal_pipe[1]);
134 pa_make_fd_cloexec(signal_pipe[0]);
135 pa_make_fd_cloexec(signal_pipe[1]);
136
137 api = a;
138
139 pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL));
140
141 return 0;
142 }
143
144 void pa_signal_done(void) {
145 while (signals)
146 pa_signal_free(signals);
147
148 if (io_event) {
149 pa_assert(api);
150 api->io_free(io_event);
151 io_event = NULL;
152 }
153
154 pa_close_pipe(signal_pipe);
155
156 api = NULL;
157 }
158
159 pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) {
160 pa_signal_event *e = NULL;
161
162 #ifdef HAVE_SIGACTION
163 struct sigaction sa;
164 #endif
165
166 pa_assert(sig > 0);
167 pa_assert(_callback);
168
169 pa_init_i18n();
170
171 for (e = signals; e; e = e->next)
172 if (e->sig == sig)
173 return NULL;
174
175 e = pa_xnew(pa_signal_event, 1);
176 e->sig = sig;
177 e->callback = _callback;
178 e->userdata = userdata;
179 e->destroy_callback = NULL;
180
181 #ifdef HAVE_SIGACTION
182 memset(&sa, 0, sizeof(sa));
183 sa.sa_handler = signal_handler;
184 sigemptyset(&sa.sa_mask);
185 sa.sa_flags = SA_RESTART;
186
187 if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
188 #else
189 if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
190 #endif
191 goto fail;
192
193 e->previous = NULL;
194 e->next = signals;
195 signals = e;
196
197 return e;
198 fail:
199 pa_xfree(e);
200 return NULL;
201 }
202
203 void pa_signal_free(pa_signal_event *e) {
204 pa_assert(e);
205
206 if (e->next)
207 e->next->previous = e->previous;
208 if (e->previous)
209 e->previous->next = e->next;
210 else
211 signals = e->next;
212
213 #ifdef HAVE_SIGACTION
214 pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0);
215 #else
216 pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler);
217 #endif
218
219 if (e->destroy_callback)
220 e->destroy_callback(api, e, e->userdata);
221
222 pa_xfree(e);
223 }
224
225 void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) {
226 pa_assert(e);
227
228 e->destroy_callback = _callback;
229 }