Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / solaris / 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 #ifndef NDEBUG
34 static char *
35 itimerspec_dump(struct itimerspec *ts)
36 {
37     static char __thread buf[1024];
38
39     snprintf(buf, sizeof(buf),
40             "itimer: [ interval=%lu s %lu ns, next expire=%lu s %lu ns ]",
41             ts->it_interval.tv_sec,
42             ts->it_interval.tv_nsec,
43             ts->it_value.tv_sec,
44             ts->it_value.tv_nsec
45            );
46
47     return (buf);
48 }
49 #endif
50
51 /* Convert milliseconds into seconds+nanoseconds */
52 static void
53 convert_msec_to_itimerspec(struct itimerspec *dst, int src, int oneshot)
54 {
55     time_t sec, nsec;
56
57     sec = src / 1000;
58     nsec = (src % 1000) * 1000000;
59
60     /* Set the interval */
61     if (oneshot) {
62         dst->it_interval.tv_sec = 0;
63         dst->it_interval.tv_nsec = 0;
64     } else {
65         dst->it_interval.tv_sec = sec;
66         dst->it_interval.tv_nsec = nsec;
67     }
68
69     /* Set the initial expiration */
70     dst->it_value.tv_sec = sec;
71     dst->it_value.tv_nsec = nsec;
72     dbg_printf("%s", itimerspec_dump(dst));
73 }
74
75 static int
76 ktimer_create(struct filter *filt, struct knote *kn)
77 {
78     port_notify_t pn;
79     struct sigevent se;
80     struct itimerspec ts;
81     timer_t timerid;
82
83     kn->kev.flags |= EV_CLEAR;
84
85     pn.portnfy_port = filt->kf_kqueue->kq_port;
86     pn.portnfy_user = (void *) kn->kev.ident;
87
88     se.sigev_notify = SIGEV_PORT;
89     se.sigev_value.sival_ptr = &pn;
90
91     if (timer_create (CLOCK_MONOTONIC, &se, &timerid) < 0) {
92         dbg_perror("timer_create(2)"); 
93         return (-1);
94     }
95    
96     convert_msec_to_itimerspec(&ts, kn->kev.data, kn->kev.flags & EV_ONESHOT);
97     if (timer_settime(timerid, 0, &ts, NULL) < 0) {
98         dbg_perror("timer_settime(2)");
99         (void) timer_delete(timerid);
100         return (-1);
101     }
102
103     kn->data.timerid = timerid;
104     dbg_printf("created timer with id #%lu", (unsigned long) timerid);
105
106     return (0);
107 }
108
109 int
110 evfilt_timer_init(struct filter *filt)
111 {
112     return (0);
113 }
114
115 void
116 evfilt_timer_destroy(struct filter *filt)
117 {
118     return;
119 }
120
121 int
122 evfilt_timer_copyout(struct filter *filt, 
123             struct kevent *dst, 
124             int nevents)
125 {
126     port_event_t *pe = (port_event_t *) pthread_getspecific(filt->kf_kqueue->kq_port_event);
127     long buf;
128     timer_t timerid;
129     struct knote *kn;
130
131     /* XXX-FIXME: danger here -- there has to be a better way */
132     buf = (long) pe->portev_user;
133     timerid = (timer_t) buf;
134     /* ^^^^^^^^^ */
135     kn = knote_lookup(filt, timerid);
136
137     dbg_printf("knote=%p", kn);
138     memcpy(dst, &kn->kev, sizeof(*dst));
139     //TODO:
140     //if (ev->events & EPOLLERR)
141     //    dst->fflags = 1; /* FIXME: Return the actual timer error */
142
143     /* FIXME: On return, data contains the number of times the
144        timer has been trigered.
145      */
146     dst->data = 1;  //workaround
147
148     if (kn->kev.flags & EV_DISPATCH) {
149         KNOTE_DISABLE(kn);
150         timer_delete(kn->data.timerid);
151     } else if (kn->kev.flags & EV_ONESHOT) {
152         timer_delete(kn->data.timerid);
153         knote_free(filt, kn);
154     }
155
156     return (1);
157 }
158
159 int
160 evfilt_timer_knote_create(struct filter *filt, struct knote *kn)
161 {
162     return ktimer_create(filt, kn);
163 }
164
165 int
166 evfilt_timer_knote_modify(struct filter *filt, struct knote *kn, 
167         const struct kevent *kev)
168 {
169     return (-1); /* STUB */
170 }
171
172 int
173 evfilt_timer_knote_delete(struct filter *filt, struct knote *kn)
174 {
175     if (kn->kev.flags & EV_DISABLE)
176         return (0);
177
178     dbg_printf("deleting timer # %d", kn->data.timerid);
179     return timer_delete(kn->data.timerid);
180 }
181
182 int
183 evfilt_timer_knote_enable(struct filter *filt, struct knote *kn)
184 {
185     return evfilt_timer_knote_create(filt, kn);
186 }
187
188 int
189 evfilt_timer_knote_disable(struct filter *filt, struct knote *kn)
190 {
191     return evfilt_timer_knote_delete(filt, kn);
192 }
193
194 const struct filter evfilt_timer = {
195     EVFILT_TIMER,
196     evfilt_timer_init,
197     evfilt_timer_destroy,
198     evfilt_timer_copyout,
199     evfilt_timer_knote_create,
200     evfilt_timer_knote_modify,
201     evfilt_timer_knote_delete,
202     evfilt_timer_knote_enable,
203     evfilt_timer_knote_disable,     
204 };