blob: 90e1f32f74be19268f87dc8084afa19859d087c5 [file] [log] [blame]
Alexandre Julliardad47a301999-11-29 01:58:35 +00001/*
2 * Waitable timers management
3 *
4 * Copyright (C) 1999 Alexandre Julliard
5 */
6
7#include <assert.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/time.h>
11#include <sys/types.h>
12
Alexandre Julliardea1afce2000-08-22 20:08:37 +000013#include "winnt.h"
Alexandre Julliardad47a301999-11-29 01:58:35 +000014#include "handle.h"
15#include "request.h"
16
Alexandre Julliardad47a301999-11-29 01:58:35 +000017struct timer
18{
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 */
Alexandre Julliardea1afce2000-08-22 20:08:37 +000025 struct thread *thread; /* thread that set the APC function */
Alexandre Julliardad47a301999-11-29 01:58:35 +000026 void *callback; /* callback APC function */
27 void *arg; /* callback argument */
28};
29
30static void timer_dump( struct object *obj, int verbose );
31static int timer_signaled( struct object *obj, struct thread *thread );
32static int timer_satisfied( struct object *obj, struct thread *thread );
33static void timer_destroy( struct object *obj );
34
35static const struct object_ops timer_ops =
36{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000037 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 */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +000045 no_get_fd, /* get_fd */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000046 no_flush, /* flush */
47 no_get_file_info, /* get_file_info */
Mike McCormack6f011c02001-12-20 00:07:05 +000048 NULL, /* queue_async */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000049 timer_destroy /* destroy */
Alexandre Julliardad47a301999-11-29 01:58:35 +000050};
51
52
53/* create a timer object */
54static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
55{
56 struct timer *timer;
57
58 if ((timer = create_named_object( &timer_ops, name, len )))
59 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +000060 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
Alexandre Julliardad47a301999-11-29 01:58:35 +000061 {
62 /* initialize it if it didn't already exist */
63 timer->manual = manual;
64 timer->signaled = 0;
65 timer->when.tv_sec = 0;
66 timer->when.tv_usec = 0;
67 timer->period = 0;
68 timer->timeout = NULL;
Alexandre Julliardea1afce2000-08-22 20:08:37 +000069 timer->thread = NULL;
Alexandre Julliardad47a301999-11-29 01:58:35 +000070 }
71 }
72 return timer;
73}
74
75/* callback on timer expiration */
76static void timer_callback( void *private )
77{
78 struct timer *timer = (struct timer *)private;
79
Alexandre Julliardea1afce2000-08-22 20:08:37 +000080 /* queue an APC */
81 if (timer->thread)
Alexandre Julliard23623802001-01-06 01:48:51 +000082 thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0, 3,
Alexandre Julliardea1afce2000-08-22 20:08:37 +000083 (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg );
84
Alexandre Julliardad47a301999-11-29 01:58:35 +000085 if (timer->period) /* schedule the next expiration */
86 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000087 add_timeout( &timer->when, timer->period );
Alexandre Julliardad47a301999-11-29 01:58:35 +000088 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
89 }
90 else timer->timeout = NULL;
91
92 /* wake up waiters */
93 timer->signaled = 1;
94 wake_up( &timer->obj, 0 );
95}
96
Alexandre Julliardea1afce2000-08-22 20:08:37 +000097/* cancel a running timer */
98static void cancel_timer( struct timer *timer )
99{
100 if (timer->timeout)
101 {
102 remove_timeout_user( timer->timeout );
103 timer->timeout = NULL;
104 }
105 if (timer->thread)
106 {
Alexandre Julliard23623802001-01-06 01:48:51 +0000107 thread_cancel_apc( timer->thread, &timer->obj, 0 );
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000108 timer->thread = NULL;
109 }
110}
111
Alexandre Julliardad47a301999-11-29 01:58:35 +0000112/* set the timer expiration and period */
113static void set_timer( struct timer *timer, int sec, int usec, int period,
114 void *callback, void *arg )
115{
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000116 cancel_timer( timer );
Alexandre Julliardad47a301999-11-29 01:58:35 +0000117 if (timer->manual)
118 {
119 period = 0; /* period doesn't make any sense for a manual timer */
120 timer->signaled = 0;
121 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000122 if (!sec && !usec)
123 {
124 /* special case: use now + period as first expiration */
125 gettimeofday( &timer->when, 0 );
126 add_timeout( &timer->when, period );
127 }
128 else
129 {
130 timer->when.tv_sec = sec;
131 timer->when.tv_usec = usec;
132 }
Alexandre Julliardad47a301999-11-29 01:58:35 +0000133 timer->period = period;
134 timer->callback = callback;
135 timer->arg = arg;
Alexandre Julliardea1afce2000-08-22 20:08:37 +0000136 if (callback) timer->thread = current;
Alexandre Julliardad47a301999-11-29 01:58:35 +0000137 timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
138}
139
Alexandre Julliardad47a301999-11-29 01:58:35 +0000140static void timer_dump( struct object *obj, int verbose )
141{
142 struct timer *timer = (struct timer *)obj;
143 assert( obj->ops == &timer_ops );
144 fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
145 timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
146 dump_object_name( &timer->obj );
147 fputc( '\n', stderr );
148}
149
150static int timer_signaled( struct object *obj, struct thread *thread )
151{
152 struct timer *timer = (struct timer *)obj;
153 assert( obj->ops == &timer_ops );
154 return timer->signaled;
155}
156
157static int timer_satisfied( struct object *obj, struct thread *thread )
158{
159 struct timer *timer = (struct timer *)obj;
160 assert( obj->ops == &timer_ops );
161 if (!timer->manual) timer->signaled = 0;
162 return 0;
163}
164
165static void timer_destroy( struct object *obj )
166{
167 struct timer *timer = (struct timer *)obj;
168 assert( obj->ops == &timer_ops );
169
170 if (timer->timeout) remove_timeout_user( timer->timeout );
171}
172
173/* create a timer */
174DECL_HANDLER(create_timer)
175{
Alexandre Julliardad47a301999-11-29 01:58:35 +0000176 struct timer *timer;
177
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000178 reply->handle = 0;
179 if ((timer = create_timer( get_req_data(), get_req_data_size(), req->manual )))
Alexandre Julliardad47a301999-11-29 01:58:35 +0000180 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000181 reply->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
Alexandre Julliardad47a301999-11-29 01:58:35 +0000182 release_object( timer );
183 }
184}
185
186/* open a handle to a timer */
187DECL_HANDLER(open_timer)
188{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000189 reply->handle = open_object( get_req_data(), get_req_data_size(),
190 &timer_ops, req->access, req->inherit );
Alexandre Julliardad47a301999-11-29 01:58:35 +0000191}
192
193/* set a waitable timer */
194DECL_HANDLER(set_timer)
195{
196 struct timer *timer;
197
198 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
199 TIMER_MODIFY_STATE, &timer_ops )))
200 {
201 set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
202 release_object( timer );
203 }
204}
205
206/* cancel a waitable timer */
207DECL_HANDLER(cancel_timer)
208{
209 struct timer *timer;
210
211 if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
212 TIMER_MODIFY_STATE, &timer_ops )))
213 {
214 cancel_timer( timer );
215 release_object( timer );
216 }
217}