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