]> code.delx.au - pulseaudio/blob - src/pulse/mainloop-signal.c
use cloexec wrappers wherever applicable
[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 (pa_pipe_cloexec(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
135 api = a;
136
137 pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL));
138
139 return 0;
140 }
141
142 void pa_signal_done(void) {
143 while (signals)
144 pa_signal_free(signals);
145
146 if (io_event) {
147 pa_assert(api);
148 api->io_free(io_event);
149 io_event = NULL;
150 }
151
152 pa_close_pipe(signal_pipe);
153
154 api = NULL;
155 }
156
157 pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) {
158 pa_signal_event *e = NULL;
159
160 #ifdef HAVE_SIGACTION
161 struct sigaction sa;
162 #endif
163
164 pa_assert(sig > 0);
165 pa_assert(_callback);
166
167 pa_init_i18n();
168
169 for (e = signals; e; e = e->next)
170 if (e->sig == sig)
171 return NULL;
172
173 e = pa_xnew(pa_signal_event, 1);
174 e->sig = sig;
175 e->callback = _callback;
176 e->userdata = userdata;
177 e->destroy_callback = NULL;
178
179 #ifdef HAVE_SIGACTION
180 memset(&sa, 0, sizeof(sa));
181 sa.sa_handler = signal_handler;
182 sigemptyset(&sa.sa_mask);
183 sa.sa_flags = SA_RESTART;
184
185 if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
186 #else
187 if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
188 #endif
189 goto fail;
190
191 e->previous = NULL;
192 e->next = signals;
193 signals = e;
194
195 return e;
196 fail:
197 pa_xfree(e);
198 return NULL;
199 }
200
201 void pa_signal_free(pa_signal_event *e) {
202 pa_assert(e);
203
204 if (e->next)
205 e->next->previous = e->previous;
206 if (e->previous)
207 e->previous->next = e->next;
208 else
209 signals = e->next;
210
211 #ifdef HAVE_SIGACTION
212 pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0);
213 #else
214 pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler);
215 #endif
216
217 if (e->destroy_callback)
218 e->destroy_callback(api, e, e->userdata);
219
220 pa_xfree(e);
221 }
222
223 void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) {
224 pa_assert(e);
225
226 e->destroy_callback = _callback;
227 }