Test for static was reversed.
[wine.git] / scheduler / services.c
blob5cb2a03d25eb64cb96e8376bc149809ae099e61e
1 /*
2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
5 */
7 #include <sys/time.h>
8 #include <unistd.h>
10 #include "services.h"
11 #include "debug.h"
13 DEFAULT_DEBUG_CHANNEL(timer)
16 #define SERVICE_USE_OBJECT 0x0001
17 #define SERVICE_USE_TIMEOUT 0x0002
18 #define SERVICE_DISABLED 0x8000
20 typedef struct _SERVICE
22 struct _SERVICE *next;
23 HANDLE self;
25 PAPCFUNC callback;
26 ULONG_PTR callback_arg;
28 int flags;
30 HANDLE object;
31 long rate;
33 struct timeval expire;
35 } SERVICE;
37 typedef struct
39 HANDLE heap;
40 HANDLE thread;
42 SERVICE *first;
43 DWORD counter;
45 } SERVICETABLE;
47 static SERVICETABLE *Service = NULL;
50 /***********************************************************************
51 * SERVICE_AddTimeval
53 static void SERVICE_AddTimeval( struct timeval *time, long delta )
55 delta += time->tv_usec;
56 time->tv_sec += delta / 1000000L;
57 time->tv_usec = delta % 1000000L;
60 /***********************************************************************
61 * SERVICE_DiffTimeval
63 static long SERVICE_DiffTimeval( struct timeval *time1, struct timeval *time2 )
65 return ( time1->tv_sec - time2->tv_sec ) * 1000000L
66 + ( time1->tv_usec - time2->tv_usec );
69 /***********************************************************************
70 * SERVICE_Loop
72 static DWORD CALLBACK SERVICE_Loop( SERVICETABLE *service )
74 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
75 int count = 0;
76 DWORD timeout = INFINITE;
77 DWORD retval = WAIT_FAILED;
79 while ( TRUE )
81 PAPCFUNC callback;
82 ULONG_PTR callback_arg;
83 SERVICE *s;
85 /* Check whether some condition is fulfilled */
87 struct timeval curTime;
88 gettimeofday( &curTime, NULL );
90 HeapLock( service->heap );
92 callback = NULL;
93 callback_arg = 0L;
94 for ( s = service->first; s; s = s->next )
96 if ( s->flags & SERVICE_DISABLED )
97 continue;
99 if ( s->flags & SERVICE_USE_OBJECT )
100 if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
101 if ( handles[retval - WAIT_OBJECT_0] == s->object )
103 callback = s->callback;
104 callback_arg = s->callback_arg;
105 break;
108 if ( s->flags & SERVICE_USE_TIMEOUT )
109 if ( timercmp( &s->expire, &curTime, < ) )
111 SERVICE_AddTimeval( &s->expire, s->rate );
112 callback = s->callback;
113 callback_arg = s->callback_arg;
114 break;
118 HeapUnlock( service->heap );
121 /* If found, call callback routine */
123 if ( callback )
125 callback( callback_arg );
126 continue;
130 /* If not found, determine wait condition */
132 HeapLock( service->heap );
134 count = 0;
135 timeout = INFINITE;
136 for ( s = service->first; s; s = s->next )
138 if ( s->flags & SERVICE_DISABLED )
139 continue;
141 if ( s->flags & SERVICE_USE_OBJECT )
142 handles[count++] = s->object;
144 if ( s->flags & SERVICE_USE_TIMEOUT )
146 long delta = SERVICE_DiffTimeval( &s->expire, &curTime );
147 long time = (delta + 999L) / 1000L;
148 if ( time < 1 ) time = 1;
149 if ( time < timeout ) timeout = time;
153 HeapUnlock( service->heap );
156 /* Wait until some condition satisfied */
158 TRACE( timer, "Waiting for %d objects with timeout %ld\n",
159 count, timeout );
161 retval = WaitForMultipleObjectsEx( count, handles,
162 FALSE, timeout, TRUE );
164 TRACE( timer, "Wait returned: %ld\n", retval );
167 return 0L;
170 /***********************************************************************
171 * SERVICE_Init
173 BOOL SERVICE_Init( void )
175 HANDLE heap, thread;
177 heap = HeapCreate( HEAP_GROWABLE, 0x1000, 0 );
178 if ( !heap ) return FALSE;
180 Service = HeapAlloc( heap, HEAP_ZERO_MEMORY, sizeof(SERVICETABLE) );
181 if ( !Service )
183 HeapDestroy( heap );
184 return FALSE;
187 Service->heap = heap;
189 thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
190 Service, 0, NULL );
191 if ( thread == INVALID_HANDLE_VALUE )
193 HeapDestroy( heap );
194 return FALSE;
197 Service->thread = ConvertToGlobalHandle( thread );
199 return TRUE;
202 /***********************************************************************
203 * SERVICE_AddObject
205 HANDLE SERVICE_AddObject( HANDLE object,
206 PAPCFUNC callback, ULONG_PTR callback_arg )
208 SERVICE *s;
209 HANDLE handle;
211 if ( !Service || object == INVALID_HANDLE_VALUE || !callback )
212 return INVALID_HANDLE_VALUE;
214 s = HeapAlloc( Service->heap, HEAP_ZERO_MEMORY, sizeof(SERVICE) );
215 if ( !s ) return INVALID_HANDLE_VALUE;
217 HeapLock( Service->heap );
219 s->callback = callback;
220 s->callback_arg = callback_arg;
221 s->object = object;
222 s->flags = SERVICE_USE_OBJECT;
224 s->self = handle = (HANDLE)++Service->counter;
225 s->next = Service->first;
226 Service->first = s;
228 HeapUnlock( Service->heap );
230 QueueUserAPC( NULL, Service->thread, 0L );
232 return handle;
235 /***********************************************************************
236 * SERVICE_AddTimer
238 HANDLE SERVICE_AddTimer( LONG rate,
239 PAPCFUNC callback, ULONG_PTR callback_arg )
241 SERVICE *s;
242 HANDLE handle;
244 if ( !Service || !rate || !callback )
245 return INVALID_HANDLE_VALUE;
247 s = HeapAlloc( Service->heap, HEAP_ZERO_MEMORY, sizeof(SERVICE) );
248 if ( !s ) return INVALID_HANDLE_VALUE;
250 HeapLock( Service->heap );
252 s->callback = callback;
253 s->callback_arg = callback_arg;
254 s->rate = rate;
255 s->flags = SERVICE_USE_TIMEOUT;
257 gettimeofday( &s->expire, NULL );
258 SERVICE_AddTimeval( &s->expire, s->rate );
260 s->self = handle = (HANDLE)++Service->counter;
261 s->next = Service->first;
262 Service->first = s;
264 HeapUnlock( Service->heap );
266 QueueUserAPC( NULL, Service->thread, 0L );
268 return handle;
271 /***********************************************************************
272 * SERVICE_Delete
274 BOOL SERVICE_Delete( HANDLE service )
276 BOOL retv = TRUE;
277 SERVICE **s;
279 if ( !Service ) return retv;
281 HeapLock( Service->heap );
283 for ( s = &Service->first; *s; s = &(*s)->next )
284 if ( (*s)->self == service )
286 *s = (*s)->next;
287 HeapFree( Service->heap, 0, *s );
288 retv = FALSE;
289 break;
292 HeapUnlock( Service->heap );
294 QueueUserAPC( NULL, Service->thread, 0L );
296 return retv;
299 /***********************************************************************
300 * SERVICE_Enable
302 BOOL SERVICE_Enable( HANDLE service )
304 BOOL retv = TRUE;
305 SERVICE *s;
307 if ( !Service ) return retv;
309 HeapLock( Service->heap );
311 for ( s = Service->first; s; s = s->next )
312 if ( s->self == service )
314 if ( s->flags & SERVICE_DISABLED )
316 s->flags &= ~SERVICE_DISABLED;
318 if ( s->flags & SERVICE_USE_TIMEOUT )
320 long delta;
321 struct timeval curTime;
322 gettimeofday( &curTime, NULL );
324 delta = SERVICE_DiffTimeval( &s->expire, &curTime );
325 if ( delta > 0 )
326 SERVICE_AddTimeval( &s->expire,
327 (delta / s->rate) * s->rate );
330 retv = FALSE;
331 break;
334 HeapUnlock( Service->heap );
336 QueueUserAPC( NULL, Service->thread, 0L );
338 return retv;
341 /***********************************************************************
342 * SERVICE_Disable
344 BOOL SERVICE_Disable( HANDLE service )
346 BOOL retv = TRUE;
347 SERVICE *s;
349 if ( !Service ) return retv;
351 HeapLock( Service->heap );
353 for ( s = Service->first; s; s = s->next )
354 if ( s->self == service )
356 s->flags |= SERVICE_DISABLED;
357 retv = FALSE;
358 break;
361 HeapUnlock( Service->heap );
363 QueueUserAPC( NULL, Service->thread, 0L );
365 return retv;