Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / common / filter.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 <assert.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/socket.h>
24 #include <unistd.h>
25
26 #include "private.h"
27
28 extern const struct filter evfilt_read;
29 extern const struct filter evfilt_write;
30 extern const struct filter evfilt_signal;
31 extern const struct filter evfilt_vnode;
32 extern const struct filter evfilt_proc;
33 extern const struct filter evfilt_timer;
34 extern const struct filter evfilt_user;
35
36 static int
37 filter_register(struct kqueue *kq, short filter, const struct filter *src)
38 {
39     struct filter *dst;
40     unsigned int filt;
41     int rv = 0;
42
43     filt = (-1 * filter) - 1;
44     if (filt >= EVFILT_SYSCOUNT) 
45         return (-1);
46
47     dst = &kq->kq_filt[filt];
48     memcpy(dst, src, sizeof(*src));
49     dst->kf_kqueue = kq;
50     RB_INIT(&dst->kf_knote);
51     TAILQ_INIT(&dst->kf_event);
52     if (src->kf_id == 0) {
53         dbg_puts("filter is not implemented");
54         return (0);
55     }
56
57     assert(src->kf_init);
58     assert(src->kf_destroy);
59     assert(src->kf_copyout);
60     assert(src->kn_create);
61     assert(src->kn_modify);
62     assert(src->kn_delete);
63     assert(src->kn_enable);
64     assert(src->kn_disable);
65
66     rv = src->kf_init(dst);
67     if (rv < 0) {
68         dbg_puts("filter failed to initialize");
69         dst->kf_id = 0;
70         return (-1);
71     }
72
73     /* Add the filter's event descriptor to the main fdset */
74     if (dst->kf_pfd > 0) {
75         FD_SET(dst->kf_pfd, &kq->kq_fds);
76         if (dst->kf_pfd > kq->kq_nfds)  
77             kq->kq_nfds = dst->kf_pfd;
78         dbg_printf("fds: added %d (nfds=%d)", dst->kf_pfd, kq->kq_nfds);
79     }
80     dbg_printf("filter %d (%s) registered", filter, filter_name(filter));
81
82     return (0);
83 }
84
85 int
86 filter_register_all(struct kqueue *kq)
87 {
88     int rv;
89
90     FD_ZERO(&kq->kq_fds);
91     rv = 0;
92     rv += filter_register(kq, EVFILT_READ, &evfilt_read);
93     rv += filter_register(kq, EVFILT_WRITE, &evfilt_write);
94     rv += filter_register(kq, EVFILT_SIGNAL, &evfilt_signal);
95     rv += filter_register(kq, EVFILT_VNODE, &evfilt_vnode);
96     rv += filter_register(kq, EVFILT_PROC, &evfilt_proc);
97     rv += filter_register(kq, EVFILT_TIMER, &evfilt_timer);
98     rv += filter_register(kq, EVFILT_USER, &evfilt_user);
99     kq->kq_nfds++;
100     if (rv != 0) {
101         filter_unregister_all(kq);
102         return (-1);
103     } else {
104         return (0);
105     }
106 }
107
108 void
109 filter_unregister_all(struct kqueue *kq)
110 {
111     int i;
112
113     for (i = 0; i < EVFILT_SYSCOUNT; i++) {
114         if (kq->kq_filt[i].kf_id == 0)
115             continue;
116
117         if (kq->kq_filt[i].kf_destroy != NULL) 
118             kq->kq_filt[i].kf_destroy(&kq->kq_filt[i]);
119
120         knote_free_all(&kq->kq_filt[i]);
121     }
122     memset(&kq->kq_filt[0], 0, sizeof(kq->kq_filt));
123 }
124
125 int 
126 filter_socketpair(struct filter *filt)
127 {
128     int sockfd[2];
129
130     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
131         return (-1);
132
133     fcntl(sockfd[0], F_SETFL, O_NONBLOCK);
134     filt->kf_wfd = sockfd[0];
135     filt->kf_pfd = sockfd[1];
136     return (0);
137
138
139 int
140 filter_lookup(struct filter **filt, struct kqueue *kq, short id)
141 {
142     if (~id < 0 || ~id >= EVFILT_SYSCOUNT) {
143         dbg_printf("invalid id: id %d ~id %d", id, (~id));
144         errno = EINVAL;
145         *filt = NULL;
146         return (-1);
147     }
148     *filt = &kq->kq_filt[~id];
149     if ((*filt)->kf_copyout == NULL) {
150         errno = ENOSYS;
151         *filt = NULL;
152         return (-1);
153     }
154
155     return (0);
156 }
157
158 const char *
159 filter_name(short filt)
160 {
161     unsigned int id;
162     const char *fname[EVFILT_SYSCOUNT] = {
163         "EVFILT_READ",
164         "EVFILT_WRITE",
165         "EVFILT_AIO", 
166         "EVFILT_VNODE",
167         "EVFILT_PROC",
168         "EVFILT_SIGNAL", 
169         "EVFILT_TIMER", 
170         "EVFILT_NETDEV", 
171         "EVFILT_FS",    
172         "EVFILT_LIO",  
173         "EVFILT_USER"
174     };
175
176     id = ~filt;
177     if (id < 0 || id >= EVFILT_SYSCOUNT)
178         return "EVFILT_INVALID";
179     else
180         return fname[id];
181 }
182
183 int
184 filter_raise(struct filter *filt)
185 {
186     for (;;) {
187         if (write(filt->kf_wfd, " ", 1) < 0) {
188             if (errno == EINTR) 
189                 continue;
190
191             if (errno != EAGAIN) {
192                 dbg_printf("write(2): %s", strerror(errno));
193                 /* TODO: set filter error flag */
194                 return (-1);
195             }
196         }
197         break;
198     }
199
200     return (0);
201 }
202
203 int
204 filter_lower(struct filter *filt)
205 {
206     char buf[1024];
207     ssize_t n;
208
209     for (;;) {
210         n = read(filt->kf_pfd, &buf, sizeof(buf));
211         if (n < 0) {
212             if (errno == EINTR) 
213                 continue;
214             if (errno == EAGAIN) 
215                 break;
216
217             dbg_printf("read(2): %s", strerror(errno));
218             return (-1);
219         }
220         break;
221     }
222
223     return (0);
224 }