2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
12 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(timer
)
16 typedef struct _SERVICE
18 struct _SERVICE
*next
;
22 ULONG_PTR callback_arg
;
28 typedef struct _SERVICETABLE
37 /***********************************************************************
40 static DWORD CALLBACK
SERVICE_Loop( SERVICETABLE
*service
)
42 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
44 DWORD retval
= WAIT_FAILED
;
49 ULONG_PTR callback_arg
;
52 /* Check whether some condition is fulfilled */
54 HeapLock( GetProcessHeap() );
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
;
74 HeapUnlock( GetProcessHeap() );
76 /* If found, call callback routine */
80 callback( callback_arg
);
84 /* If not found, determine wait condition */
86 HeapLock( GetProcessHeap() );
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
);
112 /***********************************************************************
113 * SERVICE_CreateServiceTable
115 static BOOL
SERVICE_CreateServiceTable( void )
118 SERVICETABLE
*service_table
;
119 PDB
*pdb
= PROCESS_Current();
121 service_table
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SERVICETABLE
) );
122 if ( !service_table
)
127 /* service_table field in PDB must be set *BEFORE* calling CreateThread
128 * otherwise the thread cleanup service will cause an infinite recursion
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
);
142 service_table
->thread
= thread
;
147 /***********************************************************************
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
)
158 SERVICETABLE
*service_table
;
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
;
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 );
189 /***********************************************************************
192 HANDLE
SERVICE_AddTimer( LONG rate
,
193 PAPCFUNC callback
, ULONG_PTR callback_arg
)
198 if ( !rate
|| !callback
)
199 return INVALID_HANDLE_VALUE
;
201 handle
= CreateWaitableTimerA( NULL
, FALSE
, NULL
);
202 if (!handle
) return INVALID_HANDLE_VALUE
;
204 rate
= (rate
+ 500) / 1000; /* us -> ms */
206 when
.s
.LowPart
= when
.s
.HighPart
= 0;
207 if (!SetWaitableTimer( handle
, &when
, rate
, NULL
, NULL
, FALSE
))
209 CloseHandle( handle
);
210 return INVALID_HANDLE_VALUE
;
213 if ((ret
= SERVICE_AddObject( handle
, callback
, callback_arg
)) == INVALID_HANDLE_VALUE
)
215 CloseHandle( handle
);
216 return INVALID_HANDLE_VALUE
;
221 /***********************************************************************
224 BOOL
SERVICE_Delete( HANDLE service
)
226 HANDLE handle
= INVALID_HANDLE_VALUE
;
229 SERVICETABLE
*service_table
;
231 /* service table must have been created on previous SERVICE_Add??? call */
232 if ((service_table
= PROCESS_Current()->service_table
) == 0)
235 HeapLock( GetProcessHeap() );
237 for ( s
= &service_table
->first
; *s
; s
= &(*s
)->next
)
239 if ( (*s
)->self
== service
)
241 handle
= (*s
)->object
;
243 HeapFree( GetProcessHeap(), 0, *s
);
250 HeapUnlock( GetProcessHeap() );
252 if ( handle
!= INVALID_HANDLE_VALUE
)
253 CloseHandle( handle
);
255 QueueUserAPC( NULL
, service_table
->thread
, 0L );
260 /***********************************************************************
263 BOOL
SERVICE_Enable( HANDLE service
)
267 SERVICETABLE
*service_table
;
269 /* service table must have been created on previous SERVICE_Add??? call */
270 if ((service_table
= PROCESS_Current()->service_table
) == 0)
273 HeapLock( GetProcessHeap() );
275 for ( s
= service_table
->first
; s
; s
= s
->next
)
277 if ( s
->self
== service
)
285 HeapUnlock( GetProcessHeap() );
287 QueueUserAPC( NULL
, service_table
->thread
, 0L );
292 /***********************************************************************
295 BOOL
SERVICE_Disable( HANDLE service
)
299 SERVICETABLE
*service_table
;
301 /* service table must have been created on previous SERVICE_Add??? call */
302 if ((service_table
= PROCESS_Current()->service_table
) == 0)
305 HeapLock( GetProcessHeap() );
307 for ( s
= service_table
->first
; s
; s
= s
->next
)
309 if ( s
->self
== service
)
317 HeapUnlock( GetProcessHeap() );
319 QueueUserAPC( NULL
, service_table
->thread
, 0L );