Finish any pending WaitCommEvents if the event mask is set to 0.
[wine] / server / timer.c
1 /*
2  * Waitable timers management
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26
27 #include "winnt.h"
28 #include "handle.h"
29 #include "request.h"
30
31 struct timer
32 {
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 */
42 };
43
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 );
48
49 static const struct object_ops timer_ops =
50 {
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 */
60     no_flush,                  /* flush */
61     no_get_file_info,          /* get_file_info */
62     NULL,                      /* queue_async */
63     timer_destroy              /* destroy */
64 };
65
66
67 /* create a timer object */
68 static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
69 {
70     struct timer *timer;
71
72     if ((timer = create_named_object( &timer_ops, name, len )))
73     {
74         if (get_error() != STATUS_OBJECT_NAME_COLLISION)
75         {
76             /* initialize it if it didn't already exist */
77             timer->manual       = manual;
78             timer->signaled     = 0;
79             timer->when.tv_sec  = 0;
80             timer->when.tv_usec = 0;
81             timer->period       = 0;
82             timer->timeout      = NULL;
83             timer->thread       = NULL;
84         }
85     }
86     return timer;
87 }
88
89 /* callback on timer expiration */
90 static void timer_callback( void *private )
91 {
92     struct timer *timer = (struct timer *)private;
93
94     /* queue an APC */
95     if (timer->thread)
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 );
98
99     if (timer->period)  /* schedule the next expiration */
100     {
101         add_timeout( &timer->when, timer->period );
102         timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
103     }
104     else timer->timeout = NULL;
105
106     /* wake up waiters */
107     timer->signaled = 1;
108     wake_up( &timer->obj, 0 );
109 }
110
111 /* cancel a running timer */
112 static void cancel_timer( struct timer *timer )
113 {
114     if (timer->timeout)
115     {
116         remove_timeout_user( timer->timeout );
117         timer->timeout = NULL;
118     }
119     if (timer->thread)
120     {
121         thread_cancel_apc( timer->thread, &timer->obj, 0 );
122         timer->thread = NULL;
123     }
124 }
125
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 )
129 {
130     cancel_timer( timer );
131     if (timer->manual)
132     {
133         period = 0;  /* period doesn't make any sense for a manual timer */
134         timer->signaled = 0;
135     }
136     if (!sec && !usec)
137     {
138         /* special case: use now + period as first expiration */
139         gettimeofday( &timer->when, 0 );
140         add_timeout( &timer->when, period );
141     }
142     else
143     {
144         timer->when.tv_sec  = sec;
145         timer->when.tv_usec = usec;
146     }
147     timer->period       = period;
148     timer->callback     = callback;
149     timer->arg          = arg;
150     if (callback) timer->thread = current;
151     timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
152 }
153
154 static void timer_dump( struct object *obj, int verbose )
155 {
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 );
162 }
163
164 static int timer_signaled( struct object *obj, struct thread *thread )
165 {
166     struct timer *timer = (struct timer *)obj;
167     assert( obj->ops == &timer_ops );
168     return timer->signaled;
169 }
170
171 static int timer_satisfied( struct object *obj, struct thread *thread )
172 {
173     struct timer *timer = (struct timer *)obj;
174     assert( obj->ops == &timer_ops );
175     if (!timer->manual) timer->signaled = 0;
176     return 0;
177 }
178
179 static void timer_destroy( struct object *obj )
180 {
181     struct timer *timer = (struct timer *)obj;
182     assert( obj->ops == &timer_ops );
183
184     if (timer->timeout) remove_timeout_user( timer->timeout );
185 }
186
187 /* create a timer */
188 DECL_HANDLER(create_timer)
189 {
190     struct timer *timer;
191
192     reply->handle = 0;
193     if ((timer = create_timer( get_req_data(), get_req_data_size(), req->manual )))
194     {
195         reply->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
196         release_object( timer );
197     }
198 }
199
200 /* open a handle to a timer */
201 DECL_HANDLER(open_timer)
202 {
203     reply->handle = open_object( get_req_data(), get_req_data_size(),
204                                  &timer_ops, req->access, req->inherit );
205 }
206
207 /* set a waitable timer */
208 DECL_HANDLER(set_timer)
209 {
210     struct timer *timer;
211
212     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
213                                                  TIMER_MODIFY_STATE, &timer_ops )))
214     {
215         set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
216         release_object( timer );
217     }
218 }
219
220 /* cancel a waitable timer */
221 DECL_HANDLER(cancel_timer)
222 {
223     struct timer *timer;
224
225     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
226                                                  TIMER_MODIFY_STATE, &timer_ops )))
227     {
228         cancel_timer( timer );
229         release_object( timer );
230     }
231 }