2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
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.
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.
24 #include <sys/queue.h>
25 #include <sys/types.h>
32 #include "sys/event.h"
35 pthread_cond_t wait_cond = PTHREAD_COND_INITIALIZER;
36 pthread_mutex_t wait_mtx = PTHREAD_MUTEX_INITIALIZER;
43 wait_thread(void *arg)
45 struct filter *filt = (struct filter *) arg;
51 /* Block all signals */
52 sigfillset (&sigmask);
53 sigdelset(&sigmask, SIGCHLD);
54 pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
58 /* Wait for a child process to exit(2) */
59 if ((pid = waitpid(-1, &status, 0)) < 0) {
60 if (errno == ECHILD) {
61 dbg_puts("got ECHILD, waiting for wakeup condition");
62 pthread_mutex_lock(&wait_mtx);
63 pthread_cond_wait(&wait_cond, &wait_mtx);
64 pthread_mutex_unlock(&wait_mtx);
65 dbg_puts("awoken from ECHILD-induced sleep");
70 dbg_printf("wait(2): %s", strerror(errno));
74 /* Create a proc_event */
75 if (WIFEXITED(status)) {
76 result = WEXITSTATUS(status);
77 } else if (WIFSIGNALED(status)) {
78 /* FIXME: probably not true on BSD */
79 result = WTERMSIG(status);
81 dbg_puts("unexpected code path");
82 result = 234; /* arbitrary error value */
85 /* Scan the wait queue to see if anyone is interested */
86 pthread_mutex_lock(&filt->kf_mtx);
87 kn = knote_lookup(filt, pid);
89 kn->kev.data = result;
90 kn->kev.fflags = NOTE_EXIT;
91 LIST_REMOVE(kn, entries);
92 LIST_INSERT_HEAD(&filt->kf_eventlist, kn, entries);
93 /* Indicate read(2) readiness */
94 /* TODO: error handling */
97 pthread_mutex_unlock(&filt->kf_mtx);
100 /* TODO: error handling */
106 evfilt_proc_init(struct filter *filt)
108 struct evfilt_data *ed;
110 if ((ed = calloc(1, sizeof(*ed))) == NULL)
113 if (filter_socketpair(filt) < 0)
115 if (pthread_create(&ed->wthr_id, NULL, wait_thread, filt) != 0)
126 evfilt_proc_destroy(struct filter *filt)
128 //TODO: pthread_cancel(filt->kf_data->wthr_id);
133 evfilt_proc_copyin(struct filter *filt,
134 struct knote *dst, const struct kevent *src)
136 if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
137 memcpy(&dst->kev, src, sizeof(*src));
138 /* TODO: think about locking the mutex first.. */
139 pthread_cond_signal(&wait_cond);
142 if (src->flags & EV_ADD || src->flags & EV_ENABLE) {
143 /* Nothing to do.. */
150 evfilt_proc_copyout(struct filter *filt,
159 LIST_FOREACH(kn, &filt->kf_eventlist, entries) {
160 kevent_dump(&kn->kev);
161 memcpy(dst, &kn->kev, sizeof(*dst));
162 dst->fflags = NOTE_EXIT;
164 if (kn->kev.flags & EV_DISPATCH) {
168 /* XXX - NEED TO use safe foreach instead */
169 if (kn->kev.flags & EV_ONESHOT)
173 if (++nevents > maxevents)
178 if (!LIST_EMPTY(&filt->kf_eventlist))
184 const struct filter evfilt_proc = {