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