153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2008 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdio.h> 2653a5a1b3Sopenharmony_ci#include <signal.h> 2753a5a1b3Sopenharmony_ci#include <errno.h> 2853a5a1b3Sopenharmony_ci#include <stdlib.h> 2953a5a1b3Sopenharmony_ci#include <string.h> 3053a5a1b3Sopenharmony_ci#include <unistd.h> 3153a5a1b3Sopenharmony_ci 3253a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H 3353a5a1b3Sopenharmony_ci#include <windows.h> 3453a5a1b3Sopenharmony_ci#endif 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 3953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 4053a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h> 4153a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 4253a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci#include "mainloop-signal.h" 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_cistruct pa_signal_event { 4753a5a1b3Sopenharmony_ci int sig; 4853a5a1b3Sopenharmony_ci#ifdef HAVE_SIGACTION 4953a5a1b3Sopenharmony_ci struct sigaction saved_sigaction; 5053a5a1b3Sopenharmony_ci#else 5153a5a1b3Sopenharmony_ci void (*saved_handler)(int sig); 5253a5a1b3Sopenharmony_ci#endif 5353a5a1b3Sopenharmony_ci void *userdata; 5453a5a1b3Sopenharmony_ci pa_signal_cb_t callback; 5553a5a1b3Sopenharmony_ci pa_signal_destroy_cb_t destroy_callback; 5653a5a1b3Sopenharmony_ci pa_signal_event *previous, *next; 5753a5a1b3Sopenharmony_ci}; 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_cistatic pa_mainloop_api *api = NULL; 6053a5a1b3Sopenharmony_cistatic int signal_pipe[2] = { -1, -1 }; 6153a5a1b3Sopenharmony_cistatic pa_io_event* io_event = NULL; 6253a5a1b3Sopenharmony_cistatic pa_signal_event *signals = NULL; 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_cistatic void signal_handler(int sig) { 6553a5a1b3Sopenharmony_ci int saved_errno; 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ci saved_errno = errno; 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci#ifndef HAVE_SIGACTION 7053a5a1b3Sopenharmony_ci signal(sig, signal_handler); 7153a5a1b3Sopenharmony_ci#endif 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci /* XXX: If writing fails, there's nothing we can do? */ 7453a5a1b3Sopenharmony_ci (void) pa_write(signal_pipe[1], &sig, sizeof(sig), NULL); 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci errno = saved_errno; 7753a5a1b3Sopenharmony_ci} 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_cistatic void dispatch(pa_mainloop_api*a, int sig) { 8053a5a1b3Sopenharmony_ci pa_signal_event *s; 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci for (s = signals; s; s = s->next) 8353a5a1b3Sopenharmony_ci if (s->sig == sig) { 8453a5a1b3Sopenharmony_ci pa_assert(s->callback); 8553a5a1b3Sopenharmony_ci s->callback(a, s, sig, s->userdata); 8653a5a1b3Sopenharmony_ci break; 8753a5a1b3Sopenharmony_ci } 8853a5a1b3Sopenharmony_ci} 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_cistatic void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) { 9153a5a1b3Sopenharmony_ci ssize_t r; 9253a5a1b3Sopenharmony_ci int sig; 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_ci pa_assert(a); 9553a5a1b3Sopenharmony_ci pa_assert(e); 9653a5a1b3Sopenharmony_ci pa_assert(f == PA_IO_EVENT_INPUT); 9753a5a1b3Sopenharmony_ci pa_assert(e == io_event); 9853a5a1b3Sopenharmony_ci pa_assert(fd == signal_pipe[0]); 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) { 10153a5a1b3Sopenharmony_ci if (errno == EAGAIN) 10253a5a1b3Sopenharmony_ci return; 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci pa_log("read(): %s", pa_cstrerror(errno)); 10553a5a1b3Sopenharmony_ci return; 10653a5a1b3Sopenharmony_ci } 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci if (r != sizeof(sig)) { 10953a5a1b3Sopenharmony_ci pa_log("short read()"); 11053a5a1b3Sopenharmony_ci return; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci dispatch(a, sig); 11453a5a1b3Sopenharmony_ci} 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ciint pa_signal_init(pa_mainloop_api *a) { 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci pa_assert(a); 11953a5a1b3Sopenharmony_ci pa_assert(!api); 12053a5a1b3Sopenharmony_ci pa_assert(signal_pipe[0] == -1); 12153a5a1b3Sopenharmony_ci pa_assert(signal_pipe[1] == -1); 12253a5a1b3Sopenharmony_ci pa_assert(!io_event); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci if (pa_pipe_cloexec(signal_pipe) < 0) { 12553a5a1b3Sopenharmony_ci pa_log("pipe(): %s", pa_cstrerror(errno)); 12653a5a1b3Sopenharmony_ci return -1; 12753a5a1b3Sopenharmony_ci } 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci pa_make_fd_nonblock(signal_pipe[0]); 13053a5a1b3Sopenharmony_ci pa_make_fd_nonblock(signal_pipe[1]); 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci api = a; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL)); 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci return 0; 13753a5a1b3Sopenharmony_ci} 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_civoid pa_signal_done(void) { 14053a5a1b3Sopenharmony_ci while (signals) 14153a5a1b3Sopenharmony_ci pa_signal_free(signals); 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci if (io_event) { 14453a5a1b3Sopenharmony_ci pa_assert(api); 14553a5a1b3Sopenharmony_ci api->io_free(io_event); 14653a5a1b3Sopenharmony_ci io_event = NULL; 14753a5a1b3Sopenharmony_ci } 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci pa_close_pipe(signal_pipe); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci api = NULL; 15253a5a1b3Sopenharmony_ci} 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_cipa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) { 15553a5a1b3Sopenharmony_ci pa_signal_event *e = NULL; 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci#ifdef HAVE_SIGACTION 15853a5a1b3Sopenharmony_ci struct sigaction sa; 15953a5a1b3Sopenharmony_ci#endif 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci pa_assert(sig > 0); 16253a5a1b3Sopenharmony_ci pa_assert(_callback); 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci pa_init_i18n(); 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci for (e = signals; e; e = e->next) 16753a5a1b3Sopenharmony_ci if (e->sig == sig) 16853a5a1b3Sopenharmony_ci return NULL; 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci e = pa_xnew(pa_signal_event, 1); 17153a5a1b3Sopenharmony_ci e->sig = sig; 17253a5a1b3Sopenharmony_ci e->callback = _callback; 17353a5a1b3Sopenharmony_ci e->userdata = userdata; 17453a5a1b3Sopenharmony_ci e->destroy_callback = NULL; 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci#ifdef HAVE_SIGACTION 17753a5a1b3Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 17853a5a1b3Sopenharmony_ci sa.sa_handler = signal_handler; 17953a5a1b3Sopenharmony_ci sigemptyset(&sa.sa_mask); 18053a5a1b3Sopenharmony_ci sa.sa_flags = SA_RESTART; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci if (sigaction(sig, &sa, &e->saved_sigaction) < 0) 18353a5a1b3Sopenharmony_ci#else 18453a5a1b3Sopenharmony_ci if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) 18553a5a1b3Sopenharmony_ci#endif 18653a5a1b3Sopenharmony_ci goto fail; 18753a5a1b3Sopenharmony_ci 18853a5a1b3Sopenharmony_ci e->previous = NULL; 18953a5a1b3Sopenharmony_ci e->next = signals; 19053a5a1b3Sopenharmony_ci signals = e; 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci return e; 19353a5a1b3Sopenharmony_cifail: 19453a5a1b3Sopenharmony_ci pa_xfree(e); 19553a5a1b3Sopenharmony_ci return NULL; 19653a5a1b3Sopenharmony_ci} 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_civoid pa_signal_free(pa_signal_event *e) { 19953a5a1b3Sopenharmony_ci pa_assert(e); 20053a5a1b3Sopenharmony_ci 20153a5a1b3Sopenharmony_ci if (e->next) 20253a5a1b3Sopenharmony_ci e->next->previous = e->previous; 20353a5a1b3Sopenharmony_ci if (e->previous) 20453a5a1b3Sopenharmony_ci e->previous->next = e->next; 20553a5a1b3Sopenharmony_ci else 20653a5a1b3Sopenharmony_ci signals = e->next; 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci#ifdef HAVE_SIGACTION 20953a5a1b3Sopenharmony_ci pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0); 21053a5a1b3Sopenharmony_ci#else 21153a5a1b3Sopenharmony_ci pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler); 21253a5a1b3Sopenharmony_ci#endif 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci if (e->destroy_callback) 21553a5a1b3Sopenharmony_ci e->destroy_callback(api, e, e->userdata); 21653a5a1b3Sopenharmony_ci 21753a5a1b3Sopenharmony_ci pa_xfree(e); 21853a5a1b3Sopenharmony_ci} 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_civoid pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) { 22153a5a1b3Sopenharmony_ci pa_assert(e); 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci e->destroy_callback = _callback; 22453a5a1b3Sopenharmony_ci} 225