Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / common / kevent.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 /* To get asprintf(3) */
18 #define _GNU_SOURCE
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <poll.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/queue.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include "sys/event.h"
34 #include "private.h"
35
36 static char *
37 kevent_filter_dump(const struct kevent *kev)
38 {
39     static char __thread buf[64];
40
41     snprintf(&buf[0], sizeof(buf), "%d (%s)", 
42             kev->filter, filter_name(kev->filter));
43     return (&buf[0]);
44 }
45
46 static char *
47 kevent_fflags_dump(const struct kevent *kev)
48 {
49     static char __thread buf[1024];
50
51 #define KEVFFL_DUMP(attrib) \
52     if (kev->fflags & attrib) \
53     strncat(buf, #attrib" ", 64);
54
55     snprintf(buf, sizeof(buf), "fflags=0x%04x (", kev->fflags);
56     if (kev->filter == EVFILT_VNODE) {
57         KEVFFL_DUMP(NOTE_DELETE);
58         KEVFFL_DUMP(NOTE_WRITE);
59         KEVFFL_DUMP(NOTE_EXTEND);
60         KEVFFL_DUMP(NOTE_ATTRIB);
61         KEVFFL_DUMP(NOTE_LINK);
62         KEVFFL_DUMP(NOTE_RENAME);
63     } else if (kev->filter == EVFILT_USER) {
64         KEVFFL_DUMP(NOTE_FFNOP);
65         KEVFFL_DUMP(NOTE_FFAND);
66         KEVFFL_DUMP(NOTE_FFOR);
67         KEVFFL_DUMP(NOTE_FFCOPY);
68         KEVFFL_DUMP(NOTE_TRIGGER);
69     }  else {
70         strncat(buf, " ", 1);
71     }
72     buf[strlen(buf) - 1] = ')';
73
74 #undef KEVFFL_DUMP
75
76     return (buf);
77 }
78
79 static char *
80 kevent_flags_dump(const struct kevent *kev)
81 {
82     static char __thread buf[1024];
83
84 #define KEVFL_DUMP(attrib) \
85     if (kev->flags & attrib) \
86         strncat(buf, #attrib" ", 64);
87
88     snprintf(buf, sizeof(buf), "flags=0x%04x (", kev->flags);
89     KEVFL_DUMP(EV_ADD);
90     KEVFL_DUMP(EV_ENABLE);
91     KEVFL_DUMP(EV_DISABLE);
92     KEVFL_DUMP(EV_DELETE);
93     KEVFL_DUMP(EV_ONESHOT);
94     KEVFL_DUMP(EV_CLEAR);
95     KEVFL_DUMP(EV_EOF);
96     KEVFL_DUMP(EV_ERROR);
97     KEVFL_DUMP(EV_DISPATCH);
98     KEVFL_DUMP(EV_RECEIPT);
99     buf[strlen(buf) - 1] = ')';
100
101 #undef KEVFL_DUMP
102
103     return (buf);
104 }
105
106 const char *
107 kevent_dump(const struct kevent *kev)
108 {
109     static char __thread buf[1024];
110
111     snprintf(buf, sizeof(buf), 
112             "{ ident=%d, filter=%s, %s, %s, data=%d, udata=%p }",
113             (u_int) kev->ident,
114             kevent_filter_dump(kev),
115             kevent_flags_dump(kev),
116             kevent_fflags_dump(kev),
117             (int) kev->data,
118             kev->udata);
119
120     return (buf);
121 }
122
123 static int
124 kevent_copyin_one(struct kqueue *kq, const struct kevent *src)
125 {
126     struct knote  *kn = NULL;
127     struct filter *filt;
128     int rv;
129
130     if (src->flags & EV_DISPATCH && src->flags & EV_ONESHOT) {
131         errno = EINVAL;
132         return (-1);
133     }
134
135     if (filter_lookup(&filt, kq, src->filter) < 0) 
136         return (-1);
137
138     //dbg_printf("src=%s\n", kevent_dump(src));
139
140     kn = knote_lookup(filt, src->ident);
141     if (kn == NULL) {
142         if (src->flags & EV_ADD) {
143             if ((kn = knote_new()) == NULL) {
144                 errno = ENOENT;
145                 return (-1);
146             }
147             memcpy(&kn->kev, src, sizeof(kn->kev));
148             kn->kev.flags &= ~EV_ENABLE;
149             kn->kev.flags |= EV_ADD;//FIXME why?
150             assert(filt->kn_create);
151             if (filt->kn_create(filt, kn) < 0) {
152                 knote_free(filt, kn);
153                 errno = EFAULT;
154                 return (-1);
155             } 
156             knote_insert(filt, kn);
157             dbg_printf("created kevent %s\n", kevent_dump(src));
158             if (src->flags & EV_DISABLE) {
159                 kn->kev.flags |= EV_DISABLE;
160                 return (filt->kn_disable(filt, kn));
161             }
162             return (0);
163         } else {
164             errno = ENOENT;
165             return (-1);
166         }
167     }
168
169     if (src->flags & EV_DELETE) {
170         rv = filt->kn_delete(filt, kn);
171         knote_free(filt, kn);
172         return (rv);
173     } else if (src->flags & EV_DISABLE) {
174         kn->kev.flags |= EV_DISABLE;
175         return (filt->kn_disable(filt, kn));
176     } else if (src->flags & EV_ENABLE) {
177         kn->kev.flags &= ~EV_DISABLE;
178         return (filt->kn_enable(filt, kn));
179     }
180
181     /* Implicit EV_ADD */
182     kn->kev.udata = src->udata;
183     return (filt->kn_modify(filt, kn, src));
184
185 #if DEADWOOD
186     /* Special case for EVFILT_USER:
187        Ignore user-generated events that are not of interest */
188     if (src->fflags & NOTE_TRIGGER) {
189         filter_unlock(filt);
190         continue;
191     }
192 #endif
193 }
194
195 /** @return number of events added to the eventlist */
196 static int
197 kevent_copyin(struct kqueue *kq, const struct kevent *src, int nchanges,
198         struct kevent *eventlist, int nevents)
199 {
200     int status, nret;
201
202     dbg_printf("nchanges=%d nevents=%d", nchanges, nevents);
203
204     /* TODO: refactor, this has become convoluted to support EV_RECEIPT */
205     for (nret = 0; nchanges > 0; src++, nchanges--) {
206
207         if (kevent_copyin_one(kq, src) < 0) {
208             dbg_printf("errno=%s",strerror(errno));
209             status = errno;
210             goto err_path;
211         } else {
212             if (src->flags & EV_RECEIPT) {
213                 status = 0;
214                 goto err_path;
215             }
216         }
217
218         continue;
219
220 err_path:
221         if (nevents > 0) {
222             memcpy(eventlist, src, sizeof(*src));
223             eventlist->data = status;
224             nevents--;
225             eventlist++;
226             nret++;
227         } else {
228             return (-1);
229         }
230     }
231
232     return (nret);
233 }
234
235 int __attribute__((visibility("default")))
236 kevent(int kqfd, const struct kevent *changelist, int nchanges,
237         struct kevent *eventlist, int nevents,
238         const struct timespec *timeout)
239 {
240     struct kqueue *kq;
241     int rv, n, nret;
242
243     nret = 0;
244
245     kq = kqueue_get(kqfd);
246     if (kq == NULL) {
247         errno = ENOENT;
248         return (-1);
249     }
250
251     rv = kqueue_validate(kq);
252     if (rv < 0) {
253         return (-1);
254     } else if (rv == 0) {
255         errno = EBADF;
256         return (-1);
257     }
258
259     /*
260      * Process each kevent on the changelist.
261      */
262     if (nchanges) {
263         kqueue_lock(kq);
264         rv = kevent_copyin(kq, changelist, nchanges, eventlist, nevents);
265         kqueue_unlock(kq);
266         dbg_printf("changelist: rv=%d", rv);
267         if (rv < 0)
268             goto errout;
269         if (rv > 0) {
270             eventlist += rv;
271             nevents -= rv;
272         }
273     }
274
275     /* Determine if we need to wait for events. */
276     if (nevents > MAX_KEVENT)
277         nevents = MAX_KEVENT;
278     if (nevents == 0)
279         goto out;
280
281     /* Handle spurious wakeups where no events are generated. */
282     for (nret = 0; nret == 0;) 
283     {
284         /* Wait for one or more events. */
285         n = kevent_wait(kq, timeout);
286         if (n < 0) {
287             dbg_puts("kevent_wait failed");
288             goto errout;
289         }
290         if (n == 0)
291             goto out;      /* Timeout */
292
293         /* Copy the events to the caller */
294         kqueue_lock(kq);
295         nret = kevent_copyout(kq, n, eventlist, nevents);
296         kqueue_unlock(kq);
297     }
298
299     if (KQUEUE_DEBUG) {
300         dbg_printf("returning %d events", nret);
301         for (n = 0; n < nret; n++) {
302             dbg_printf("eventlist[%d] = %s", n, kevent_dump(&eventlist[n]));
303         }
304     }
305
306     goto out;
307
308 errout:
309     nret = -1;
310
311 out:
312     kqueue_put(kq);
313     return (nret);
314 }