StgOpenStorage16: correct arguments to the CreateFile call.
[wine.git] / scheduler / services.c
blob8cc45feee0c6aa400c5e85b5b6d34815dbf44383
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 "process.h"
12 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(timer)
16 typedef struct _SERVICE
18 struct _SERVICE *next;
19 HANDLE self;
21 PAPCFUNC callback;
22 ULONG_PTR callback_arg;
24 BOOL disabled;
25 HANDLE object;
26 } SERVICE;
28 typedef struct _SERVICETABLE
30 HANDLE thread;
32 SERVICE *first;
33 DWORD counter;
35 } SERVICETABLE;
37 /***********************************************************************
38 * SERVICE_Loop
40 static DWORD CALLBACK SERVICE_Loop( SERVICETABLE *service )
42 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
43 int count = 0;
44 DWORD retval = WAIT_FAILED;
46 while ( TRUE )
48 PAPCFUNC callback;
49 ULONG_PTR callback_arg;
50 SERVICE *s;
52 /* Check whether some condition is fulfilled */
54 HeapLock( GetProcessHeap() );
56 callback = NULL;
57 callback_arg = 0L;
58 for ( s = service->first; s; s = s->next )
60 if (s->disabled) continue;
62 if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
64 if ( handles[retval - WAIT_OBJECT_0] == s->object )
66 retval = WAIT_TIMEOUT;
67 callback = s->callback;
68 callback_arg = s->callback_arg;
69 break;
74 HeapUnlock( GetProcessHeap() );
76 /* If found, call callback routine */
78 if ( callback )
80 callback( callback_arg );
81 continue;
84 /* If not found, determine wait condition */
86 HeapLock( GetProcessHeap() );
88 count = 0;
89 for ( s = service->first; s; s = s->next )
91 if (s->disabled) continue;
93 if ( count < MAXIMUM_WAIT_OBJECTS )
94 handles[count++] = s->object;
97 HeapUnlock( GetProcessHeap() );
100 /* Wait until some condition satisfied */
102 TRACE("Waiting for %d objects\n", count );
104 retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
106 TRACE("Wait returned: %ld\n", retval );
109 return 0L;
112 /***********************************************************************
113 * SERVICE_CreateServiceTable
115 static BOOL SERVICE_CreateServiceTable( void )
117 HANDLE thread;
118 SERVICETABLE *service_table;
119 PDB *pdb = PROCESS_Current();
121 service_table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICETABLE) );
122 if ( !service_table )
124 return FALSE;
127 /* 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
131 pdb->service_table = service_table;
133 thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
134 service_table, 0, NULL );
135 if ( thread == INVALID_HANDLE_VALUE )
137 pdb->service_table = 0;
138 HeapFree( GetProcessHeap(), 0, service_table );
139 return FALSE;
142 service_table->thread = thread;
144 return TRUE;
147 /***********************************************************************
148 * SERVICE_AddObject
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.
154 HANDLE SERVICE_AddObject( HANDLE object,
155 PAPCFUNC callback, ULONG_PTR callback_arg )
157 SERVICE *s;
158 SERVICETABLE *service_table;
159 HANDLE handle;
161 if ( object == INVALID_HANDLE_VALUE || !callback )
162 return INVALID_HANDLE_VALUE;
164 if (PROCESS_Current()->service_table == 0 && !SERVICE_CreateServiceTable())
165 return INVALID_HANDLE_VALUE;
166 service_table = PROCESS_Current()->service_table;
168 s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
169 if ( !s ) return INVALID_HANDLE_VALUE;
171 s->callback = callback;
172 s->callback_arg = callback_arg;
173 s->object = object;
174 s->disabled = FALSE;
176 HeapLock( GetProcessHeap() );
178 s->self = handle = (HANDLE)++service_table->counter;
179 s->next = service_table->first;
180 service_table->first = s;
182 HeapUnlock( GetProcessHeap() );
184 QueueUserAPC( NULL, service_table->thread, 0L );
186 return handle;
189 /***********************************************************************
190 * SERVICE_AddTimer
192 HANDLE SERVICE_AddTimer( LONG rate,
193 PAPCFUNC callback, ULONG_PTR callback_arg )
195 HANDLE handle, ret;
196 LARGE_INTEGER when;
198 if ( !rate || !callback )
199 return INVALID_HANDLE_VALUE;
201 handle = CreateWaitableTimerA( NULL, FALSE, NULL );
202 if (!handle) return INVALID_HANDLE_VALUE;
204 if (!rate) rate = 1;
205 when.s.LowPart = when.s.HighPart = 0;
206 if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
208 CloseHandle( handle );
209 return INVALID_HANDLE_VALUE;
212 if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
214 CloseHandle( handle );
215 return INVALID_HANDLE_VALUE;
217 return ret;
220 /***********************************************************************
221 * SERVICE_Delete
223 BOOL SERVICE_Delete( HANDLE service )
225 HANDLE handle = INVALID_HANDLE_VALUE;
226 BOOL retv = FALSE;
227 SERVICE **s, *next;
228 SERVICETABLE *service_table;
230 /* service table must have been created on previous SERVICE_Add??? call */
231 if ((service_table = PROCESS_Current()->service_table) == 0)
232 return retv;
234 HeapLock( GetProcessHeap() );
236 for ( s = &service_table->first; *s; s = &(*s)->next )
238 if ( (*s)->self == service )
240 handle = (*s)->object;
241 next = (*s)->next;
242 HeapFree( GetProcessHeap(), 0, *s );
243 *s = next;
244 retv = TRUE;
245 break;
249 HeapUnlock( GetProcessHeap() );
251 if ( handle != INVALID_HANDLE_VALUE )
252 CloseHandle( handle );
254 QueueUserAPC( NULL, service_table->thread, 0L );
256 return retv;
259 /***********************************************************************
260 * SERVICE_Enable
262 BOOL SERVICE_Enable( HANDLE service )
264 BOOL retv = FALSE;
265 SERVICE *s;
266 SERVICETABLE *service_table;
268 /* service table must have been created on previous SERVICE_Add??? call */
269 if ((service_table = PROCESS_Current()->service_table) == 0)
270 return retv;
272 HeapLock( GetProcessHeap() );
274 for ( s = service_table->first; s; s = s->next )
276 if ( s->self == service )
278 s->disabled = FALSE;
279 retv = TRUE;
280 break;
284 HeapUnlock( GetProcessHeap() );
286 QueueUserAPC( NULL, service_table->thread, 0L );
288 return retv;
291 /***********************************************************************
292 * SERVICE_Disable
294 BOOL SERVICE_Disable( HANDLE service )
296 BOOL retv = TRUE;
297 SERVICE *s;
298 SERVICETABLE *service_table;
300 /* service table must have been created on previous SERVICE_Add??? call */
301 if ((service_table = PROCESS_Current()->service_table) == 0)
302 return retv;
304 HeapLock( GetProcessHeap() );
306 for ( s = service_table->first; s; s = s->next )
308 if ( s->self == service )
310 s->disabled = TRUE;
311 retv = TRUE;
312 break;
316 HeapUnlock( GetProcessHeap() );
318 QueueUserAPC( NULL, service_table->thread, 0L );
320 return retv;