Basic implementation of service control dispatcher.
This commit is contained in:
parent
7bfda49772
commit
e6985ab3a5
|
@ -40,6 +40,8 @@ static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
|
||||||
'L','O','C','K',0};
|
'L','O','C','K',0};
|
||||||
static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
|
static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
|
||||||
'S','E','B','_','%','s',0};
|
'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 */
|
struct SEB /* service environment block */
|
||||||
{ /* resides in service's shared memory object */
|
{ /* resides in service's shared memory object */
|
||||||
|
@ -47,6 +49,11 @@ struct SEB /* service environment block */
|
||||||
/* variable part of SEB contains service arguments */
|
/* 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
|
* SC_HANDLEs
|
||||||
*/
|
*/
|
||||||
|
@ -280,7 +287,7 @@ static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* build_arg_vectors
|
* 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
|
* Allocate and initialize array of LPWSTRs to arguments in variable part
|
||||||
* of service environment block.
|
* of service environment block.
|
||||||
|
@ -315,6 +322,9 @@ struct service_thread_data
|
||||||
LPSERVICE_MAIN_FUNCTIONW service_main;
|
LPSERVICE_MAIN_FUNCTIONW service_main;
|
||||||
DWORD argc;
|
DWORD argc;
|
||||||
LPWSTR *argv;
|
LPWSTR *argv;
|
||||||
|
HANDLE hServiceShmem;
|
||||||
|
struct SEB *seb;
|
||||||
|
HANDLE thread_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DWORD WINAPI service_thread( LPVOID arg )
|
static DWORD WINAPI service_thread( LPVOID arg )
|
||||||
|
@ -322,25 +332,37 @@ static DWORD WINAPI service_thread( LPVOID arg )
|
||||||
struct service_thread_data *data = arg;
|
struct service_thread_data *data = arg;
|
||||||
|
|
||||||
data->service_main( data->argc, data->argv );
|
data->service_main( data->argc, data->argv );
|
||||||
|
SetEvent( dispatcher_event );
|
||||||
return 0;
|
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;
|
struct service_thread_data *thread_data;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
HANDLE thread;
|
|
||||||
|
|
||||||
thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
|
thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
|
||||||
if( NULL == thread_data )
|
if( NULL == thread_data )
|
||||||
return FALSE;
|
return NULL;
|
||||||
|
|
||||||
if( ! read_scm_lock_data( thread_data->service_name ) )
|
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.
|
submitted against revision 1.45 and so preserved here.
|
||||||
*/
|
*/
|
||||||
FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
|
FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
|
||||||
servent->lpServiceProc( 0, NULL );
|
service_main( 0, NULL );
|
||||||
HeapFree( GetProcessHeap(), 0, thread_data );
|
HeapFree( GetProcessHeap(), 0, thread_data );
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
seb = open_seb_shmem( thread_data->service_name, &hServiceShmem );
|
thread_data->seb = open_seb_shmem( thread_data->service_name, &thread_data->hServiceShmem );
|
||||||
if( NULL == seb )
|
if( NULL == thread_data->seb )
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
thread_data->argv = build_arg_vectors( seb );
|
thread_data->argv = build_arg_vectors( thread_data->seb );
|
||||||
if( NULL == thread_data->argv )
|
if( NULL == thread_data->argv )
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
thread_data->argv[0] = thread_data->service_name;
|
thread_data->argv[0] = thread_data->service_name;
|
||||||
thread_data->argc = seb->argc + 1;
|
thread_data->argc = thread_data->seb->argc + 1;
|
||||||
|
|
||||||
if( ascii )
|
if( ascii )
|
||||||
{
|
{
|
||||||
|
@ -388,30 +410,81 @@ static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start the service thread */
|
/* create service thread in suspended state
|
||||||
thread_data->service_main = servent->lpServiceProc;
|
* to avoid race while caller handles return value */
|
||||||
thread = CreateThread( NULL, 0, service_thread, thread_data, 0, NULL );
|
thread_data->service_main = service_main;
|
||||||
if( NULL == thread )
|
thread_data->thread_handle = CreateThread( NULL, 0, service_thread,
|
||||||
goto error;
|
thread_data, CREATE_SUSPENDED, NULL );
|
||||||
|
if( thread_data->thread_handle )
|
||||||
/* FIXME: dispatch control requests */
|
return thread_data;
|
||||||
WaitForSingleObject( thread, INFINITE );
|
|
||||||
CloseHandle( thread );
|
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, thread_data->argv );
|
|
||||||
HeapFree( GetProcessHeap(), 0, thread_data );
|
|
||||||
UnmapViewOfFile( seb );
|
|
||||||
CloseHandle( hServiceShmem );
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
|
dispose_service_thread_data( thread_data );
|
||||||
if( seb ) UnmapViewOfFile( seb );
|
|
||||||
if( hServiceShmem ) CloseHandle( hServiceShmem );
|
|
||||||
HeapFree( GetProcessHeap(), 0, thread_data );
|
|
||||||
return FALSE;
|
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.@]
|
* StartServiceCtrlDispatcherA [ADVAPI32.@]
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue