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