Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / posix / timer.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 <fcntl.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29
30 #include "sys/event.h"
31 #include "private.h"
32
33 /* A request to sleep for a certain time */
34 struct sleepreq {
35     int         pfd;            /* fd to poll for ACKs */
36     int         wfd;            /* fd to wake up when sleep is over */
37     uintptr_t   ident;          /* from kevent */
38     intptr_t    interval;       /* sleep time, in milliseconds */
39     struct sleepstat *stat;
40 };
41
42 /* Information about a successful sleep operation */
43 struct sleepinfo {
44     uintptr_t   ident;          /* from kevent */
45     uintptr_t   counter;        /* number of times the timer expired */
46 };
47
48 static void *
49 sleeper_thread(void *arg)
50 {
51     struct sleepreq sr;
52     struct sleepinfo si;
53     struct timespec req, rem;
54     sigset_t        mask;
55     ssize_t         cnt;
56     bool            cts = true;     /* Clear To Send */
57     char            buf[1];
58
59     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
60
61     /* Copyin the request */
62     memcpy(&sr, arg, sizeof(sr));
63     free(arg);
64
65     /* Initialize the response */
66     si.ident = sr.ident;
67     si.counter = 0;
68
69     /* Convert milliseconds into seconds+nanoseconds */
70     req.tv_sec = sr.interval / 1000;
71     req.tv_nsec = (sr.interval % 1000) * 1000000;
72
73     /* Block all signals */
74     sigfillset(&mask);
75     (void) pthread_sigmask(SIG_BLOCK, &mask, NULL);
76
77     for (;;) {
78
79         /* Sleep */
80         if (nanosleep(&req, &rem) < 0) {
81             //TODO: handle eintr, spurious wakeups
82             dbg_perror("nanosleep(2)");
83         }
84         si.counter++;
85         dbg_printf(" -------- sleep over (CTS=%d)----------", cts);
86
87         /* Test if the previous wakeup has been acknowledged */
88         if (!cts) {
89             cnt = read(sr.wfd, &buf, 1);
90             if (cnt < 0) {
91                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
92                     ;
93                 } else {
94                     dbg_perror("read(2)");
95                     break;
96                 }
97             } else if (cnt == 0) {
98                 dbg_perror("short read(2)");
99                 break;
100             } else {
101                 cts = true;
102             }
103         }
104
105         /* Wake up kevent waiters if they are ready */
106         if (cts) {
107             cnt = write(sr.wfd, &si, sizeof(si));
108             if (cnt < 0) {
109                 /* FIXME: handle EAGAIN and EINTR */
110                 dbg_perror("write(2)");
111             } else if (cnt < sizeof(si)) {
112                 dbg_puts("FIXME: handle short write"); 
113             } 
114             cts = false;
115             si.counter = 0;
116         }
117     }
118
119     return (NULL);
120 }
121
122 static int
123 _timer_create(struct filter *filt, struct knote *kn)
124 {
125     pthread_attr_t attr;
126     struct sleepreq *req;
127     kn->kev.flags |= EV_CLEAR;
128
129     req = malloc(sizeof(*req));
130     if (req == NULL) {
131         dbg_perror("malloc");
132         return (-1);
133     }
134     req->pfd = filt->kf_pfd;
135     req->wfd = filt->kf_wfd;
136     req->ident = kn->kev.ident;
137     req->interval = kn->kev.data;
138
139     pthread_attr_init(&attr);
140     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
141     if (pthread_create(&kn->data.tid, &attr, sleeper_thread, req) != 0) {
142         dbg_perror("pthread_create");
143         pthread_attr_destroy(&attr);
144         free(req);
145         return (-1);
146     }
147     pthread_attr_destroy(&attr);
148
149     return (0);
150 }
151
152 static int
153 _timer_delete(struct knote *kn)
154 {
155     if (pthread_cancel(kn->data.tid) != 0) {
156         /* Race condition: sleeper_thread exits before it is cancelled */
157         if (errno == ENOENT)
158             return (0);
159         dbg_perror("pthread_cancel(3)");
160         return (-1);
161     }
162     return (0);
163 }
164
165 int
166 evfilt_timer_init(struct filter *filt)
167 {
168     int fd[2];
169
170     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
171         dbg_perror("socketpair(3)");
172         return (-1);
173     }
174     if (fcntl(fd[0], F_SETFL, O_NONBLOCK) < 0
175         || fcntl(fd[1], F_SETFL, O_NONBLOCK) < 0) {
176         dbg_perror("fcntl(2)");
177         close(fd[0]);
178         close(fd[1]);
179         return (-1);
180     }
181
182     filt->kf_wfd = fd[0];
183     filt->kf_pfd = fd[1];
184
185     return (0);
186 }
187
188 void
189 evfilt_timer_destroy(struct filter *filt)
190 {
191     (void) close(filt->kf_wfd);
192     (void) close(filt->kf_pfd);
193 }
194
195 int
196 evfilt_timer_copyout(struct filter *filt, 
197             struct kevent *dst, 
198             int nevents)
199 {
200     struct sleepinfo    si;
201     ssize_t       cnt;
202     struct knote *kn;
203
204     /* Read the ident */
205     cnt = read(filt->kf_pfd, &si, sizeof(si));
206     if (cnt < 0) {
207         /* FIXME: handle EAGAIN and EINTR */
208         dbg_printf("read(2): %s", strerror(errno));
209         return (-1);
210     } else if (cnt < sizeof(si)) {
211         dbg_puts("error: short read");
212         return (-1);
213     }
214
215     /* Acknowlege receipt */
216     cnt = write(filt->kf_pfd, ".", 1);
217     if (cnt < 0) {
218         /* FIXME: handle EAGAIN and EINTR */
219         dbg_printf("write(2): %s", strerror(errno));
220         return (-1);
221     } else if (cnt < 1) {
222         dbg_puts("error: short write");
223         return (-1);
224     }
225
226     kn = knote_lookup(filt, si.ident);
227
228     /* Race condition: timer events remain queued even after
229        the knote is deleted. Ignore these events */
230     if (kn == NULL)
231         return (0);
232
233     dbg_printf("knote=%p", kn);
234     memcpy(dst, &kn->kev, sizeof(*dst));
235
236     dst->data = si.counter;
237
238     if (kn->kev.flags & EV_DISPATCH) {
239         KNOTE_DISABLE(kn);
240         _timer_delete(kn);
241     } else if (kn->kev.flags & EV_ONESHOT) {
242         _timer_delete(kn);
243         knote_free(filt, kn);
244     } 
245
246     return (1);
247 }
248
249 int
250 evfilt_timer_knote_create(struct filter *filt, struct knote *kn)
251 {
252     return _timer_create(filt, kn);
253 }
254
255 int
256 evfilt_timer_knote_modify(struct filter *filt, struct knote *kn, 
257         const struct kevent *kev)
258 {
259     return (-1); /* STUB */
260 }
261
262 int
263 evfilt_timer_knote_delete(struct filter *filt, struct knote *kn)
264 {
265     if (kn->kev.flags & EV_DISABLE)
266         return (0);
267
268     dbg_printf("deleting timer # %d", (int) kn->kev.ident);
269     return _timer_delete(kn);
270 }
271
272 int
273 evfilt_timer_knote_enable(struct filter *filt, struct knote *kn)
274 {
275     return evfilt_timer_knote_create(filt, kn);
276 }
277
278 int
279 evfilt_timer_knote_disable(struct filter *filt, struct knote *kn)
280 {
281     return evfilt_timer_knote_delete(filt, kn);
282 }
283
284 const struct filter evfilt_timer = {
285     EVFILT_TIMER,
286     evfilt_timer_init,
287     evfilt_timer_destroy,
288     evfilt_timer_copyout,
289     evfilt_timer_knote_create,
290     evfilt_timer_knote_modify,
291     evfilt_timer_knote_delete,
292     evfilt_timer_knote_enable,
293     evfilt_timer_knote_disable,     
294 };