2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
11 #include "debugtools.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
;
26 ULONG_PTR callback_arg
;
33 struct timeval expire
;
47 static SERVICETABLE
*Service
= NULL
;
50 /***********************************************************************
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 /***********************************************************************
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 /***********************************************************************
72 static DWORD CALLBACK
SERVICE_Loop( SERVICETABLE
*service
)
74 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
76 DWORD timeout
= INFINITE
;
77 DWORD retval
= WAIT_FAILED
;
82 ULONG_PTR callback_arg
;
85 /* Check whether some condition is fulfilled */
87 struct timeval curTime
;
88 gettimeofday( &curTime
, NULL
);
90 HeapLock( service
->heap
);
94 for ( s
= service
->first
; s
; s
= s
->next
)
96 if ( s
->flags
& SERVICE_DISABLED
)
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 retval
= WAIT_TIMEOUT
;
104 callback
= s
->callback
;
105 callback_arg
= s
->callback_arg
;
109 if ( s
->flags
& SERVICE_USE_TIMEOUT
)
110 if ((s
->expire
.tv_sec
< curTime
.tv_sec
) ||
111 ((s
->expire
.tv_sec
== curTime
.tv_sec
) &&
112 (s
->expire
.tv_usec
<= curTime
.tv_usec
)))
114 SERVICE_AddTimeval( &s
->expire
, s
->rate
);
115 callback
= s
->callback
;
116 callback_arg
= s
->callback_arg
;
121 HeapUnlock( service
->heap
);
124 /* If found, call callback routine */
128 callback( callback_arg
);
133 /* If not found, determine wait condition */
135 HeapLock( service
->heap
);
139 for ( s
= service
->first
; s
; s
= s
->next
)
141 if ( s
->flags
& SERVICE_DISABLED
)
144 if ( s
->flags
& SERVICE_USE_OBJECT
)
145 if ( count
< MAXIMUM_WAIT_OBJECTS
)
146 handles
[count
++] = s
->object
;
148 if ( s
->flags
& SERVICE_USE_TIMEOUT
)
150 long delta
= SERVICE_DiffTimeval( &s
->expire
, &curTime
);
151 long time
= (delta
+ 999L) / 1000L;
152 if ( time
< 1 ) time
= 1;
153 if ( time
< timeout
) timeout
= time
;
157 HeapUnlock( service
->heap
);
160 /* Wait until some condition satisfied */
162 TRACE("Waiting for %d objects with timeout %ld\n",
165 retval
= WaitForMultipleObjectsEx( count
, handles
,
166 FALSE
, timeout
, TRUE
);
168 TRACE("Wait returned: %ld\n", retval
);
174 /***********************************************************************
177 BOOL
SERVICE_Init( void )
181 heap
= HeapCreate( HEAP_GROWABLE
, 0x1000, 0 );
182 if ( !heap
) return FALSE
;
184 Service
= HeapAlloc( heap
, HEAP_ZERO_MEMORY
, sizeof(SERVICETABLE
) );
191 Service
->heap
= heap
;
193 thread
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)SERVICE_Loop
,
195 if ( thread
== INVALID_HANDLE_VALUE
)
201 Service
->thread
= ConvertToGlobalHandle( thread
);
206 /***********************************************************************
209 void SERVICE_Exit( void )
211 TerminateThread( Service
->thread
, 0 );
214 /***********************************************************************
217 HANDLE
SERVICE_AddObject( HANDLE object
,
218 PAPCFUNC callback
, ULONG_PTR callback_arg
)
223 object
= ConvertToGlobalHandle( object
); /* FIXME */
225 if ( !Service
|| object
== INVALID_HANDLE_VALUE
|| !callback
)
226 return INVALID_HANDLE_VALUE
;
228 s
= HeapAlloc( Service
->heap
, HEAP_ZERO_MEMORY
, sizeof(SERVICE
) );
229 if ( !s
) return INVALID_HANDLE_VALUE
;
231 HeapLock( Service
->heap
);
233 s
->callback
= callback
;
234 s
->callback_arg
= callback_arg
;
236 s
->flags
= SERVICE_USE_OBJECT
;
238 s
->self
= handle
= (HANDLE
)++Service
->counter
;
239 s
->next
= Service
->first
;
242 HeapUnlock( Service
->heap
);
244 QueueUserAPC( NULL
, Service
->thread
, 0L );
249 /***********************************************************************
252 HANDLE
SERVICE_AddTimer( LONG rate
,
253 PAPCFUNC callback
, ULONG_PTR callback_arg
)
258 if ( !Service
|| !rate
|| !callback
)
259 return INVALID_HANDLE_VALUE
;
261 s
= HeapAlloc( Service
->heap
, HEAP_ZERO_MEMORY
, sizeof(SERVICE
) );
262 if ( !s
) return INVALID_HANDLE_VALUE
;
264 HeapLock( Service
->heap
);
266 s
->callback
= callback
;
267 s
->callback_arg
= callback_arg
;
269 s
->flags
= SERVICE_USE_TIMEOUT
;
271 gettimeofday( &s
->expire
, NULL
);
272 SERVICE_AddTimeval( &s
->expire
, s
->rate
);
274 s
->self
= handle
= (HANDLE
)++Service
->counter
;
275 s
->next
= Service
->first
;
278 HeapUnlock( Service
->heap
);
280 QueueUserAPC( NULL
, Service
->thread
, 0L );
285 /***********************************************************************
288 BOOL
SERVICE_Delete( HANDLE service
)
290 HANDLE handle
= INVALID_HANDLE_VALUE
;
294 if ( !Service
) return retv
;
296 HeapLock( Service
->heap
);
298 for ( s
= &Service
->first
; *s
; s
= &(*s
)->next
)
299 if ( (*s
)->self
== service
)
301 if ( (*s
)->flags
& SERVICE_USE_OBJECT
)
302 handle
= (*s
)->object
;
305 HeapFree( Service
->heap
, 0, *s
);
311 HeapUnlock( Service
->heap
);
313 if ( handle
!= INVALID_HANDLE_VALUE
)
314 CloseHandle( handle
);
316 QueueUserAPC( NULL
, Service
->thread
, 0L );
321 /***********************************************************************
324 BOOL
SERVICE_Enable( HANDLE service
)
329 if ( !Service
) return retv
;
331 HeapLock( Service
->heap
);
333 for ( s
= Service
->first
; s
; s
= s
->next
)
334 if ( s
->self
== service
)
336 if ( s
->flags
& SERVICE_DISABLED
)
338 s
->flags
&= ~SERVICE_DISABLED
;
340 if ( s
->flags
& SERVICE_USE_TIMEOUT
)
343 struct timeval curTime
;
344 gettimeofday( &curTime
, NULL
);
346 delta
= SERVICE_DiffTimeval( &s
->expire
, &curTime
);
348 SERVICE_AddTimeval( &s
->expire
,
349 (delta
/ s
->rate
) * s
->rate
);
356 HeapUnlock( Service
->heap
);
358 QueueUserAPC( NULL
, Service
->thread
, 0L );
363 /***********************************************************************
366 BOOL
SERVICE_Disable( HANDLE service
)
371 if ( !Service
) return retv
;
373 HeapLock( Service
->heap
);
375 for ( s
= Service
->first
; s
; s
= s
->next
)
376 if ( s
->self
== service
)
378 s
->flags
|= SERVICE_DISABLED
;
383 HeapUnlock( Service
->heap
);
385 QueueUserAPC( NULL
, Service
->thread
, 0L );