Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / posix / 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/event.h"
30 #include "private.h"
31
32 /* Highest signal number supported. POSIX standard signals are < 32 */
33 #define SIGNAL_MAX      32
34
35 struct sentry {
36     struct filter  *s_filt;
37     struct knote   *s_knote;
38     volatile uint32_t s_cnt;
39 };
40
41 static pthread_mutex_t sigtbl_mtx = PTHREAD_MUTEX_INITIALIZER;
42 static struct sentry sigtbl[SIGNAL_MAX];
43
44 static void
45 signal_handler(int sig)
46 {
47     struct sentry *s = &sigtbl[sig];
48
49     dbg_printf("caught sig=%d", sig);
50     atomic_inc(&s->s_cnt);
51 #if defined(__sun__)
52     if (port_send(s->s_filt->kf_kqueue->kq_port, 
53                    X_PORT_SOURCE_SIGNAL, &sigtbl[sig]) < 0) {
54         return; //FIXME: errorhandling
55     }
56 #else
57     (void)write(s->s_filt->kf_wfd, &sig, sizeof(sig));//FIXME:errhandling
58 #endif
59 }
60
61 static int
62 catch_signal(struct filter *filt, struct knote *kn)
63 {
64         int sig;
65         struct sigaction sa;
66     
67     sig = kn->kev.ident;
68         memset(&sa, 0, sizeof(sa));
69         sa.sa_handler = signal_handler;
70         sa.sa_flags |= SA_RESTART;
71         sigfillset(&sa.sa_mask);
72
73         if (sigaction(kn->kev.ident, &sa, NULL) == -1) {
74                 dbg_perror("sigaction");
75                 return (-1);
76         }
77     /* FIXME: will clobber previous entry, if any */
78     pthread_mutex_lock(&sigtbl_mtx);
79     sigtbl[kn->kev.ident].s_filt = filt;
80     sigtbl[kn->kev.ident].s_knote = kn;
81     pthread_mutex_unlock(&sigtbl_mtx);
82
83     dbg_printf("installed handler for signal %d", sig);
84     return (0);
85 }
86
87 static int
88 ignore_signal(int sig)
89 {
90         struct sigaction sa;
91     
92         memset(&sa, 0, sizeof(sa));
93         sa.sa_handler = SIG_IGN;
94         sigemptyset(&sa.sa_mask);
95
96         if (sigaction(sig, &sa, NULL) == -1) {
97                 dbg_perror("sigaction");
98                 return (-1);
99         }
100     pthread_mutex_lock(&sigtbl_mtx);
101     sigtbl[sig].s_filt = NULL;
102     sigtbl[sig].s_knote = NULL;
103     pthread_mutex_unlock(&sigtbl_mtx);
104
105     dbg_printf("removed handler for signal %d", sig);
106     return (0);
107 }
108
109 int
110 evfilt_signal_init(struct filter *filt)
111 {
112     return filter_socketpair(filt);
113 }
114
115 void
116 evfilt_signal_destroy(struct filter *filt)
117 {
118     close(filt->kf_pfd);
119 }
120
121 int
122 evfilt_signal_knote_create(struct filter *filt, struct knote *kn)
123 {
124     if (kn->kev.ident >= SIGNAL_MAX) {
125         dbg_printf("unsupported signal number %u", 
126                     (unsigned int) kn->kev.ident);
127         return (-1);
128     }
129
130     kn->kev.flags |= EV_CLEAR;
131
132     return catch_signal(filt, kn);
133 }
134
135 int
136 evfilt_signal_knote_modify(struct filter *filt, struct knote *kn, 
137                 const struct kevent *kev)
138 {
139     kn->kev.flags = kev->flags | EV_CLEAR;
140     return (0);
141 }
142
143 int
144 evfilt_signal_knote_delete(struct filter *filt, struct knote *kn)
145 {   
146     return ignore_signal(kn->kev.ident);
147 }
148
149 int
150 evfilt_signal_knote_enable(struct filter *filt, struct knote *kn)
151 {
152     return catch_signal(filt, kn);
153 }
154
155 int
156 evfilt_signal_knote_disable(struct filter *filt, struct knote *kn)
157 {
158     return ignore_signal(kn->kev.ident);
159 }
160
161 int
162 evfilt_signal_copyout(struct filter *filt, 
163             struct kevent *dst, 
164             int nevents)
165 {
166     struct sentry *s;
167     struct knote *kn;
168     int sig;
169
170 #if defined(__sun__)
171     port_event_t *pe = (port_event_t *) pthread_getspecific(filt->kf_kqueue->kq_port_event);
172
173     s = (struct sentry *) pe->portev_user;
174     sig = s - &sigtbl[0];
175 #else
176     read(filt->kf_pfd, &sig, sizeof(sig));//FIXME:errhandling
177     s = &sigtbl[sig];
178 #endif
179
180     kn = s->s_knote;
181     //TODO: READ counter: s->s_knote->kev.data = ?;
182     /* TODO: dst->data should be the number of times the signal occurred */
183     dst->ident = sig;
184     dst->filter = EVFILT_SIGNAL;
185     dst->udata = kn->kev.udata;
186     dst->flags = kn->kev.flags; 
187     dst->fflags = 0;
188     dst->data = 1;  
189
190     if (kn->kev.flags & EV_DISPATCH) {
191         ignore_signal(kn->kev.ident);
192         KNOTE_DISABLE(kn);
193     } else if (kn->kev.flags & EV_ONESHOT) {
194         ignore_signal(kn->kev.ident);
195         knote_free(filt, kn);
196     }
197
198     return (1);
199 }
200
201 const struct filter evfilt_signal = {
202     EVFILT_SIGNAL,
203     evfilt_signal_init,
204     evfilt_signal_destroy,
205     evfilt_signal_copyout,
206     evfilt_signal_knote_create,
207     evfilt_signal_knote_modify,
208     evfilt_signal_knote_delete,
209     evfilt_signal_knote_enable,
210     evfilt_signal_knote_disable,     
211 };