Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / posix / proc.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 <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
35 pthread_cond_t   wait_cond = PTHREAD_COND_INITIALIZER;
36 pthread_mutex_t  wait_mtx = PTHREAD_MUTEX_INITIALIZER;
37
38 struct evfilt_data {
39     pthread_t       wthr_id;
40 };
41
42 static void *
43 wait_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
105 int
106 evfilt_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
120 errout:
121     free(ed);
122     return (-1);
123 }
124
125 void
126 evfilt_proc_destroy(struct filter *filt)
127 {
128 //TODO:    pthread_cancel(filt->kf_data->wthr_id);
129     close(filt->kf_pfd);
130 }
131
132 int
133 evfilt_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
149 int
150 evfilt_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
184 const struct filter evfilt_proc = {
185     EVFILT_PROC,
186     evfilt_proc_init,
187     evfilt_proc_destroy,
188     evfilt_proc_copyin,
189     evfilt_proc_copyout,
190 };