2 * Kernel Services Thread
4 * Copyright 1999 Ulrich Weigand
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(timer
);
29 typedef struct _SERVICE
31 struct _SERVICE
*next
;
35 ULONG_PTR callback_arg
;
42 static HANDLE service_thread
;
43 static SERVICE
*service_first
;
44 static DWORD service_counter
;
46 /***********************************************************************
49 static DWORD CALLBACK
SERVICE_Loop( void *dummy
)
51 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
53 DWORD retval
= WAIT_FAILED
;
58 ULONG_PTR callback_arg
;
61 /* Check whether some condition is fulfilled */
63 HeapLock( GetProcessHeap() );
67 for ( s
= service_first
; s
; s
= s
->next
)
69 if (s
->disabled
) continue;
71 if ( retval
>= WAIT_OBJECT_0
&& retval
< WAIT_OBJECT_0
+ count
)
73 if ( handles
[retval
- WAIT_OBJECT_0
] == s
->object
)
75 retval
= WAIT_TIMEOUT
;
76 callback
= s
->callback
;
77 callback_arg
= s
->callback_arg
;
83 HeapUnlock( GetProcessHeap() );
85 /* If found, call callback routine */
89 callback( callback_arg
);
93 /* If not found, determine wait condition */
95 HeapLock( GetProcessHeap() );
98 for ( s
= service_first
; s
; s
= s
->next
)
100 if (s
->disabled
) continue;
102 if ( count
< MAXIMUM_WAIT_OBJECTS
)
103 handles
[count
++] = s
->object
;
106 HeapUnlock( GetProcessHeap() );
109 /* Wait until some condition satisfied */
111 TRACE("Waiting for %d objects\n", count
);
113 retval
= WaitForMultipleObjectsEx( count
, handles
, FALSE
, INFINITE
, TRUE
);
115 TRACE("Wait returned: %ld\n", retval
);
121 /***********************************************************************
122 * SERVICE_CreateServiceTable
124 static BOOL
SERVICE_CreateServiceTable( void )
126 /* service_thread must be set *BEFORE* calling CreateThread
127 * otherwise the thread cleanup service will cause an infinite recursion
130 service_thread
= INVALID_HANDLE_VALUE
;
131 service_thread
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)SERVICE_Loop
,
133 return (service_thread
!= 0);
136 /***********************************************************************
139 * Warning: the object supplied by the caller must not be closed. It'll
140 * be destroyed when the service is deleted. It's up to the caller
141 * to ensure that object will not be destroyed in between.
143 HANDLE
SERVICE_AddObject( HANDLE object
,
144 PAPCFUNC callback
, ULONG_PTR callback_arg
)
149 if ( !object
|| object
== INVALID_HANDLE_VALUE
|| !callback
)
150 return INVALID_HANDLE_VALUE
;
152 if (!service_thread
&& !SERVICE_CreateServiceTable()) return INVALID_HANDLE_VALUE
;
154 s
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SERVICE
) );
155 if ( !s
) return INVALID_HANDLE_VALUE
;
157 s
->callback
= callback
;
158 s
->callback_arg
= callback_arg
;
162 HeapLock( GetProcessHeap() );
164 s
->self
= handle
= (HANDLE
)++service_counter
;
165 s
->next
= service_first
;
168 HeapUnlock( GetProcessHeap() );
170 QueueUserAPC( NULL
, service_thread
, 0L );
175 /***********************************************************************
178 HANDLE
SERVICE_AddTimer( LONG rate
,
179 PAPCFUNC callback
, ULONG_PTR callback_arg
)
184 if ( !rate
|| !callback
)
185 return INVALID_HANDLE_VALUE
;
187 handle
= CreateWaitableTimerA( NULL
, FALSE
, NULL
);
188 if (!handle
) return INVALID_HANDLE_VALUE
;
191 when
.s
.LowPart
= when
.s
.HighPart
= 0;
192 if (!SetWaitableTimer( handle
, &when
, rate
, NULL
, NULL
, FALSE
))
194 CloseHandle( handle
);
195 return INVALID_HANDLE_VALUE
;
198 if ((ret
= SERVICE_AddObject( handle
, callback
, callback_arg
)) == INVALID_HANDLE_VALUE
)
200 CloseHandle( handle
);
201 return INVALID_HANDLE_VALUE
;
206 /***********************************************************************
209 BOOL
SERVICE_Delete( HANDLE service
)
211 HANDLE handle
= INVALID_HANDLE_VALUE
;
215 HeapLock( GetProcessHeap() );
217 for ( s
= &service_first
; *s
; s
= &(*s
)->next
)
219 if ( (*s
)->self
== service
)
221 handle
= (*s
)->object
;
223 HeapFree( GetProcessHeap(), 0, *s
);
230 HeapUnlock( GetProcessHeap() );
232 if ( handle
!= INVALID_HANDLE_VALUE
)
233 CloseHandle( handle
);
235 QueueUserAPC( NULL
, service_thread
, 0L );
240 /***********************************************************************
243 BOOL
SERVICE_Enable( HANDLE service
)
248 HeapLock( GetProcessHeap() );
250 for ( s
= service_first
; s
; s
= s
->next
)
252 if ( s
->self
== service
)
260 HeapUnlock( GetProcessHeap() );
262 QueueUserAPC( NULL
, service_thread
, 0L );
267 /***********************************************************************
270 BOOL
SERVICE_Disable( HANDLE service
)
275 HeapLock( GetProcessHeap() );
277 for ( s
= service_first
; s
; s
= s
->next
)
279 if ( s
->self
== service
)
287 HeapUnlock( GetProcessHeap() );
289 QueueUserAPC( NULL
, service_thread
, 0L );