blob: d2b6f316a437e1ef4235f0ea6573329b9745d457 [file] [log] [blame]
Ulrich Weigand7761cbe1999-04-11 15:01:20 +00001/*
2 * Kernel Services Thread
3 *
4 * Copyright 1999 Ulrich Weigand
5 */
6
7#include <sys/time.h>
8#include <unistd.h>
9
10#include "services.h"
Eric Pouech63c7cdf1999-06-12 08:24:23 +000011#include "process.h"
Alexandre Julliard15657091999-05-23 10:25:25 +000012#include "debugtools.h"
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000013
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000014DEFAULT_DEBUG_CHANNEL(timer)
15
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000016typedef struct _SERVICE
17{
Eric Pouech63c7cdf1999-06-12 08:24:23 +000018 struct _SERVICE *next;
19 HANDLE self;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000020
Eric Pouech63c7cdf1999-06-12 08:24:23 +000021 PAPCFUNC callback;
22 ULONG_PTR callback_arg;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000023
Alexandre Julliard000c9801999-12-13 01:42:03 +000024 BOOL disabled;
Eric Pouech63c7cdf1999-06-12 08:24:23 +000025 HANDLE object;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000026} SERVICE;
27
Eric Pouech63c7cdf1999-06-12 08:24:23 +000028typedef struct _SERVICETABLE
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000029{
Eric Pouech63c7cdf1999-06-12 08:24:23 +000030 HANDLE thread;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000031
Eric Pouech63c7cdf1999-06-12 08:24:23 +000032 SERVICE *first;
33 DWORD counter;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000034
35} SERVICETABLE;
36
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000037/***********************************************************************
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000038 * SERVICE_Loop
39 */
40static DWORD CALLBACK SERVICE_Loop( SERVICETABLE *service )
41{
Eric Pouech63c7cdf1999-06-12 08:24:23 +000042 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
43 int count = 0;
Eric Pouech63c7cdf1999-06-12 08:24:23 +000044 DWORD retval = WAIT_FAILED;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000045
46 while ( TRUE )
47 {
48 PAPCFUNC callback;
49 ULONG_PTR callback_arg;
50 SERVICE *s;
51
52 /* Check whether some condition is fulfilled */
53
Eric Pouech63c7cdf1999-06-12 08:24:23 +000054 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000055
56 callback = NULL;
57 callback_arg = 0L;
58 for ( s = service->first; s; s = s->next )
59 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000060 if (s->disabled) continue;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000061
Alexandre Julliard000c9801999-12-13 01:42:03 +000062 if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
Eric Pouech63c7cdf1999-06-12 08:24:23 +000063 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000064 if ( handles[retval - WAIT_OBJECT_0] == s->object )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000065 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000066 retval = WAIT_TIMEOUT;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000067 callback = s->callback;
68 callback_arg = s->callback_arg;
69 break;
70 }
Alexandre Julliard000c9801999-12-13 01:42:03 +000071 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000072 }
73
Eric Pouech63c7cdf1999-06-12 08:24:23 +000074 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000075
76 /* If found, call callback routine */
77
78 if ( callback )
79 {
Eric Pouech63c7cdf1999-06-12 08:24:23 +000080 callback( callback_arg );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000081 continue;
82 }
83
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000084 /* If not found, determine wait condition */
85
Eric Pouech63c7cdf1999-06-12 08:24:23 +000086 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000087
88 count = 0;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000089 for ( s = service->first; s; s = s->next )
90 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000091 if (s->disabled) continue;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000092
Alexandre Julliard000c9801999-12-13 01:42:03 +000093 if ( count < MAXIMUM_WAIT_OBJECTS )
94 handles[count++] = s->object;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000095 }
96
Eric Pouech63c7cdf1999-06-12 08:24:23 +000097 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000098
99
100 /* Wait until some condition satisfied */
101
Alexandre Julliard000c9801999-12-13 01:42:03 +0000102 TRACE("Waiting for %d objects\n", count );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000103
Alexandre Julliard000c9801999-12-13 01:42:03 +0000104 retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000105
Alexandre Julliard15657091999-05-23 10:25:25 +0000106 TRACE("Wait returned: %ld\n", retval );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000107 }
108
109 return 0L;
110}
111
112/***********************************************************************
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000113 * SERVICE_CreateServiceTable
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000114 */
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000115static BOOL SERVICE_CreateServiceTable( void )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000116{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000117 HANDLE thread;
118 SERVICETABLE *service_table;
119 PDB *pdb = PROCESS_Current();
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000120
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000121 service_table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICETABLE) );
122 if ( !service_table )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000123 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000124 return FALSE;
125 }
126
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000127 /* service_table field in PDB must be set *BEFORE* calling CreateThread
128 * otherwise the thread cleanup service will cause an infinite recursion
129 * when installed
130 */
131 pdb->service_table = service_table;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000132
133 thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000134 service_table, 0, NULL );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000135 if ( thread == INVALID_HANDLE_VALUE )
136 {
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000137 pdb->service_table = 0;
138 HeapFree( GetProcessHeap(), 0, service_table );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000139 return FALSE;
140 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000141
142 service_table->thread = thread;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000143
144 return TRUE;
145}
146
147/***********************************************************************
148 * SERVICE_AddObject
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000149 *
150 * Warning: the object supplied by the caller must not be closed. It'll
151 * be destroyed when the service is deleted. It's up to the caller
152 * to ensure that object will not be destroyed in between.
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000153 */
154HANDLE SERVICE_AddObject( HANDLE object,
155 PAPCFUNC callback, ULONG_PTR callback_arg )
156{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000157 SERVICE *s;
158 SERVICETABLE *service_table;
159 HANDLE handle;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000160
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000161 if ( object == INVALID_HANDLE_VALUE || !callback )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000162 return INVALID_HANDLE_VALUE;
163
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000164 if (PROCESS_Current()->service_table == 0 && !SERVICE_CreateServiceTable())
165 return INVALID_HANDLE_VALUE;
166 service_table = PROCESS_Current()->service_table;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000167
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000168 s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
169 if ( !s ) return INVALID_HANDLE_VALUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000170
171 s->callback = callback;
172 s->callback_arg = callback_arg;
173 s->object = object;
Alexandre Julliard000c9801999-12-13 01:42:03 +0000174 s->disabled = FALSE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000175
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000176 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000177
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000178 s->self = handle = (HANDLE)++service_table->counter;
179 s->next = service_table->first;
180 service_table->first = s;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000181
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000182 HeapUnlock( GetProcessHeap() );
183
184 QueueUserAPC( NULL, service_table->thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000185
186 return handle;
187}
188
189/***********************************************************************
190 * SERVICE_AddTimer
191 */
192HANDLE SERVICE_AddTimer( LONG rate,
193 PAPCFUNC callback, ULONG_PTR callback_arg )
194{
Alexandre Julliard000c9801999-12-13 01:42:03 +0000195 HANDLE handle, ret;
196 LARGE_INTEGER when;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000197
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000198 if ( !rate || !callback )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000199 return INVALID_HANDLE_VALUE;
200
Alexandre Julliard000c9801999-12-13 01:42:03 +0000201 handle = CreateWaitableTimerA( NULL, FALSE, NULL );
202 if (!handle) return INVALID_HANDLE_VALUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000203
Alexandre Julliard000c9801999-12-13 01:42:03 +0000204 rate = (rate + 500) / 1000; /* us -> ms */
205 if (!rate) rate = 1;
206 when.s.LowPart = when.s.HighPart = 0;
207 if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
208 {
209 CloseHandle( handle );
210 return INVALID_HANDLE_VALUE;
211 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000212
Alexandre Julliard000c9801999-12-13 01:42:03 +0000213 if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
214 {
215 CloseHandle( handle );
216 return INVALID_HANDLE_VALUE;
217 }
218 return ret;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000219}
220
221/***********************************************************************
222 * SERVICE_Delete
223 */
224BOOL SERVICE_Delete( HANDLE service )
225{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000226 HANDLE handle = INVALID_HANDLE_VALUE;
227 BOOL retv = FALSE;
228 SERVICE **s, *next;
229 SERVICETABLE *service_table;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000230
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000231 /* service table must have been created on previous SERVICE_Add??? call */
232 if ((service_table = PROCESS_Current()->service_table) == 0)
233 return retv;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000234
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000235 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000236
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000237 for ( s = &service_table->first; *s; s = &(*s)->next )
238 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000239 if ( (*s)->self == service )
240 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000241 handle = (*s)->object;
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000242 next = (*s)->next;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000243 HeapFree( GetProcessHeap(), 0, *s );
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000244 *s = next;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000245 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000246 break;
247 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000248 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000249
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000250 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000251
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000252 if ( handle != INVALID_HANDLE_VALUE )
253 CloseHandle( handle );
254
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000255 QueueUserAPC( NULL, service_table->thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000256
257 return retv;
258}
259
260/***********************************************************************
261 * SERVICE_Enable
262 */
263BOOL SERVICE_Enable( HANDLE service )
264{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000265 BOOL retv = FALSE;
266 SERVICE *s;
267 SERVICETABLE *service_table;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000268
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000269 /* service table must have been created on previous SERVICE_Add??? call */
270 if ((service_table = PROCESS_Current()->service_table) == 0)
271 return retv;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000272
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000273 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000274
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000275 for ( s = service_table->first; s; s = s->next )
276 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000277 if ( s->self == service )
278 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000279 s->disabled = FALSE;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000280 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000281 break;
282 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000283 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000284
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000285 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000286
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000287 QueueUserAPC( NULL, service_table->thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000288
289 return retv;
290}
291
292/***********************************************************************
293 * SERVICE_Disable
294 */
295BOOL SERVICE_Disable( HANDLE service )
296{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000297 BOOL retv = TRUE;
298 SERVICE *s;
299 SERVICETABLE *service_table;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000300
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000301 /* service table must have been created on previous SERVICE_Add??? call */
302 if ((service_table = PROCESS_Current()->service_table) == 0)
303 return retv;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000304
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000305 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000306
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000307 for ( s = service_table->first; s; s = s->next )
308 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000309 if ( s->self == service )
310 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000311 s->disabled = TRUE;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000312 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000313 break;
314 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000315 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000316
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000317 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000318
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000319 QueueUserAPC( NULL, service_table->thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000320
321 return retv;
322}
323
324