SERVICE_AddObject check for NULL handles in addition to
[wine] / scheduler / services.c
1 /*
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"
11 #include "debugtools.h"
12
13 DEFAULT_DEBUG_CHANNEL(timer);
14
15 typedef struct _SERVICE
16 {
17    struct _SERVICE      *next;
18    HANDLE               self;
19
20    PAPCFUNC             callback;
21    ULONG_PTR            callback_arg;
22
23    BOOL                 disabled;
24    HANDLE               object;
25 } SERVICE;
26
27
28 static HANDLE service_thread;
29 static SERVICE *service_first;
30 static DWORD service_counter;
31  
32 /***********************************************************************
33  *           SERVICE_Loop
34  */
35 static DWORD CALLBACK SERVICE_Loop( void *dummy )
36 {
37     HANDLE      handles[MAXIMUM_WAIT_OBJECTS];
38     int         count = 0;
39     DWORD       retval = WAIT_FAILED;
40
41     while ( TRUE )
42     {
43         PAPCFUNC callback;
44         ULONG_PTR callback_arg;
45         SERVICE *s;
46
47         /* Check whether some condition is fulfilled */
48
49         HeapLock( GetProcessHeap() );
50
51         callback = NULL;
52         callback_arg = 0L;
53         for ( s = service_first; s; s = s->next )
54         {
55             if (s->disabled) continue;
56
57             if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
58             {
59                 if ( handles[retval - WAIT_OBJECT_0] == s->object )
60                 {
61                     retval = WAIT_TIMEOUT;
62                     callback = s->callback;
63                     callback_arg = s->callback_arg;
64                     break;
65                 }
66             }
67         }
68
69         HeapUnlock( GetProcessHeap() );
70         
71         /* If found, call callback routine */
72
73         if ( callback )
74         {
75             callback( callback_arg );
76             continue;
77         }
78
79         /* If not found, determine wait condition */
80
81         HeapLock( GetProcessHeap() );
82
83         count = 0;
84         for ( s = service_first; s; s = s->next )
85         {
86             if (s->disabled) continue;
87
88             if ( count < MAXIMUM_WAIT_OBJECTS )
89                 handles[count++] = s->object;
90         }
91
92         HeapUnlock( GetProcessHeap() );
93
94
95         /* Wait until some condition satisfied */
96
97         TRACE("Waiting for %d objects\n", count );
98
99         retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
100
101         TRACE("Wait returned: %ld\n", retval );
102     }
103
104     return 0L;
105 }
106
107 /***********************************************************************
108  *           SERVICE_CreateServiceTable
109  */
110 static  BOOL    SERVICE_CreateServiceTable( void )
111 {
112     /* service_thread must be set *BEFORE* calling CreateThread
113      * otherwise the thread cleanup service will cause an infinite recursion
114      * when installed
115      */
116     service_thread = INVALID_HANDLE_VALUE;
117
118     service_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop, 
119                                    NULL, 0, NULL );
120     if ( service_thread == INVALID_HANDLE_VALUE )
121     {
122         service_thread = 0;
123         return FALSE;
124     }
125     return TRUE;
126 }
127
128 /***********************************************************************
129  *           SERVICE_AddObject
130  *
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.
134  */
135 HANDLE SERVICE_AddObject( HANDLE object, 
136                           PAPCFUNC callback, ULONG_PTR callback_arg )
137 {
138     SERVICE             *s;
139     HANDLE              handle;
140
141     if ( !object || object == INVALID_HANDLE_VALUE || !callback ) 
142         return INVALID_HANDLE_VALUE;
143
144     if (!service_thread && !SERVICE_CreateServiceTable()) return INVALID_HANDLE_VALUE;
145
146     s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
147     if ( !s ) return INVALID_HANDLE_VALUE;
148
149     s->callback = callback;
150     s->callback_arg = callback_arg;
151     s->object = object;
152     s->disabled = FALSE;
153
154     HeapLock( GetProcessHeap() );
155
156     s->self = handle = (HANDLE)++service_counter;
157     s->next = service_first;
158     service_first = s;
159
160     HeapUnlock( GetProcessHeap() );
161
162     QueueUserAPC( NULL, service_thread, 0L );
163
164     return handle;
165 }
166
167 /***********************************************************************
168  *           SERVICE_AddTimer
169  */
170 HANDLE SERVICE_AddTimer( LONG rate, 
171                          PAPCFUNC callback, ULONG_PTR callback_arg )
172 {
173     HANDLE handle, ret;
174     LARGE_INTEGER when;
175
176     if ( !rate || !callback ) 
177         return INVALID_HANDLE_VALUE;
178
179     handle = CreateWaitableTimerA( NULL, FALSE, NULL );
180     if (!handle) return INVALID_HANDLE_VALUE;
181
182     if (!rate) rate = 1;
183     when.s.LowPart = when.s.HighPart = 0;
184     if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
185     {
186         CloseHandle( handle );
187         return INVALID_HANDLE_VALUE;
188     }
189
190     if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
191     {
192         CloseHandle( handle );
193         return INVALID_HANDLE_VALUE;
194     }
195     return ret;
196 }
197
198 /***********************************************************************
199  *           SERVICE_Delete
200  */
201 BOOL SERVICE_Delete( HANDLE service )
202 {
203     HANDLE              handle = INVALID_HANDLE_VALUE;
204     BOOL                retv = FALSE;
205     SERVICE             **s, *next;
206
207     HeapLock( GetProcessHeap() );
208
209     for ( s = &service_first; *s; s = &(*s)->next )
210     {
211         if ( (*s)->self == service )
212         {
213             handle = (*s)->object;
214             next = (*s)->next;
215             HeapFree( GetProcessHeap(), 0, *s );
216             *s = next;
217             retv = TRUE;
218             break;
219         }
220     }
221
222     HeapUnlock( GetProcessHeap() );
223
224     if ( handle != INVALID_HANDLE_VALUE )
225         CloseHandle( handle );
226
227     QueueUserAPC( NULL, service_thread, 0L );
228
229     return retv;
230 }
231
232 /***********************************************************************
233  *           SERVICE_Enable
234  */
235 BOOL SERVICE_Enable( HANDLE service )
236 {
237     BOOL                retv = FALSE;
238     SERVICE             *s;
239
240     HeapLock( GetProcessHeap() );
241
242     for ( s = service_first; s; s = s->next ) 
243     {
244         if ( s->self == service )
245         {
246             s->disabled = FALSE;
247             retv = TRUE;
248             break;
249         }
250     }
251
252     HeapUnlock( GetProcessHeap() );
253
254     QueueUserAPC( NULL, service_thread, 0L );
255
256     return retv;
257 }
258
259 /***********************************************************************
260  *           SERVICE_Disable
261  */
262 BOOL SERVICE_Disable( HANDLE service )
263 {
264     BOOL                retv = TRUE;
265     SERVICE             *s;
266
267     HeapLock( GetProcessHeap() );
268
269     for ( s = service_first; s; s = s->next ) 
270     {
271         if ( s->self == service )
272         {
273             s->disabled = TRUE;
274             retv = TRUE;
275             break;
276         }
277     }
278
279     HeapUnlock( GetProcessHeap() );
280
281     QueueUserAPC( NULL, service_thread, 0L );
282
283     return retv;
284 }
285
286