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