Moved poll handling to the generic part of the server objects.
[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 "winerror.h"
14
15 #include "handle.h"
16 #include "request.h"
17
18 /* FIXME: check values and move to standard header */
19 #define TIMER_MODIFY_STATE  0x0001
20 #define TIMER_QUERY_STATE   0x0002
21 #define TIMER_ALL_ACCESS    (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
22
23 struct timer
24 {
25     struct object        obj;       /* object header */
26     int                  manual;    /* manual reset */
27     int                  signaled;  /* current signaled state */
28     int                  period;    /* timer period in ms */
29     struct timeval       when;      /* next expiration */
30     struct timeout_user *timeout;   /* timeout user */
31     void                *callback;  /* callback APC function */
32     void                *arg;       /* callback argument */
33 };
34
35 static void timer_dump( struct object *obj, int verbose );
36 static int timer_signaled( struct object *obj, struct thread *thread );
37 static int timer_satisfied( struct object *obj, struct thread *thread );
38 static void timer_destroy( struct object *obj );
39
40 static const struct object_ops timer_ops =
41 {
42     sizeof(struct timer),      /* size */
43     timer_dump,                /* dump */
44     add_queue,                 /* add_queue */
45     remove_queue,              /* remove_queue */
46     timer_signaled,            /* signaled */
47     timer_satisfied,           /* satisfied */
48     NULL,                      /* get_poll_events */
49     NULL,                      /* poll_event */
50     no_read_fd,                /* get_read_fd */
51     no_write_fd,               /* get_write_fd */
52     no_flush,                  /* flush */
53     no_get_file_info,          /* get_file_info */
54     timer_destroy              /* destroy */
55 };
56
57
58 /* create a timer object */
59 static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
60 {
61     struct timer *timer;
62
63     if ((timer = create_named_object( &timer_ops, name, len )))
64     {
65         if (get_error() != ERROR_ALREADY_EXISTS)
66         {
67             /* initialize it if it didn't already exist */
68             timer->manual       = manual;
69             timer->signaled     = 0;
70             timer->when.tv_sec  = 0;
71             timer->when.tv_usec = 0;
72             timer->period       = 0;
73             timer->timeout      = NULL;
74         }
75     }
76     return timer;
77 }
78
79 /* callback on timer expiration */
80 static void timer_callback( void *private )
81 {
82     struct timer *timer = (struct timer *)private;
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 /* set the timer expiration and period */
97 static void set_timer( struct timer *timer, int sec, int usec, int period,
98                        void *callback, void *arg )
99 {
100     if (timer->manual)
101     {
102         period = 0;  /* period doesn't make any sense for a manual timer */
103         timer->signaled = 0;
104     }
105     if (timer->timeout) remove_timeout_user( timer->timeout );
106     if (!sec && !usec)
107     {
108         /* special case: use now + period as first expiration */
109         gettimeofday( &timer->when, 0 );
110         add_timeout( &timer->when, period );
111     }
112     else
113     {
114         timer->when.tv_sec  = sec;
115         timer->when.tv_usec = usec;
116     }
117     timer->period       = period;
118     timer->callback     = callback;
119     timer->arg          = arg;
120     timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
121 }
122
123 /* cancel a running timer */
124 static void cancel_timer( struct timer *timer )
125 {
126     if (timer->timeout)
127     {
128         remove_timeout_user( timer->timeout );
129         timer->timeout = NULL;
130     }
131 }
132
133 static void timer_dump( struct object *obj, int verbose )
134 {
135     struct timer *timer = (struct timer *)obj;
136     assert( obj->ops == &timer_ops );
137     fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
138              timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
139     dump_object_name( &timer->obj );
140     fputc( '\n', stderr );
141 }
142
143 static int timer_signaled( struct object *obj, struct thread *thread )
144 {
145     struct timer *timer = (struct timer *)obj;
146     assert( obj->ops == &timer_ops );
147     return timer->signaled;
148 }
149
150 static int timer_satisfied( struct object *obj, struct thread *thread )
151 {
152     struct timer *timer = (struct timer *)obj;
153     assert( obj->ops == &timer_ops );
154     if (!timer->manual) timer->signaled = 0;
155     return 0;
156 }
157
158 static void timer_destroy( struct object *obj )
159 {
160     struct timer *timer = (struct timer *)obj;
161     assert( obj->ops == &timer_ops );
162
163     if (timer->timeout) remove_timeout_user( timer->timeout );
164 }
165
166 /* create a timer */
167 DECL_HANDLER(create_timer)
168 {
169     size_t len = get_req_strlenW( req->name );
170     struct timer *timer;
171
172     req->handle = -1;
173     if ((timer = create_timer( req->name, len, req->manual )))
174     {
175         req->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
176         release_object( timer );
177     }
178 }
179
180 /* open a handle to a timer */
181 DECL_HANDLER(open_timer)
182 {
183     size_t len = get_req_strlenW( req->name );
184     req->handle = open_object( req->name, len, &timer_ops, req->access, req->inherit );
185 }
186
187 /* set a waitable timer */
188 DECL_HANDLER(set_timer)
189 {
190     struct timer *timer;
191
192     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
193                                                  TIMER_MODIFY_STATE, &timer_ops )))
194     {
195         set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
196         release_object( timer );
197     }
198 }
199
200 /* cancel a waitable timer */
201 DECL_HANDLER(cancel_timer)
202 {
203     struct timer *timer;
204
205     if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
206                                                  TIMER_MODIFY_STATE, &timer_ops )))
207     {
208         cancel_timer( timer );
209         release_object( timer );
210     }
211 }