Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / linux / signal.c
1 /*
2  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <sys/signalfd.h>
30
31 #include "sys/event.h"
32 #include "private.h"
33
34 /* Highest signal number supported. POSIX standard signals are < 32 */
35 #define SIGNAL_MAX      32
36
37 static int
38 update_sigmask(const struct filter *filt)
39 {
40     int rv;
41     rv = signalfd(filt->kf_pfd, &filt->kf_sigmask, 0);
42     dbg_printf("signalfd = %d", filt->kf_pfd);
43     if (rv < 0 || rv != filt->kf_pfd) {
44         dbg_printf("signalfd(2): %s", strerror(errno));
45         return (-1);
46     }
47
48     return (0);
49 }
50
51 int
52 evfilt_signal_init(struct filter *filt)
53 {
54     sigemptyset(&filt->kf_sigmask);
55     filt->kf_pfd = signalfd(-1, &filt->kf_sigmask, 0);
56     dbg_printf("signalfd = %d", filt->kf_pfd);
57     if (filt->kf_pfd < 0) 
58         return (-1);
59
60     return (0);
61 }
62
63 void
64 evfilt_signal_destroy(struct filter *filt)
65 {
66     close (filt->kf_pfd);
67 }
68
69 int
70 evfilt_signal_copyout(struct filter *filt, 
71             struct kevent *dst, 
72             int nevents)
73 {
74     struct knote *kn;
75     struct signalfd_siginfo sig[MAX_KEVENT];
76     int i;
77     ssize_t n;
78
79     n = read(filt->kf_pfd, &sig, nevents * sizeof(sig[0]));
80     if (n < 0 || n < sizeof(sig[0])) {
81         dbg_puts("invalid read from signalfd");
82         return (-1);
83     }
84     n /= sizeof(sig[0]);
85
86     for (i = 0, nevents = 0; i < n; i++) {
87         /* This is not an error because of this race condition:
88          *    1. Signal arrives and is queued
89          *    2. The kevent is deleted via kevent(..., EV_DELETE)
90          *    3. The event is dequeued from the signalfd
91          */
92         kn = knote_lookup(filt, sig[i].ssi_signo);
93         if (kn == NULL)
94             continue;
95
96         dbg_printf("got signal %d", sig[i].ssi_signo);
97         memcpy(dst, &kn->kev, sizeof(*dst));
98         /* TODO: dst->data should be the number of times the signal occurred */
99         dst->data = 1;  
100
101         if (kn->kev.flags & EV_DISPATCH || kn->kev.flags & EV_ONESHOT) {
102             sigdelset(&filt->kf_sigmask, dst->ident);
103             update_sigmask(filt); /* TODO: error checking */
104         }
105         if (kn->kev.flags & EV_DISPATCH)
106             KNOTE_DISABLE(kn);
107         if (kn->kev.flags & EV_ONESHOT) 
108             knote_free(filt, kn);
109
110         dst++; 
111         nevents++;
112     }
113
114     return (nevents);
115 }
116
117 int
118 evfilt_signal_knote_create(struct filter *filt, struct knote *kn)
119 {
120     if (kn->kev.ident >= SIGNAL_MAX) {
121         dbg_printf("bad signal number %u", (u_int) kn->kev.ident);
122         return (-1);
123     }
124
125     kn->kev.flags |= EV_CLEAR;
126     sigaddset(&filt->kf_sigmask, kn->kev.ident);
127
128     return (update_sigmask(filt));
129 }
130
131 int
132 evfilt_signal_knote_modify(struct filter *filt, struct knote *kn, 
133         const struct kevent *kev)
134 {
135     if (kev.ident >= SIGNAL_MAX) {
136         dbg_printf("bad signal number %u", (u_int) kev.ident);
137         return (-1);
138     }
139
140     /* Nothing to do since the sigmask does not change. */
141
142     return (0);
143 }
144
145 int
146 evfilt_signal_knote_delete(struct filter *filt, struct knote *kn)
147 {   
148     sigdelset(&filt->kf_sigmask, kn->kev.ident);
149
150     return (update_sigmask(filt));
151 }
152
153 int
154 evfilt_signal_knote_enable(struct filter *filt, struct knote *kn)
155 {
156     sigaddset(&filt->kf_sigmask, kn->kev.ident);
157
158     return (update_sigmask(filt));
159 }
160
161 int
162 evfilt_signal_knote_disable(struct filter *filt, struct knote *kn)
163 {
164     return (evfilt_signal_knote_delete(filt, kn));
165 }
166
167
168 const struct filter evfilt_signal = {
169     EVFILT_SIGNAL,
170     evfilt_signal_init,
171     evfilt_signal_destroy,
172     evfilt_signal_copyout,
173     evfilt_signal_knote_create,
174     evfilt_signal_knote_modify,
175     evfilt_signal_knote_delete,
176     evfilt_signal_knote_enable,
177     evfilt_signal_knote_disable,         
178 };