Added notification format handling.
[wine/multimedia.git] / scheduler / services.c
blob0b874e3b1e40c523b71d2b6691d6ce609a0c2e09
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 "debugtools.h"
13 DEFAULT_DEBUG_CHANNEL(timer);
15 typedef struct _SERVICE
17 struct _SERVICE *next;
18 HANDLE self;
20 PAPCFUNC callback;
21 ULONG_PTR callback_arg;
23 BOOL disabled;
24 HANDLE object;
25 } SERVICE;
28 static HANDLE service_thread;
29 static SERVICE *service_first;
30 static DWORD service_counter;
32 /***********************************************************************
33 * SERVICE_Loop
35 static DWORD CALLBACK SERVICE_Loop( void *dummy )
37 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
38 int count = 0;
39 DWORD retval = WAIT_FAILED;
41 while ( TRUE )
43 PAPCFUNC callback;
44 ULONG_PTR callback_arg;
45 SERVICE *s;
47 /* Check whether some condition is fulfilled */
49 HeapLock( GetProcessHeap() );
51 callback = NULL;
52 callback_arg = 0L;
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;
64 break;
69 HeapUnlock( GetProcessHeap() );
71 /* If found, call callback routine */
73 if ( callback )
75 callback( callback_arg );
76 continue;
79 /* If not found, determine wait condition */
81 HeapLock( GetProcessHeap() );
83 count = 0;
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 );
104 return 0L;
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
114 * when installed
116 service_thread = INVALID_HANDLE_VALUE;
118 service_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
119 NULL, 0, NULL );
120 if ( service_thread == INVALID_HANDLE_VALUE )
122 service_thread = 0;
123 return FALSE;
125 return TRUE;
128 /***********************************************************************
129 * SERVICE_AddObject
131 * Warning: the object supplied by the caller must not be closed. It'll
132 * be destroyed when the service is deleted. It's up to the caller
133 * to ensure that object will not be destroyed in between.
135 HANDLE SERVICE_AddObject( HANDLE object,
136 PAPCFUNC callback, ULONG_PTR callback_arg )
138 SERVICE *s;
139 HANDLE handle;
141 if ( object == INVALID_HANDLE_VALUE || !callback )
142 return INVALID_HANDLE_VALUE;
144 if (!service_thread && !SERVICE_CreateServiceTable()) return INVALID_HANDLE_VALUE;
146 s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
147 if ( !s ) return INVALID_HANDLE_VALUE;
149 s->callback = callback;
150 s->callback_arg = callback_arg;
151 s->object = object;
152 s->disabled = FALSE;
154 HeapLock( GetProcessHeap() );
156 s->self = handle = (HANDLE)++service_counter;
157 s->next = service_first;
158 service_first = s;
160 HeapUnlock( GetProcessHeap() );
162 QueueUserAPC( NULL, service_thread, 0L );
164 return handle;
167 /***********************************************************************
168 * SERVICE_AddTimer
170 HANDLE SERVICE_AddTimer( LONG rate,
171 PAPCFUNC callback, ULONG_PTR callback_arg )
173 HANDLE handle, ret;
174 LARGE_INTEGER when;
176 if ( !rate || !callback )
177 return INVALID_HANDLE_VALUE;
179 handle = CreateWaitableTimerA( NULL, FALSE, NULL );
180 if (!handle) return INVALID_HANDLE_VALUE;
182 if (!rate) rate = 1;
183 when.s.LowPart = when.s.HighPart = 0;
184 if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
186 CloseHandle( handle );
187 return INVALID_HANDLE_VALUE;
190 if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
192 CloseHandle( handle );
193 return INVALID_HANDLE_VALUE;
195 return ret;
198 /***********************************************************************
199 * SERVICE_Delete
201 BOOL SERVICE_Delete( HANDLE service )
203 HANDLE handle = INVALID_HANDLE_VALUE;
204 BOOL retv = FALSE;
205 SERVICE **s, *next;
207 HeapLock( GetProcessHeap() );
209 for ( s = &service_first; *s; s = &(*s)->next )
211 if ( (*s)->self == service )
213 handle = (*s)->object;
214 next = (*s)->next;
215 HeapFree( GetProcessHeap(), 0, *s );
216 *s = next;
217 retv = TRUE;
218 break;
222 HeapUnlock( GetProcessHeap() );
224 if ( handle != INVALID_HANDLE_VALUE )
225 CloseHandle( handle );
227 QueueUserAPC( NULL, service_thread, 0L );
229 return retv;
232 /***********************************************************************
233 * SERVICE_Enable
235 BOOL SERVICE_Enable( HANDLE service )
237 BOOL retv = FALSE;
238 SERVICE *s;
240 HeapLock( GetProcessHeap() );
242 for ( s = service_first; s; s = s->next )
244 if ( s->self == service )
246 s->disabled = FALSE;
247 retv = TRUE;
248 break;
252 HeapUnlock( GetProcessHeap() );
254 QueueUserAPC( NULL, service_thread, 0L );
256 return retv;
259 /***********************************************************************
260 * SERVICE_Disable
262 BOOL SERVICE_Disable( HANDLE service )
264 BOOL retv = TRUE;
265 SERVICE *s;
267 HeapLock( GetProcessHeap() );
269 for ( s = service_first; s; s = s->next )
271 if ( s->self == service )
273 s->disabled = TRUE;
274 retv = TRUE;
275 break;
279 HeapUnlock( GetProcessHeap() );
281 QueueUserAPC( NULL, service_thread, 0L );
283 return retv;