Implement FC_STRUCTPAD2 for complex types.
[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 "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <stdarg.h>
30
31 #include "windef.h"
32 #include "winternl.h"
33
34 #include "file.h"
35 #include "handle.h"
36 #include "request.h"
37
38 struct timer
39 {
40     struct object        obj;       /* object header */
41     int                  manual;    /* manual reset */
42     int                  signaled;  /* current signaled state */
43     int                  period;    /* timer period in ms */
44     struct timeval       when;      /* next expiration */
45     struct timeout_user *timeout;   /* timeout user */
46     struct thread       *thread;    /* thread that set the APC function */
47     void                *callback;  /* callback APC function */
48     void                *arg;       /* callback argument */
49 };
50
51 static void timer_dump( struct object *obj, int verbose );
52 static int timer_signaled( struct object *obj, struct thread *thread );
53 static int timer_satisfied( struct object *obj, struct thread *thread );
54 static void timer_destroy( struct object *obj );
55
56 static const struct object_ops timer_ops =
57 {
58     sizeof(struct timer),      /* size */
59     timer_dump,                /* dump */
60     add_queue,                 /* add_queue */
61     remove_queue,              /* remove_queue */
62     timer_signaled,            /* signaled */
63     timer_satisfied,           /* satisfied */
64     no_signal,                 /* signal */
65     no_get_fd,                 /* get_fd */
66     no_lookup_name,            /* lookup_name */
67     no_close_handle,           /* close_handle */
68     timer_destroy              /* destroy */
69 };
70
71
72 /* create a timer object */
73 static struct timer *create_timer( const struct unicode_str *name, unsigned int attr,
74                                    int manual )
75 {
76     struct timer *timer;
77
78     if ((timer = create_named_object( sync_namespace, &timer_ops, name, attr )))
79     {
80         if (get_error() != STATUS_OBJECT_NAME_EXISTS)
81         {
82             /* initialize it if it didn't already exist */
83             timer->manual       = manual;
84             timer->signaled     = 0;
85             timer->when.tv_sec  = 0;
86             timer->when.tv_usec = 0;
87             timer->period       = 0;
88             timer->timeout      = NULL;
89             timer->thread       = NULL;
90         }
91     }
92     return timer;
93 }
94
95 /* callback on timer expiration */
96 static void timer_callback( void *private )
97 {
98     struct timer *timer = (struct timer *)private;
99
100     /* queue an APC */
101     if (timer->thread)
102     {
103         if (!thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0,
104                                (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg))
105         {
106             release_object( timer->thread );
107             timer->thread = NULL;
108         }
109     }
110
111     if (timer->period)  /* schedule the next expiration */
112     {
113         add_timeout( &timer->when, timer->period );
114         timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
115     }
116     else timer->timeout = NULL;
117
118     /* wake up waiters */
119     timer->signaled = 1;
120     wake_up( &timer->obj, 0 );
121 }
122
123 /* cancel a running timer */
124 static int cancel_timer( struct timer *timer )
125 {
126     int signaled = timer->signaled;
127
128     if (timer->timeout)
129     {
130         remove_timeout_user( timer->timeout );
131         timer->timeout = NULL;
132     }
133     if (timer->thread)
134     {
135         thread_cancel_apc( timer->thread, &timer->obj, 0 );
136         release_object( timer->thread );
137         timer->thread = NULL;
138     }
139     return signaled;
140 }
141
142 /* set the timer expiration and period */
143 static int set_timer( struct timer *timer, const abs_time_t *expire, int period,
144                       void *callback, void *arg )
145 {
146     int signaled = cancel_timer( timer );
147     if (timer->manual)
148     {
149         period = 0;  /* period doesn't make any sense for a manual timer */
150         timer->signaled = 0;
151     }
152     if (!expire->sec && !expire->usec)
153     {
154         /* special case: use now + period as first expiration */
155         gettimeofday( &timer->when, NULL );
156         add_timeout( &timer->when, period );
157     }
158     else
159     {
160         timer->when.tv_sec  = expire->sec;
161         timer->when.tv_usec = expire->usec;
162     }
163     timer->period       = period;
164     timer->callback     = callback;
165     timer->arg          = arg;
166     if (callback) timer->thread = (struct thread *)grab_object( current );
167     timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
168     return signaled;
169 }
170
171 static void timer_dump( struct object *obj, int verbose )
172 {
173     struct timer *timer = (struct timer *)obj;
174     assert( obj->ops == &timer_ops );
175     fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
176              timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
177     dump_object_name( &timer->obj );
178     fputc( '\n', stderr );
179 }
180
181 static int timer_signaled( struct object *obj, struct thread *thread )
182 {
183     struct timer *timer = (struct timer *)obj;
184     assert( obj->ops == &timer_ops );
185     return timer->signaled;
186 }
187
188 static int timer_satisfied( struct object *obj, struct thread *thread )
189 {
190     struct timer *timer = (struct timer *)obj;
191     assert( obj->ops == &timer_ops );
192     if (!timer->manual) timer->signaled = 0;
193     return 0;
194 }
195
196 static void timer_destroy( struct object *obj )
197 {
198     struct timer *timer = (struct timer *)obj;
199     assert( obj->ops == &timer_ops );
200
201     if (timer->timeout) remove_timeout_user( timer->timeout );
202     if (timer->thread) release_object( timer->thread );
203 }
204
205 /* create a timer */
206 DECL_HANDLER(create_timer)
207 {
208     struct timer *timer;
209     struct unicode_str name;
210
211     reply->handle = 0;
212     get_req_unicode_str( &name );
213     if ((timer = create_timer( &name, req->attributes, req->manual )))
214     {
215         reply->handle = alloc_handle( current->process, timer, req->access,
216                                       req->attributes & OBJ_INHERIT );
217         release_object( timer );
218     }
219 }
220
221 /* open a handle to a timer */
222 DECL_HANDLER(open_timer)
223 {
224     struct unicode_str name;
225
226     get_req_unicode_str( &name );
227     reply->handle = open_object( sync_namespace, &name, &timer_ops, req->access, req->attributes );
228 }
229
230 /* set a waitable timer */
231 DECL_HANDLER(set_timer)
232 {
233     struct timer *timer;
234
235     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
236                                                  TIMER_MODIFY_STATE, &timer_ops )))
237     {
238         reply->signaled = set_timer( timer, &req->expire, req->period, req->callback, req->arg );
239         release_object( timer );
240     }
241 }
242
243 /* cancel a waitable timer */
244 DECL_HANDLER(cancel_timer)
245 {
246     struct timer *timer;
247
248     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
249                                                  TIMER_MODIFY_STATE, &timer_ops )))
250     {
251         reply->signaled = cancel_timer( timer );
252         release_object( timer );
253     }
254 }
255
256 /* Get information on a waitable timer */
257 DECL_HANDLER(get_timer_info)
258 {
259     struct timer *timer;
260
261     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
262                                                  TIMER_QUERY_STATE, &timer_ops )))
263     {
264         reply->when.sec  = timer->when.tv_sec;
265         reply->when.usec = timer->when.tv_usec;
266         reply->signaled  = timer->signaled;
267         release_object( timer );
268     }
269 }