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