Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / linux / 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 #include <sys/inotify.h>
32 #include <sys/epoll.h>
33
34 #include "sys/event.h"
35 #include "private.h"
36
37
38 /* XXX-FIXME Should only have one wait_thread per process.
39    Now, there is one thread per kqueue
40  */
41 struct evfilt_data {
42     pthread_t       wthr_id;
43     pthread_cond_t   wait_cond;
44     pthread_mutex_t  wait_mtx;
45 };
46
47 //FIXME: WANT: static void *
48 void *
49 wait_thread(void *arg)
50 {
51     struct filter *filt = (struct filter *) arg;
52     uint64_t counter = 1;
53     const int options = WEXITED | WNOWAIT; 
54     struct knote *kn;
55     siginfo_t si;
56     sigset_t sigmask;
57
58     /* Block all signals */
59     sigfillset (&sigmask);
60     pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
61
62     for (;;) {
63
64         /* Wait for a child process to exit(2) */
65         if (waitid(P_ALL, 0, &si, options) != 0) {
66             if (errno == ECHILD) {
67                 dbg_puts("got ECHILD, waiting for wakeup condition");
68                 pthread_mutex_lock(&filt->kf_data->wait_mtx);
69                 pthread_cond_wait(&filt->kf_data->wait_cond, &filt->kf_data->wait_mtx);
70                 pthread_mutex_unlock(&filt->kf_data->wait_mtx);
71                 dbg_puts("awoken from ECHILD-induced sleep");
72                 continue;
73             }
74
75             dbg_puts("  waitid(2) returned");
76             if (errno == EINTR)
77                 continue;
78             dbg_perror("waitid(2)");
79             break; 
80         }
81
82         /* Scan the wait queue to see if anyone is interested */
83         kn = knote_lookup(filt, si.si_pid);
84         if (kn == NULL) 
85             continue;
86
87         /* Create a proc_event */
88         if (si.si_code == CLD_EXITED) {
89             kn->kev.data = si.si_status;
90         } else if (si.si_code == CLD_KILLED) {
91             /* FIXME: probably not true on BSD */
92             /* FIXME: arbitrary non-zero number */
93             kn->kev.data = 254; 
94         } else {
95             /* Should never happen. */
96             /* FIXME: arbitrary non-zero number */
97             kn->kev.data = 1; 
98         }
99
100         knote_enqueue(filt, kn);
101
102         /* Indicate read(2) readiness */
103         if (write(filt->kf_pfd, &counter, sizeof(counter)) < 0) {
104             if (errno != EAGAIN) {
105                 dbg_printf("write(2): %s", strerror(errno));
106                 /* TODO: set filter error flag */
107                 break;
108                 }
109         }
110     }
111
112     /* TODO: error handling */
113
114     return (NULL);
115 }
116
117 int
118 evfilt_proc_init(struct filter *filt)
119 {
120 #if FIXME
121     struct evfilt_data *ed;
122     int efd = -1;
123
124     if ((ed = calloc(1, sizeof(*ed))) == NULL)
125         return (-1);
126     filt->kf_data = ed;
127
128     pthread_mutex_init(&ed->wait_mtx, NULL);
129     pthread_cond_init(&ed->wait_cond, NULL);
130     if ((efd = eventfd(0, 0)) < 0) 
131         goto errout;
132     if (fcntl(filt->kf_pfd, F_SETFL, O_NONBLOCK) < 0) 
133         goto errout;
134     filt->kf_pfd = efd;
135     if (pthread_create(&ed->wthr_id, NULL, wait_thread, filt) != 0) 
136         goto errout;
137
138
139     return (0);
140
141 errout:
142     if (efd >= 0)
143         close(efd);
144     free(ed);
145     close(filt->kf_pfd);
146     return (-1);
147 #endif
148     return (-1); /*STUB*/
149 }
150
151 void
152 evfilt_proc_destroy(struct filter *filt)
153 {
154 //TODO:    pthread_cancel(filt->kf_data->wthr_id);
155     close(filt->kf_pfd);
156 }
157
158 int
159 evfilt_proc_copyout(struct filter *filt, 
160             struct kevent *dst, 
161             int maxevents)
162 {
163     struct knote *kn;
164     int nevents = 0;
165     uint64_t cur;
166
167     /* Reset the counter */
168     if (read(filt->kf_pfd, &cur, sizeof(cur)) < sizeof(cur)) {
169         dbg_printf("read(2): %s", strerror(errno));
170         return (-1);
171     }
172     dbg_printf("  counter=%llu", (unsigned long long) cur);
173
174     for (kn = knote_dequeue(filt); kn != NULL; kn = knote_dequeue(filt)) {
175         kevent_dump(&kn->kev);
176         memcpy(dst, &kn->kev, sizeof(*dst));
177
178         if (kn->kev.flags & EV_DISPATCH) {
179             KNOTE_DISABLE(kn);
180         }
181         if (kn->kev.flags & EV_ONESHOT) {
182             knote_free(filt, kn);
183         } else {
184             kn->kev.data = 0; //why??
185         }
186
187
188         if (++nevents > maxevents)
189             break;
190         dst++;
191     }
192
193     if (knote_events_pending(filt)) {
194     /* XXX-FIXME: If there are leftover events on the waitq, 
195        re-arm the eventfd. list */
196         abort();
197     }
198
199     return (nevents);
200 }
201  
202 int
203 evfilt_proc_knote_create(struct filter *filt, struct knote *kn)
204 {
205     return (0); /* STUB */
206 }
207
208 int
209 evfilt_proc_knote_modify(struct filter *filt, struct knote *kn, 
210         const struct kevent *kev)
211 {
212     return (0); /* STUB */
213 }
214
215 int
216 evfilt_proc_knote_delete(struct filter *filt, struct knote *kn)
217 {
218     return (0); /* STUB */
219 }
220
221 int
222 evfilt_proc_knote_enable(struct filter *filt, struct knote *kn)
223 {
224     return (0); /* STUB */
225 }
226
227 int
228 evfilt_proc_knote_disable(struct filter *filt, struct knote *kn)
229 {
230     return (0); /* STUB */
231 }
232
233 const struct filter evfilt_proc_DEADWOOD = {
234     0, //XXX-FIXME broken: EVFILT_PROC,
235     evfilt_proc_init,
236     evfilt_proc_destroy,
237     evfilt_proc_copyout,
238     evfilt_proc_knote_create,
239     evfilt_proc_knote_modify,
240     evfilt_proc_knote_delete,
241     evfilt_proc_knote_enable,
242     evfilt_proc_knote_disable,
243 };