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 <err.h> 19#include <fcntl.h> 20#include <pthread.h> 21#include <signal.h> 22#include <stdlib.h> 23#include <stdio.h> 24#include <sys/queue.h> 25#include <sys/types.h> 26#include <sys/wait.h> 27#include <string.h> 28#include <unistd.h> 29 30#include <limits.h> 31 32#include "sys/event.h" 33#include "private.h" 34 35pthread_cond_t wait_cond = PTHREAD_COND_INITIALIZER; 36pthread_mutex_t wait_mtx = PTHREAD_MUTEX_INITIALIZER; 37 38struct evfilt_data { 39 pthread_t wthr_id; 40}; 41 42static void * 43wait_thread(void *arg) 44{ 45 struct filter *filt = (struct filter *) arg; 46 struct knote *kn; 47 int status, result; 48 pid_t pid; 49 sigset_t sigmask; 50 51 /* Block all signals */ 52 sigfillset (&sigmask); 53 sigdelset(&sigmask, SIGCHLD); 54 pthread_sigmask(SIG_BLOCK, &sigmask, NULL); 55 56 for (;;) { 57 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"); 66 continue; 67 } 68 if (errno == EINTR) 69 continue; 70 dbg_printf("wait(2): %s", strerror(errno)); 71 break; 72 } 73 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); 80 } else { 81 dbg_puts("unexpected code path"); 82 result = 234; /* arbitrary error value */ 83 } 84 85 /* Scan the wait queue to see if anyone is interested */ 86 pthread_mutex_lock(&filt->kf_mtx); 87 kn = knote_lookup(filt, pid); 88 if (kn != NULL) { 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 */ 95 filter_raise(filt); 96 } 97 pthread_mutex_unlock(&filt->kf_mtx); 98 } 99 100 /* TODO: error handling */ 101 102 return (NULL); 103} 104 105int 106evfilt_proc_init(struct filter *filt) 107{ 108 struct evfilt_data *ed; 109 110 if ((ed = calloc(1, sizeof(*ed))) == NULL) 111 return (-1); 112 113 if (filter_socketpair(filt) < 0) 114 goto errout; 115 if (pthread_create(&ed->wthr_id, NULL, wait_thread, filt) != 0) 116 goto errout; 117 118 return (0); 119 120errout: 121 free(ed); 122 return (-1); 123} 124 125void 126evfilt_proc_destroy(struct filter *filt) 127{ 128//TODO: pthread_cancel(filt->kf_data->wthr_id); 129 close(filt->kf_pfd); 130} 131 132int 133evfilt_proc_copyin(struct filter *filt, 134 struct knote *dst, const struct kevent *src) 135{ 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); 140 } 141 142 if (src->flags & EV_ADD || src->flags & EV_ENABLE) { 143 /* Nothing to do.. */ 144 } 145 146 return (0); 147} 148 149int 150evfilt_proc_copyout(struct filter *filt, 151 struct kevent *dst, 152 int maxevents) 153{ 154 struct knote *kn; 155 int nevents = 0; 156 157 filter_lower(filt); 158 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; 163 164 if (kn->kev.flags & EV_DISPATCH) { 165 KNOTE_DISABLE(kn); 166 } 167#if FIXME 168 /* XXX - NEED TO use safe foreach instead */ 169 if (kn->kev.flags & EV_ONESHOT) 170 knote_free(kn); 171#endif 172 173 if (++nevents > maxevents) 174 break; 175 dst++; 176 } 177 178 if (!LIST_EMPTY(&filt->kf_eventlist)) 179 filter_raise(filt); 180 181 return (nevents); 182} 183 184const struct filter evfilt_proc = { 185 EVFILT_PROC, 186 evfilt_proc_init, 187 evfilt_proc_destroy, 188 evfilt_proc_copyin, 189 evfilt_proc_copyout, 190}; 191