2 * Waitable timers management
4 * Copyright (C) 1999 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sys/types.h>
33 struct object obj; /* object header */
34 int manual; /* manual reset */
35 int signaled; /* current signaled state */
36 int period; /* timer period in ms */
37 struct timeval when; /* next expiration */
38 struct timeout_user *timeout; /* timeout user */
39 struct thread *thread; /* thread that set the APC function */
40 void *callback; /* callback APC function */
41 void *arg; /* callback argument */
44 static void timer_dump( struct object *obj, int verbose );
45 static int timer_signaled( struct object *obj, struct thread *thread );
46 static int timer_satisfied( struct object *obj, struct thread *thread );
47 static void timer_destroy( struct object *obj );
49 static const struct object_ops timer_ops =
51 sizeof(struct timer), /* size */
52 timer_dump, /* dump */
53 add_queue, /* add_queue */
54 remove_queue, /* remove_queue */
55 timer_signaled, /* signaled */
56 timer_satisfied, /* satisfied */
57 NULL, /* get_poll_events */
58 NULL, /* poll_event */
59 no_get_fd, /* get_fd */
61 no_get_file_info, /* get_file_info */
62 NULL, /* queue_async */
63 timer_destroy /* destroy */
67 /* create a timer object */
68 static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
72 if ((timer = create_named_object( &timer_ops, name, len )))
74 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
76 /* initialize it if it didn't already exist */
77 timer->manual = manual;
79 timer->when.tv_sec = 0;
80 timer->when.tv_usec = 0;
82 timer->timeout = NULL;
89 /* callback on timer expiration */
90 static void timer_callback( void *private )
92 struct timer *timer = (struct timer *)private;
96 thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0, 3,
97 (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg );
99 if (timer->period) /* schedule the next expiration */
101 add_timeout( &timer->when, timer->period );
102 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
104 else timer->timeout = NULL;
106 /* wake up waiters */
108 wake_up( &timer->obj, 0 );
111 /* cancel a running timer */
112 static void cancel_timer( struct timer *timer )
116 remove_timeout_user( timer->timeout );
117 timer->timeout = NULL;
121 thread_cancel_apc( timer->thread, &timer->obj, 0 );
122 timer->thread = NULL;
126 /* set the timer expiration and period */
127 static void set_timer( struct timer *timer, int sec, int usec, int period,
128 void *callback, void *arg )
130 cancel_timer( timer );
133 period = 0; /* period doesn't make any sense for a manual timer */
138 /* special case: use now + period as first expiration */
139 gettimeofday( &timer->when, 0 );
140 add_timeout( &timer->when, period );
144 timer->when.tv_sec = sec;
145 timer->when.tv_usec = usec;
147 timer->period = period;
148 timer->callback = callback;
150 if (callback) timer->thread = current;
151 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
154 static void timer_dump( struct object *obj, int verbose )
156 struct timer *timer = (struct timer *)obj;
157 assert( obj->ops == &timer_ops );
158 fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
159 timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
160 dump_object_name( &timer->obj );
161 fputc( '\n', stderr );
164 static int timer_signaled( struct object *obj, struct thread *thread )
166 struct timer *timer = (struct timer *)obj;
167 assert( obj->ops == &timer_ops );
168 return timer->signaled;
171 static int timer_satisfied( struct object *obj, struct thread *thread )
173 struct timer *timer = (struct timer *)obj;
174 assert( obj->ops == &timer_ops );
175 if (!timer->manual) timer->signaled = 0;
179 static void timer_destroy( struct object *obj )
181 struct timer *timer = (struct timer *)obj;
182 assert( obj->ops == &timer_ops );
184 if (timer->timeout) remove_timeout_user( timer->timeout );
188 DECL_HANDLER(create_timer)
193 if ((timer = create_timer( get_req_data(), get_req_data_size(), req->manual )))
195 reply->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
196 release_object( timer );
200 /* open a handle to a timer */
201 DECL_HANDLER(open_timer)
203 reply->handle = open_object( get_req_data(), get_req_data_size(),
204 &timer_ops, req->access, req->inherit );
207 /* set a waitable timer */
208 DECL_HANDLER(set_timer)
212 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
213 TIMER_MODIFY_STATE, &timer_ops )))
215 set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
216 release_object( timer );
220 /* cancel a waitable timer */
221 DECL_HANDLER(cancel_timer)
225 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
226 TIMER_MODIFY_STATE, &timer_ops )))
228 cancel_timer( timer );
229 release_object( timer );