Basic implementation of service control dispatcher.

This commit is contained in:
Alexander Yaworsky 2004-12-02 19:51:41 +00:00 committed by Alexandre Julliard
parent 7bfda49772
commit e6985ab3a5
1 changed files with 106 additions and 33 deletions

View File

@ -40,6 +40,8 @@ static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
'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 @@ struct SEB /* service environment block */
/* 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
*/
@ -280,7 +287,7 @@ static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
/******************************************************************************
* 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.
@ -315,6 +322,9 @@ struct service_thread_data
LPSERVICE_MAIN_FUNCTIONW service_main;
DWORD argc;
LPWSTR *argv;
HANDLE hServiceShmem;
struct SEB *seb;
HANDLE thread_handle;
};
static DWORD WINAPI service_thread( LPVOID arg )
@ -322,25 +332,37 @@ static DWORD WINAPI service_thread( LPVOID arg )
struct service_thread_data *data = arg;
data->service_main( data->argc, data->argv );
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 ) )
{
@ -350,21 +372,21 @@ static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii
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 )
{
@ -388,30 +410,81 @@ static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii
}
}
/* 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 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(;;)
{
DWORD ret;
WaitForSingleObject( dispatcher_event, INFINITE );
/* at first, look for terminated service thread
* FIXME: threads, if shared service */
if( !GetExitCodeThread( service->thread_handle, &ret ) )
ERR("Couldn't get thread exit code\n");
else if( ret != STILL_ACTIVE )
{
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.@]
*/