2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
11 #include "debugtools.h"
13 DEFAULT_DEBUG_CHANNEL(timer
);
15 typedef struct _SERVICE
17 struct _SERVICE
*next
;
21 ULONG_PTR callback_arg
;
28 static HANDLE service_thread
;
29 static SERVICE
*service_first
;
30 static DWORD service_counter
;
32 /***********************************************************************
35 static DWORD CALLBACK
SERVICE_Loop( void *dummy
)
37 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
39 DWORD retval
= WAIT_FAILED
;
44 ULONG_PTR callback_arg
;
47 /* Check whether some condition is fulfilled */
49 HeapLock( GetProcessHeap() );
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
;
69 HeapUnlock( GetProcessHeap() );
71 /* If found, call callback routine */
75 callback( callback_arg
);
79 /* If not found, determine wait condition */
81 HeapLock( GetProcessHeap() );
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
);
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
116 service_thread
= INVALID_HANDLE_VALUE
;
118 service_thread
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)SERVICE_Loop
,
120 if ( service_thread
== INVALID_HANDLE_VALUE
)
128 /***********************************************************************
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
)
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
;
154 HeapLock( GetProcessHeap() );
156 s
->self
= handle
= (HANDLE
)++service_counter
;
157 s
->next
= service_first
;
160 HeapUnlock( GetProcessHeap() );
162 QueueUserAPC( NULL
, service_thread
, 0L );
167 /***********************************************************************
170 HANDLE
SERVICE_AddTimer( LONG rate
,
171 PAPCFUNC callback
, ULONG_PTR callback_arg
)
176 if ( !rate
|| !callback
)
177 return INVALID_HANDLE_VALUE
;
179 handle
= CreateWaitableTimerA( NULL
, FALSE
, NULL
);
180 if (!handle
) return INVALID_HANDLE_VALUE
;
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
;
198 /***********************************************************************
201 BOOL
SERVICE_Delete( HANDLE service
)
203 HANDLE handle
= INVALID_HANDLE_VALUE
;
207 HeapLock( GetProcessHeap() );
209 for ( s
= &service_first
; *s
; s
= &(*s
)->next
)
211 if ( (*s
)->self
== service
)
213 handle
= (*s
)->object
;
215 HeapFree( GetProcessHeap(), 0, *s
);
222 HeapUnlock( GetProcessHeap() );
224 if ( handle
!= INVALID_HANDLE_VALUE
)
225 CloseHandle( handle
);
227 QueueUserAPC( NULL
, service_thread
, 0L );
232 /***********************************************************************
235 BOOL
SERVICE_Enable( HANDLE service
)
240 HeapLock( GetProcessHeap() );
242 for ( s
= service_first
; s
; s
= s
->next
)
244 if ( s
->self
== service
)
252 HeapUnlock( GetProcessHeap() );
254 QueueUserAPC( NULL
, service_thread
, 0L );
259 /***********************************************************************
262 BOOL
SERVICE_Disable( HANDLE service
)
267 HeapLock( GetProcessHeap() );
269 for ( s
= service_first
; s
; s
= s
->next
)
271 if ( s
->self
== service
)
279 HeapUnlock( GetProcessHeap() );
281 QueueUserAPC( NULL
, service_thread
, 0L );