2 * Waitable timers management
4 * Copyright (C) 1999 Alexandre Julliard
11 #include <sys/types.h>
19 struct object obj; /* object header */
20 int manual; /* manual reset */
21 int signaled; /* current signaled state */
22 int period; /* timer period in ms */
23 struct timeval when; /* next expiration */
24 struct timeout_user *timeout; /* timeout user */
25 struct thread *thread; /* thread that set the APC function */
26 void *callback; /* callback APC function */
27 void *arg; /* callback argument */
30 static void timer_dump( struct object *obj, int verbose );
31 static int timer_signaled( struct object *obj, struct thread *thread );
32 static int timer_satisfied( struct object *obj, struct thread *thread );
33 static void timer_destroy( struct object *obj );
35 static const struct object_ops timer_ops =
37 sizeof(struct timer), /* size */
38 timer_dump, /* dump */
39 add_queue, /* add_queue */
40 remove_queue, /* remove_queue */
41 timer_signaled, /* signaled */
42 timer_satisfied, /* satisfied */
43 NULL, /* get_poll_events */
44 NULL, /* poll_event */
45 no_get_fd, /* get_fd */
47 no_get_file_info, /* get_file_info */
48 timer_destroy /* destroy */
52 /* create a timer object */
53 static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
57 if ((timer = create_named_object( &timer_ops, name, len )))
59 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
61 /* initialize it if it didn't already exist */
62 timer->manual = manual;
64 timer->when.tv_sec = 0;
65 timer->when.tv_usec = 0;
67 timer->timeout = NULL;
74 /* callback on timer expiration */
75 static void timer_callback( void *private )
77 struct timer *timer = (struct timer *)private;
81 thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0, 3,
82 (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg );
84 if (timer->period) /* schedule the next expiration */
86 add_timeout( &timer->when, timer->period );
87 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
89 else timer->timeout = NULL;
93 wake_up( &timer->obj, 0 );
96 /* cancel a running timer */
97 static void cancel_timer( struct timer *timer )
101 remove_timeout_user( timer->timeout );
102 timer->timeout = NULL;
106 thread_cancel_apc( timer->thread, &timer->obj, 0 );
107 timer->thread = NULL;
111 /* set the timer expiration and period */
112 static void set_timer( struct timer *timer, int sec, int usec, int period,
113 void *callback, void *arg )
115 cancel_timer( timer );
118 period = 0; /* period doesn't make any sense for a manual timer */
123 /* special case: use now + period as first expiration */
124 gettimeofday( &timer->when, 0 );
125 add_timeout( &timer->when, period );
129 timer->when.tv_sec = sec;
130 timer->when.tv_usec = usec;
132 timer->period = period;
133 timer->callback = callback;
135 if (callback) timer->thread = current;
136 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
139 static void timer_dump( struct object *obj, int verbose )
141 struct timer *timer = (struct timer *)obj;
142 assert( obj->ops == &timer_ops );
143 fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
144 timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
145 dump_object_name( &timer->obj );
146 fputc( '\n', stderr );
149 static int timer_signaled( struct object *obj, struct thread *thread )
151 struct timer *timer = (struct timer *)obj;
152 assert( obj->ops == &timer_ops );
153 return timer->signaled;
156 static int timer_satisfied( struct object *obj, struct thread *thread )
158 struct timer *timer = (struct timer *)obj;
159 assert( obj->ops == &timer_ops );
160 if (!timer->manual) timer->signaled = 0;
164 static void timer_destroy( struct object *obj )
166 struct timer *timer = (struct timer *)obj;
167 assert( obj->ops == &timer_ops );
169 if (timer->timeout) remove_timeout_user( timer->timeout );
173 DECL_HANDLER(create_timer)
178 if ((timer = create_timer( get_req_data(req), get_req_data_size(req), req->manual )))
180 req->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
181 release_object( timer );
185 /* open a handle to a timer */
186 DECL_HANDLER(open_timer)
188 req->handle = open_object( get_req_data(req), get_req_data_size(req),
189 &timer_ops, req->access, req->inherit );
192 /* set a waitable timer */
193 DECL_HANDLER(set_timer)
197 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
198 TIMER_MODIFY_STATE, &timer_ops )))
200 set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
201 release_object( timer );
205 /* cancel a waitable timer */
206 DECL_HANDLER(cancel_timer)
210 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
211 TIMER_MODIFY_STATE, &timer_ops )))
213 cancel_timer( timer );
214 release_object( timer );