blob: fd156dd0da5e19fc63df3ccdeca0089aab61f320 [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"
Alexandre Julliard15657091999-05-23 10:25:25 +000011#include "debugtools.h"
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000012
Alexandre Julliard46733de2000-08-09 22:31:24 +000013DEFAULT_DEBUG_CHANNEL(timer);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000014
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000015typedef struct _SERVICE
16{
Eric Pouech63c7cdf1999-06-12 08:24:23 +000017 struct _SERVICE *next;
18 HANDLE self;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000019
Eric Pouech63c7cdf1999-06-12 08:24:23 +000020 PAPCFUNC callback;
21 ULONG_PTR callback_arg;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000022
Alexandre Julliard000c9801999-12-13 01:42:03 +000023 BOOL disabled;
Eric Pouech63c7cdf1999-06-12 08:24:23 +000024 HANDLE object;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000025} SERVICE;
26
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000027
Alexandre Julliard46733de2000-08-09 22:31:24 +000028static HANDLE service_thread;
29static SERVICE *service_first;
30static DWORD service_counter;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000031
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000032/***********************************************************************
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000033 * SERVICE_Loop
34 */
Alexandre Julliard46733de2000-08-09 22:31:24 +000035static DWORD CALLBACK SERVICE_Loop( void *dummy )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000036{
Eric Pouech63c7cdf1999-06-12 08:24:23 +000037 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
38 int count = 0;
Eric Pouech63c7cdf1999-06-12 08:24:23 +000039 DWORD retval = WAIT_FAILED;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000040
41 while ( TRUE )
42 {
43 PAPCFUNC callback;
44 ULONG_PTR callback_arg;
45 SERVICE *s;
46
47 /* Check whether some condition is fulfilled */
48
Eric Pouech63c7cdf1999-06-12 08:24:23 +000049 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000050
51 callback = NULL;
52 callback_arg = 0L;
Alexandre Julliard46733de2000-08-09 22:31:24 +000053 for ( s = service_first; s; s = s->next )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000054 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000055 if (s->disabled) continue;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000056
Alexandre Julliard000c9801999-12-13 01:42:03 +000057 if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
Eric Pouech63c7cdf1999-06-12 08:24:23 +000058 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000059 if ( handles[retval - WAIT_OBJECT_0] == s->object )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000060 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000061 retval = WAIT_TIMEOUT;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000062 callback = s->callback;
63 callback_arg = s->callback_arg;
64 break;
65 }
Alexandre Julliard000c9801999-12-13 01:42:03 +000066 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000067 }
68
Eric Pouech63c7cdf1999-06-12 08:24:23 +000069 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000070
71 /* If found, call callback routine */
72
73 if ( callback )
74 {
Eric Pouech63c7cdf1999-06-12 08:24:23 +000075 callback( callback_arg );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000076 continue;
77 }
78
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000079 /* If not found, determine wait condition */
80
Eric Pouech63c7cdf1999-06-12 08:24:23 +000081 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000082
83 count = 0;
Alexandre Julliard46733de2000-08-09 22:31:24 +000084 for ( s = service_first; s; s = s->next )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000085 {
Alexandre Julliard000c9801999-12-13 01:42:03 +000086 if (s->disabled) continue;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000087
Alexandre Julliard000c9801999-12-13 01:42:03 +000088 if ( count < MAXIMUM_WAIT_OBJECTS )
89 handles[count++] = s->object;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000090 }
91
Eric Pouech63c7cdf1999-06-12 08:24:23 +000092 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000093
94
95 /* Wait until some condition satisfied */
96
Alexandre Julliard000c9801999-12-13 01:42:03 +000097 TRACE("Waiting for %d objects\n", count );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +000098
Alexandre Julliard000c9801999-12-13 01:42:03 +000099 retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000100
Alexandre Julliard15657091999-05-23 10:25:25 +0000101 TRACE("Wait returned: %ld\n", retval );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000102 }
103
104 return 0L;
105}
106
107/***********************************************************************
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000108 * SERVICE_CreateServiceTable
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000109 */
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000110static BOOL SERVICE_CreateServiceTable( void )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000111{
Alexandre Julliard46733de2000-08-09 22:31:24 +0000112 /* service_thread must be set *BEFORE* calling CreateThread
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000113 * otherwise the thread cleanup service will cause an infinite recursion
114 * when installed
115 */
Alexandre Julliard46733de2000-08-09 22:31:24 +0000116 service_thread = INVALID_HANDLE_VALUE;
Alexandre Julliard46733de2000-08-09 22:31:24 +0000117 service_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
118 NULL, 0, NULL );
Josh DuBoisec33cd62001-01-17 21:50:17 +0000119 return (service_thread != 0);
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000120}
121
122/***********************************************************************
123 * SERVICE_AddObject
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000124 *
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.
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000128 */
129HANDLE SERVICE_AddObject( HANDLE object,
130 PAPCFUNC callback, ULONG_PTR callback_arg )
131{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000132 SERVICE *s;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000133 HANDLE handle;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000134
François Gouget1dac6ea2001-01-09 20:51:36 +0000135 if ( !object || object == INVALID_HANDLE_VALUE || !callback )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000136 return INVALID_HANDLE_VALUE;
137
Alexandre Julliard46733de2000-08-09 22:31:24 +0000138 if (!service_thread && !SERVICE_CreateServiceTable()) return INVALID_HANDLE_VALUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000139
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000140 s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
141 if ( !s ) return INVALID_HANDLE_VALUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000142
143 s->callback = callback;
144 s->callback_arg = callback_arg;
145 s->object = object;
Alexandre Julliard000c9801999-12-13 01:42:03 +0000146 s->disabled = FALSE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000147
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000148 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000149
Alexandre Julliard46733de2000-08-09 22:31:24 +0000150 s->self = handle = (HANDLE)++service_counter;
151 s->next = service_first;
152 service_first = s;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000153
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000154 HeapUnlock( GetProcessHeap() );
155
Alexandre Julliard46733de2000-08-09 22:31:24 +0000156 QueueUserAPC( NULL, service_thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000157
158 return handle;
159}
160
161/***********************************************************************
162 * SERVICE_AddTimer
163 */
164HANDLE SERVICE_AddTimer( LONG rate,
165 PAPCFUNC callback, ULONG_PTR callback_arg )
166{
Alexandre Julliard000c9801999-12-13 01:42:03 +0000167 HANDLE handle, ret;
168 LARGE_INTEGER when;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000169
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000170 if ( !rate || !callback )
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000171 return INVALID_HANDLE_VALUE;
172
Alexandre Julliard000c9801999-12-13 01:42:03 +0000173 handle = CreateWaitableTimerA( NULL, FALSE, NULL );
174 if (!handle) return INVALID_HANDLE_VALUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000175
Alexandre Julliard000c9801999-12-13 01:42:03 +0000176 if (!rate) rate = 1;
177 when.s.LowPart = when.s.HighPart = 0;
178 if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
179 {
180 CloseHandle( handle );
181 return INVALID_HANDLE_VALUE;
182 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000183
Alexandre Julliard000c9801999-12-13 01:42:03 +0000184 if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
185 {
186 CloseHandle( handle );
187 return INVALID_HANDLE_VALUE;
188 }
189 return ret;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000190}
191
192/***********************************************************************
193 * SERVICE_Delete
194 */
195BOOL SERVICE_Delete( HANDLE service )
196{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000197 HANDLE handle = INVALID_HANDLE_VALUE;
198 BOOL retv = FALSE;
199 SERVICE **s, *next;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000200
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000201 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000202
Alexandre Julliard46733de2000-08-09 22:31:24 +0000203 for ( s = &service_first; *s; s = &(*s)->next )
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000204 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000205 if ( (*s)->self == service )
206 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000207 handle = (*s)->object;
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000208 next = (*s)->next;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000209 HeapFree( GetProcessHeap(), 0, *s );
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000210 *s = next;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000211 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000212 break;
213 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000214 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000215
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000216 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000217
Ulrich Weigand70b2e381999-05-04 16:43:38 +0000218 if ( handle != INVALID_HANDLE_VALUE )
219 CloseHandle( handle );
220
Alexandre Julliard46733de2000-08-09 22:31:24 +0000221 QueueUserAPC( NULL, service_thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000222
223 return retv;
224}
225
226/***********************************************************************
227 * SERVICE_Enable
228 */
229BOOL SERVICE_Enable( HANDLE service )
230{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000231 BOOL retv = FALSE;
232 SERVICE *s;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000233
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000234 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000235
Alexandre Julliard46733de2000-08-09 22:31:24 +0000236 for ( s = service_first; s; s = s->next )
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000237 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000238 if ( s->self == service )
239 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000240 s->disabled = FALSE;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000241 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000242 break;
243 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000244 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000245
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000246 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000247
Alexandre Julliard46733de2000-08-09 22:31:24 +0000248 QueueUserAPC( NULL, service_thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000249
250 return retv;
251}
252
253/***********************************************************************
254 * SERVICE_Disable
255 */
256BOOL SERVICE_Disable( HANDLE service )
257{
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000258 BOOL retv = TRUE;
259 SERVICE *s;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000260
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000261 HeapLock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000262
Alexandre Julliard46733de2000-08-09 22:31:24 +0000263 for ( s = service_first; s; s = s->next )
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000264 {
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000265 if ( s->self == service )
266 {
Alexandre Julliard000c9801999-12-13 01:42:03 +0000267 s->disabled = TRUE;
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000268 retv = TRUE;
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000269 break;
270 }
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000271 }
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000272
Eric Pouech63c7cdf1999-06-12 08:24:23 +0000273 HeapUnlock( GetProcessHeap() );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000274
Alexandre Julliard46733de2000-08-09 22:31:24 +0000275 QueueUserAPC( NULL, service_thread, 0L );
Ulrich Weigand7761cbe1999-04-11 15:01:20 +0000276
277 return retv;
278}
279
280