- fixed copy&paste bug (GENERIC_WRITE instead of GENERIC_READ)
[wine] / server / timer.c
1 /*
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
13 #include "winnt.h"
14 #include "handle.h"
15 #include "request.h"
16
17 struct 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 */
25     struct thread       *thread;    /* thread that set the APC function */
26     void                *callback;  /* callback APC function */
27     void                *arg;       /* callback argument */
28 };
29
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 );
34
35 static const struct object_ops timer_ops =
36 {
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 */
46     no_flush,                  /* flush */
47     no_get_file_info,          /* get_file_info */
48     timer_destroy              /* destroy */
49 };
50
51
52 /* create a timer object */
53 static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
54 {
55     struct timer *timer;
56
57     if ((timer = create_named_object( &timer_ops, name, len )))
58     {
59         if (get_error() != STATUS_OBJECT_NAME_COLLISION)
60         {
61             /* initialize it if it didn't already exist */
62             timer->manual       = manual;
63             timer->signaled     = 0;
64             timer->when.tv_sec  = 0;
65             timer->when.tv_usec = 0;
66             timer->period       = 0;
67             timer->timeout      = NULL;
68             timer->thread       = NULL;
69         }
70     }
71     return timer;
72 }
73
74 /* callback on timer expiration */
75 static void timer_callback( void *private )
76 {
77     struct timer *timer = (struct timer *)private;
78
79     /* queue an APC */
80     if (timer->thread)
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 );
83
84     if (timer->period)  /* schedule the next expiration */
85     {
86         add_timeout( &timer->when, timer->period );
87         timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
88     }
89     else timer->timeout = NULL;
90
91     /* wake up waiters */
92     timer->signaled = 1;
93     wake_up( &timer->obj, 0 );
94 }
95
96 /* cancel a running timer */
97 static void cancel_timer( struct timer *timer )
98 {
99     if (timer->timeout)
100     {
101         remove_timeout_user( timer->timeout );
102         timer->timeout = NULL;
103     }
104     if (timer->thread)
105     {
106         thread_cancel_apc( timer->thread, &timer->obj, 0 );
107         timer->thread = NULL;
108     }
109 }
110
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 )
114 {
115     cancel_timer( timer );
116     if (timer->manual)
117     {
118         period = 0;  /* period doesn't make any sense for a manual timer */
119         timer->signaled = 0;
120     }
121     if (!sec && !usec)
122     {
123         /* special case: use now + period as first expiration */
124         gettimeofday( &timer->when, 0 );
125         add_timeout( &timer->when, period );
126     }
127     else
128     {
129         timer->when.tv_sec  = sec;
130         timer->when.tv_usec = usec;
131     }
132     timer->period       = period;
133     timer->callback     = callback;
134     timer->arg          = arg;
135     if (callback) timer->thread = current;
136     timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
137 }
138
139 static void timer_dump( struct object *obj, int verbose )
140 {
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 );
147 }
148
149 static int timer_signaled( struct object *obj, struct thread *thread )
150 {
151     struct timer *timer = (struct timer *)obj;
152     assert( obj->ops == &timer_ops );
153     return timer->signaled;
154 }
155
156 static int timer_satisfied( struct object *obj, struct thread *thread )
157 {
158     struct timer *timer = (struct timer *)obj;
159     assert( obj->ops == &timer_ops );
160     if (!timer->manual) timer->signaled = 0;
161     return 0;
162 }
163
164 static void timer_destroy( struct object *obj )
165 {
166     struct timer *timer = (struct timer *)obj;
167     assert( obj->ops == &timer_ops );
168
169     if (timer->timeout) remove_timeout_user( timer->timeout );
170 }
171
172 /* create a timer */
173 DECL_HANDLER(create_timer)
174 {
175     struct timer *timer;
176
177     req->handle = 0;
178     if ((timer = create_timer( get_req_data(req), get_req_data_size(req), req->manual )))
179     {
180         req->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
181         release_object( timer );
182     }
183 }
184
185 /* open a handle to a timer */
186 DECL_HANDLER(open_timer)
187 {
188     req->handle = open_object( get_req_data(req), get_req_data_size(req),
189                                &timer_ops, req->access, req->inherit );
190 }
191
192 /* set a waitable timer */
193 DECL_HANDLER(set_timer)
194 {
195     struct timer *timer;
196
197     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
198                                                  TIMER_MODIFY_STATE, &timer_ops )))
199     {
200         set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
201         release_object( timer );
202     }
203 }
204
205 /* cancel a waitable timer */
206 DECL_HANDLER(cancel_timer)
207 {
208     struct timer *timer;
209
210     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
211                                                  TIMER_MODIFY_STATE, &timer_ops )))
212     {
213         cancel_timer( timer );
214         release_object( timer );
215     }
216 }