]> code.delx.au - pulseaudio/blob - src/pulse/mainloop-signal.c
volume: Increase PA_SW_VOLUME_SNPRINT_DB_MAX
[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
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 static void signal_handler(int sig) {
67 int saved_errno;
68
69 saved_errno = errno;
70
71 #ifndef HAVE_SIGACTION
72 signal(sig, signal_handler);
73 #endif
74
75 /* XXX: If writing fails, there's nothing we can do? */
76 (void) pa_write(signal_pipe[1], &sig, sizeof(sig), NULL);
77
78 errno = saved_errno;
79 }
80
81 static void dispatch(pa_mainloop_api*a, int sig) {
82 pa_signal_event *s;
83
84 for (s = signals; s; s = s->next)
85 if (s->sig == sig) {
86 pa_assert(s->callback);
87 s->callback(a, s, sig, s->userdata);
88 break;
89 }
90 }
91
92 static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) {
93 ssize_t r;
94 int sig;
95
96 pa_assert(a);
97 pa_assert(e);
98 pa_assert(f == PA_IO_EVENT_INPUT);
99 pa_assert(e == io_event);
100 pa_assert(fd == signal_pipe[0]);
101
102 if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) {
103 if (errno == EAGAIN)
104 return;
105
106 pa_log("read(): %s", pa_cstrerror(errno));
107 return;
108 }
109
110 if (r != sizeof(sig)) {
111 pa_log("short read()");
112 return;
113 }
114
115 dispatch(a, sig);
116 }
117
118 int pa_signal_init(pa_mainloop_api *a) {
119
120 pa_assert(a);
121 pa_assert(!api);
122 pa_assert(signal_pipe[0] == -1);
123 pa_assert(signal_pipe[1] == -1);
124 pa_assert(!io_event);
125
126 if (pa_pipe_cloexec(signal_pipe) < 0) {
127 pa_log("pipe(): %s", pa_cstrerror(errno));
128 return -1;
129 }
130
131 pa_make_fd_nonblock(signal_pipe[0]);
132 pa_make_fd_nonblock(signal_pipe[1]);
133
134 api = a;
135
136 pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL));
137
138 return 0;
139 }
140
141 void pa_signal_done(void) {
142 while (signals)
143 pa_signal_free(signals);
144
145 if (io_event) {
146 pa_assert(api);
147 api->io_free(io_event);
148 io_event = NULL;
149 }
150
151 pa_close_pipe(signal_pipe);
152
153 api = NULL;
154 }
155
156 pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) {
157 pa_signal_event *e = NULL;
158
159 #ifdef HAVE_SIGACTION
160 struct sigaction sa;
161 #endif
162
163 pa_assert(sig > 0);
164 pa_assert(_callback);
165
166 pa_init_i18n();
167
168 for (e = signals; e; e = e->next)
169 if (e->sig == sig)
170 return NULL;
171
172 e = pa_xnew(pa_signal_event, 1);
173 e->sig = sig;
174 e->callback = _callback;
175 e->userdata = userdata;
176 e->destroy_callback = NULL;
177
178 #ifdef HAVE_SIGACTION
179 memset(&sa, 0, sizeof(sa));
180 sa.sa_handler = signal_handler;
181 sigemptyset(&sa.sa_mask);
182 sa.sa_flags = SA_RESTART;
183
184 if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
185 #else
186 if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
187 #endif
188 goto fail;
189
190 e->previous = NULL;
191 e->next = signals;
192 signals = e;
193
194 return e;
195 fail:
196 pa_xfree(e);
197 return NULL;
198 }
199
200 void pa_signal_free(pa_signal_event *e) {
201 pa_assert(e);
202
203 if (e->next)
204 e->next->previous = e->previous;
205 if (e->previous)
206 e->previous->next = e->next;
207 else
208 signals = e->next;
209
210 #ifdef HAVE_SIGACTION
211 pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0);
212 #else
213 pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler);
214 #endif
215
216 if (e->destroy_callback)
217 e->destroy_callback(api, e, e->userdata);
218
219 pa_xfree(e);
220 }
221
222 void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) {
223 pa_assert(e);
224
225 e->destroy_callback = _callback;
226 }