Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / posix / user.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 int
33 evfilt_user_init(struct filter *filt)
34 {
35     filt->kf_efd = eventfd_create();
36     if (filt->kf_efd == NULL)
37         return (-1);
38
39     filt->kf_pfd = eventfd_reader(filt->kf_efd);
40     if (filt->kf_pfd < 0) 
41         return (-1);
42
43     return (0);
44 }
45
46 void
47 evfilt_user_destroy(struct filter *filt)
48 {
49     eventfd_free(filt->kf_efd);
50     return;
51 }
52
53 int
54 evfilt_user_copyout(struct filter *filt, 
55             struct kevent *dst, 
56             int maxevents)
57 {
58     struct knote *kn;
59     int nevents = 0;
60   
61     for (kn = knote_dequeue(filt); kn != NULL; kn = knote_dequeue(filt)) {
62         memcpy(dst, &kn->kev, sizeof(*dst));
63         dst->fflags &= ~NOTE_FFCTRLMASK;     //FIXME: Not sure if needed
64         dst->fflags &= ~NOTE_TRIGGER;
65         if (kn->kev.flags & EV_ADD) {
66             /* NOTE: True on FreeBSD but not consistent behavior with
67                       other filters. */
68             dst->flags &= ~EV_ADD;
69         }
70         if (kn->kev.flags & EV_CLEAR)
71             kn->kev.fflags &= ~NOTE_TRIGGER;
72         if (kn->kev.flags & (EV_DISPATCH | EV_CLEAR | EV_ONESHOT))
73             eventfd_lower(filt->kf_efd);
74         if (kn->kev.flags & EV_DISPATCH) {
75             KNOTE_DISABLE(kn);
76             kn->kev.fflags &= ~NOTE_TRIGGER;
77         } else if (kn->kev.flags & EV_ONESHOT) {
78             knote_free(filt, kn);
79         }
80
81         dst++;
82         if (++nevents == maxevents)
83             break;
84     }
85
86     /* This should normally never happen but is here for debugging */
87     if (nevents == 0) {
88         dbg_puts("spurious wakeup");
89         eventfd_lower(filt->kf_efd);
90     }
91
92     return (nevents);
93 }
94
95 int
96 evfilt_user_knote_create(struct filter *filt, struct knote *kn)
97 {
98 #if TODO
99     u_int ffctrl;
100
101     //determine if EV_ADD + NOTE_TRIGGER in the same kevent will cause a trigger */
102     if ((!(dst->kev.flags & EV_DISABLE)) && src->fflags & NOTE_TRIGGER) {
103         dst->kev.fflags |= NOTE_TRIGGER;
104         eventfd_raise(filt->kf_pfd);
105     }
106
107 #endif
108     return (0);
109 }
110
111 int
112 evfilt_user_knote_modify(struct filter *filt, struct knote *kn, 
113         const struct kevent *kev)
114 {
115     unsigned int ffctrl;
116     unsigned int fflags;
117
118     /* Excerpted from sys/kern/kern_event.c in FreeBSD HEAD */
119     ffctrl = kev->fflags & NOTE_FFCTRLMASK;
120     fflags = kev->fflags & NOTE_FFLAGSMASK;
121     switch (ffctrl) {
122         case NOTE_FFNOP:
123             break;
124
125         case NOTE_FFAND:
126             kn->kev.fflags &= fflags;
127             break;
128
129         case NOTE_FFOR:
130             kn->kev.fflags |= fflags;
131             break;
132
133         case NOTE_FFCOPY:
134             kn->kev.fflags = fflags;
135             break;
136
137         default:
138             /* XXX Return error? */
139             break;
140     }
141
142     if ((!(kn->kev.flags & EV_DISABLE)) && kev->fflags & NOTE_TRIGGER) {
143         kn->kev.fflags |= NOTE_TRIGGER;
144         knote_enqueue(filt, kn);
145         eventfd_raise(filt->kf_efd);
146     }
147
148     return (0);
149 }
150
151 int
152 evfilt_user_knote_delete(struct filter *filt, struct knote *kn)
153 {
154     return (0);
155 }
156
157 int
158 evfilt_user_knote_enable(struct filter *filt, struct knote *kn)
159 {
160     /* FIXME: what happens if NOTE_TRIGGER is in fflags?
161        should the event fire? */
162     return (0);
163 }
164
165 int
166 evfilt_user_knote_disable(struct filter *filt, struct knote *kn)
167 {
168     return (0);
169 }
170
171 const struct filter evfilt_user = {
172     EVFILT_USER,
173     evfilt_user_init,
174     evfilt_user_destroy,
175     evfilt_user_copyout,
176     evfilt_user_knote_create,
177     evfilt_user_knote_modify,
178     evfilt_user_knote_delete,
179     evfilt_user_knote_enable,
180     evfilt_user_knote_disable,   
181 };