advapi32/service.c; patch 4/7: Basic implementation of service control
dispatcher
Alexander Yaworsky
yaworsky at migusoft.ru
Thu Nov 11 21:34:52 CST 2004
ChangeLog:
Basic implementation of service control dispatcher.
diff -urN out1/dlls/advapi32/service.c out2/dlls/advapi32/service.c
--- out1/dlls/advapi32/service.c 2004-11-12 01:20:12.000000000 +0600
+++ out2/dlls/advapi32/service.c 2004-11-12 01:22:33.000000000 +0600
@@ -40,6 +40,8 @@
'L','O','C','K',0};
static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
'S','E','B','_','%','s',0};
+static const WCHAR szServiceDispEventNameFmtW[] = {'A','D','V','A','P','I','_',
+ 'D','I','S','P','_','%','s',0};
struct SEB /* service environment block */
{ /* resides in service's shared memory object */
@@ -47,6 +49,11 @@
/* variable part of SEB contains service arguments */
};
+static HANDLE dispatcher_event; /* this is used by service thread to wakeup
+ * service control dispatcher when thread terminates */
+
+static struct service_thread_data *service; /* FIXME: this should be a list */
+
/******************************************************************************
* SC_HANDLEs
*/
@@ -283,7 +290,7 @@
/******************************************************************************
* build_arg_vectors
*
- * helper function for service control dispatcher
+ * helper function for start_new_service
*
* Allocate and initialize array of LPWSTRs to arguments in variable part
* of service environment block.
@@ -318,6 +325,10 @@
LPSERVICE_MAIN_FUNCTIONW service_main;
DWORD argc;
LPWSTR *argv;
+ HANDLE hServiceShmem;
+ struct SEB *seb;
+ HANDLE thread_handle;
+ BOOL terminated;
};
static DWORD WINAPI service_thread( LPVOID arg )
@@ -325,25 +336,38 @@
struct service_thread_data *data = arg;
data->service_main( data->argc, data->argv );
+ data->terminated = TRUE;
+ SetEvent( dispatcher_event );
return 0;
}
/******************************************************************************
- * service_ctrl_dispatcher
+ * dispose_service_thread_data
*
- * helper function for StartServiceCtrlDispatcherA/W
+ * helper function for service control dispatcher
*/
-static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
+static void dispose_service_thread_data( struct service_thread_data* thread_data )
+{
+ if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
+ if( thread_data->seb ) UnmapViewOfFile( thread_data->seb );
+ if( thread_data->hServiceShmem ) CloseHandle( thread_data->hServiceShmem );
+ HeapFree( GetProcessHeap(), 0, thread_data );
+}
+
+/******************************************************************************
+ * start_new_service
+ *
+ * helper function for service control dispatcher
+ */
+static struct service_thread_data*
+start_new_service( LPSERVICE_MAIN_FUNCTIONW service_main, BOOL ascii )
{
- HANDLE hServiceShmem = NULL;
- struct SEB *seb = NULL;
struct service_thread_data *thread_data;
unsigned int i;
- HANDLE thread;
thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
if( NULL == thread_data )
- return FALSE;
+ return NULL;
if( ! read_scm_lock_data( thread_data->service_name ) )
{
@@ -353,21 +377,21 @@
submitted against revision 1.45 and so preserved here.
*/
FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
- servent->lpServiceProc( 0, NULL );
+ service_main( 0, NULL );
HeapFree( GetProcessHeap(), 0, thread_data );
- return TRUE;
+ return NULL;
}
- seb = open_seb_shmem( thread_data->service_name, &hServiceShmem );
- if( NULL == seb )
+ thread_data->seb = open_seb_shmem( thread_data->service_name, &thread_data->hServiceShmem );
+ if( NULL == thread_data->seb )
goto error;
- thread_data->argv = build_arg_vectors( seb );
+ thread_data->argv = build_arg_vectors( thread_data->seb );
if( NULL == thread_data->argv )
goto error;
thread_data->argv[0] = thread_data->service_name;
- thread_data->argc = seb->argc + 1;
+ thread_data->argc = thread_data->seb->argc + 1;
if( ascii )
{
@@ -391,31 +415,80 @@
}
}
- /* start the service thread */
- thread_data->service_main = servent->lpServiceProc;
- thread = CreateThread( NULL, 0, service_thread, thread_data, 0, NULL );
- if( NULL == thread )
- goto error;
-
- /* FIXME: dispatch control requests */
- WaitForSingleObject( thread, INFINITE );
- CloseHandle( thread );
-
- HeapFree( GetProcessHeap(), 0, thread_data->argv );
- HeapFree( GetProcessHeap(), 0, thread_data );
- UnmapViewOfFile( seb );
- CloseHandle( hServiceShmem );
- return TRUE;
+ /* create service thread in suspended state
+ * to avoid race while caller handles return value */
+ thread_data->service_main = service_main;
+ thread_data->thread_handle = CreateThread( NULL, 0, service_thread,
+ thread_data, CREATE_SUSPENDED, NULL );
+ if( thread_data->thread_handle )
+ return thread_data;
error:
- if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
- if( seb ) UnmapViewOfFile( seb );
- if( hServiceShmem ) CloseHandle( hServiceShmem );
- HeapFree( GetProcessHeap(), 0, thread_data );
+ dispose_service_thread_data( thread_data );
return FALSE;
}
/******************************************************************************
+ * service_ctrl_dispatcher
+ */
+static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
+{
+ WCHAR object_name[ MAX_PATH ];
+
+ /* FIXME: if shared service, find entry by service name */
+
+ /* FIXME: move this into dispatcher loop */
+ service = start_new_service( servent->lpServiceProc, ascii );
+ if( NULL == service )
+ return FALSE;
+
+ ResumeThread( service->thread_handle );
+
+ /* create dispatcher event object */
+ /* FIXME: object name should be based on executable image path because
+ * this object is a dispatcher's entity; it is common for all services in the process */
+ snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, service->service_name );
+ dispatcher_event = CreateEventW( NULL, FALSE, FALSE, object_name );
+ if( NULL == dispatcher_event )
+ {
+ dispose_service_thread_data( service );
+ return FALSE;
+ }
+
+ if( ERROR_ALREADY_EXISTS == GetLastError() )
+ {
+ SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
+ CloseHandle( dispatcher_event );
+ return FALSE;
+ }
+
+ /* dispatcher loop */
+ for(;;)
+ {
+ WaitForSingleObject( dispatcher_event, INFINITE );
+
+ /* at first, look for terminated service thread
+ * FIXME: threads */
+ if( service->terminated )
+ {
+ TRACE("waiting for service thread shutdown\n");
+ WaitForSingleObject( service->thread_handle, INFINITE );
+ CloseHandle( service->thread_handle );
+ dispose_service_thread_data( service );
+ break;
+ }
+
+ /* FIXME: look for control requests */
+
+ /* FIXME: if shared service, check SCM lock object;
+ * if exists, a new service should be started */
+ }
+
+ CloseHandle( dispatcher_event );
+ return TRUE;
+}
+
+/******************************************************************************
* StartServiceCtrlDispatcherA [ADVAPI32.@]
*/
BOOL WINAPI
More information about the wine-patches
mailing list