2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
11 #include "debugtools.h"
13 DEFAULT_DEBUG_CHANNEL(timer);
15 typedef struct _SERVICE
17 struct _SERVICE *next;
21 ULONG_PTR callback_arg;
28 static HANDLE service_thread;
29 static SERVICE *service_first;
30 static DWORD service_counter;
32 /***********************************************************************
35 static DWORD CALLBACK SERVICE_Loop( void *dummy )
37 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
39 DWORD retval = WAIT_FAILED;
44 ULONG_PTR callback_arg;
47 /* Check whether some condition is fulfilled */
49 HeapLock( GetProcessHeap() );
53 for ( s = service_first; s; s = s->next )
55 if (s->disabled) continue;
57 if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
59 if ( handles[retval - WAIT_OBJECT_0] == s->object )
61 retval = WAIT_TIMEOUT;
62 callback = s->callback;
63 callback_arg = s->callback_arg;
69 HeapUnlock( GetProcessHeap() );
71 /* If found, call callback routine */
75 callback( callback_arg );
79 /* If not found, determine wait condition */
81 HeapLock( GetProcessHeap() );
84 for ( s = service_first; s; s = s->next )
86 if (s->disabled) continue;
88 if ( count < MAXIMUM_WAIT_OBJECTS )
89 handles[count++] = s->object;
92 HeapUnlock( GetProcessHeap() );
95 /* Wait until some condition satisfied */
97 TRACE("Waiting for %d objects\n", count );
99 retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
101 TRACE("Wait returned: %ld\n", retval );
107 /***********************************************************************
108 * SERVICE_CreateServiceTable
110 static BOOL SERVICE_CreateServiceTable( void )
112 /* service_thread must be set *BEFORE* calling CreateThread
113 * otherwise the thread cleanup service will cause an infinite recursion
116 service_thread = INVALID_HANDLE_VALUE;
117 service_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
119 return (service_thread != 0);
122 /***********************************************************************
125 * Warning: the object supplied by the caller must not be closed. It'll
126 * be destroyed when the service is deleted. It's up to the caller
127 * to ensure that object will not be destroyed in between.
129 HANDLE SERVICE_AddObject( HANDLE object,
130 PAPCFUNC callback, ULONG_PTR callback_arg )
135 if ( !object || object == INVALID_HANDLE_VALUE || !callback )
136 return INVALID_HANDLE_VALUE;
138 if (!service_thread && !SERVICE_CreateServiceTable()) return INVALID_HANDLE_VALUE;
140 s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
141 if ( !s ) return INVALID_HANDLE_VALUE;
143 s->callback = callback;
144 s->callback_arg = callback_arg;
148 HeapLock( GetProcessHeap() );
150 s->self = handle = (HANDLE)++service_counter;
151 s->next = service_first;
154 HeapUnlock( GetProcessHeap() );
156 QueueUserAPC( NULL, service_thread, 0L );
161 /***********************************************************************
164 HANDLE SERVICE_AddTimer( LONG rate,
165 PAPCFUNC callback, ULONG_PTR callback_arg )
170 if ( !rate || !callback )
171 return INVALID_HANDLE_VALUE;
173 handle = CreateWaitableTimerA( NULL, FALSE, NULL );
174 if (!handle) return INVALID_HANDLE_VALUE;
177 when.s.LowPart = when.s.HighPart = 0;
178 if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
180 CloseHandle( handle );
181 return INVALID_HANDLE_VALUE;
184 if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
186 CloseHandle( handle );
187 return INVALID_HANDLE_VALUE;
192 /***********************************************************************
195 BOOL SERVICE_Delete( HANDLE service )
197 HANDLE handle = INVALID_HANDLE_VALUE;
201 HeapLock( GetProcessHeap() );
203 for ( s = &service_first; *s; s = &(*s)->next )
205 if ( (*s)->self == service )
207 handle = (*s)->object;
209 HeapFree( GetProcessHeap(), 0, *s );
216 HeapUnlock( GetProcessHeap() );
218 if ( handle != INVALID_HANDLE_VALUE )
219 CloseHandle( handle );
221 QueueUserAPC( NULL, service_thread, 0L );
226 /***********************************************************************
229 BOOL SERVICE_Enable( HANDLE service )
234 HeapLock( GetProcessHeap() );
236 for ( s = service_first; s; s = s->next )
238 if ( s->self == service )
246 HeapUnlock( GetProcessHeap() );
248 QueueUserAPC( NULL, service_thread, 0L );
253 /***********************************************************************
256 BOOL SERVICE_Disable( HANDLE service )
261 HeapLock( GetProcessHeap() );
263 for ( s = service_first; s; s = s->next )
265 if ( s->self == service )
273 HeapUnlock( GetProcessHeap() );
275 QueueUserAPC( NULL, service_thread, 0L );