]> code.delx.au - pulseaudio/blob - src/mainloop-signal.c
some fixes
[pulseaudio] / src / mainloop-signal.c
1 #include <stdio.h>
2 #include <assert.h>
3 #include <signal.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8
9 #include "mainloop-signal.h"
10 #include "util.h"
11
12 struct signal_info {
13 int sig;
14 struct sigaction saved_sigaction;
15 void (*callback) (void *id, int signal, void *userdata);
16 void *userdata;
17 struct signal_info *previous, *next;
18 };
19
20 static struct pa_mainloop_api *api = NULL;
21 static int signal_pipe[2] = { -1, -1 };
22 static void* mainloop_source = NULL;
23 static struct signal_info *signals = NULL;
24
25 static void signal_handler(int sig) {
26 write(signal_pipe[1], &sig, sizeof(sig));
27 }
28
29 static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
30 assert(a && id && events == PA_MAINLOOP_API_IO_EVENT_INPUT && id == mainloop_source && fd == signal_pipe[0]);
31
32 for (;;) {
33 ssize_t r;
34 int sig;
35 struct signal_info*s;
36
37 if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
38 if (errno == EAGAIN)
39 return;
40
41 fprintf(stderr, "signal.c: read(): %s\n", strerror(errno));
42 return;
43 }
44
45 if (r != sizeof(sig)) {
46 fprintf(stderr, "signal.c: short read()\n");
47 return;
48 }
49
50 for (s = signals; s; s = s->next)
51 if (s->sig == sig) {
52 assert(s->callback);
53 s->callback(s, sig, s->userdata);
54 break;
55 }
56 }
57 }
58
59 int pa_signal_init(struct pa_mainloop_api *a) {
60 assert(a);
61 if (pipe(signal_pipe) < 0) {
62 fprintf(stderr, "pipe() failed: %s\n", strerror(errno));
63 return -1;
64 }
65
66 make_nonblock_fd(signal_pipe[0]);
67 make_nonblock_fd(signal_pipe[1]);
68
69 api = a;
70 mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL);
71 assert(mainloop_source);
72 return 0;
73 }
74
75 void pa_signal_done(void) {
76 assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && mainloop_source);
77
78 api->cancel_io(api, mainloop_source);
79 mainloop_source = NULL;
80
81 close(signal_pipe[0]);
82 close(signal_pipe[1]);
83 signal_pipe[0] = signal_pipe[1] = -1;
84
85 while (signals)
86 pa_signal_unregister(signals);
87
88 api = NULL;
89 }
90
91 void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void *userdata), void *userdata) {
92 struct signal_info *s = NULL;
93 struct sigaction sa;
94 assert(sig > 0 && callback);
95
96 for (s = signals; s; s = s->next)
97 if (s->sig == sig)
98 goto fail;
99
100 s = malloc(sizeof(struct signal_info));
101 assert(s);
102 s->sig = sig;
103 s->callback = callback;
104 s->userdata = userdata;
105
106 memset(&sa, 0, sizeof(sa));
107 sa.sa_handler = signal_handler;
108 sigemptyset(&sa.sa_mask);
109 sa.sa_flags = SA_RESTART;
110
111 if (sigaction(sig, &sa, &s->saved_sigaction) < 0)
112 goto fail;
113
114 s->previous = NULL;
115 s->next = signals;
116 signals = s;
117
118 return s;
119 fail:
120 if (s)
121 free(s);
122 return NULL;
123 }
124
125 void pa_signal_unregister(void *id) {
126 struct signal_info *s = id;
127 assert(s);
128
129 if (s->next)
130 s->next->previous = s->previous;
131 if (s->previous)
132 s->previous->next = s->next;
133 else
134 signals = s->next;
135
136 sigaction(s->sig, &s->saved_sigaction, NULL);
137 free(s);
138 }