[Wine-patches] [5/23] winedevice: Load drivers into one process.
Alexander Morozov
=?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Пн Янв 19 18:23:08 MSK 2009
For eterhack branch
----------- следующая часть -----------
From 86c901427b3c75e57bf60523bcd3a2b253279772 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 12 Jan 2009 14:23:09 +0300
Subject: [PATCH] winedevice: Load drivers into one process.
---
programs/winedevice/device.c | 318 +++++++++++++++++++++++++++++++++++-------
1 files changed, 268 insertions(+), 50 deletions(-)
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index ac988e1..adf61a4 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -46,13 +46,19 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
extern DEVICE_OBJECT * CDECL __wine_usbhub_get_pdo( UCHAR *pdo_info );
extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
+extern HANDLE CDECL __wine_make_process_system(void);
+#define EVENT_NAME_LEN (30 * sizeof(WCHAR))
+
+static const WCHAR pipe_nameW[] = {'\\','\\','.','\\','p','i','p','e',
+ '\\','w','i','n','e','d','e','v','i','c','e',0};
+static const WCHAR winedevice_mutexW[] = {'_','_','w','i','n','e','_',
+ 'W','i','n','e','d','e','v','i','c','e',0};
+
+/* these variables are used only by "winedevice driver_name" */
static WCHAR *driver_name;
static SERVICE_STATUS_HANDLE service_handle;
-static HKEY driver_hkey;
static HANDLE stop_event;
-static DRIVER_OBJECT driver_obj;
-static DRIVER_EXTENSION driver_extension;
/* find the LDR_MODULE corresponding to the driver module */
static LDR_MODULE *find_ldr_module( HMODULE module )
@@ -133,7 +139,9 @@ error:
}
/* call the driver init entry point */
-static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname )
+static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname,
+ const WCHAR *drv_name, PDRIVER_OBJECT driver_obj,
+ PDRIVER_EXTENSION driver_extension )
{
unsigned int i;
NTSTATUS status;
@@ -141,37 +149,38 @@ static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname )
if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS;
- driver_obj.Size = sizeof(driver_obj);
- driver_obj.DriverSection = find_ldr_module( module );
- driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);
- driver_obj.DriverExtension = &driver_extension;
+ driver_obj->Size = sizeof(DRIVER_OBJECT);
+ driver_obj->DriverSection = find_ldr_module( module );
+ driver_obj->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);
+ driver_obj->DriverExtension = driver_extension;
- driver_extension.DriverObject = &driver_obj;
- driver_extension.ServiceKeyName = *keyname;
+ driver_extension->DriverObject = driver_obj;
+ driver_extension->ServiceKeyName = *keyname;
if (WINE_TRACE_ON(relay))
WINE_DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(),
- driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer) );
+ driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname->Buffer) );
- status = driver_obj.DriverInit( &driver_obj, keyname );
+ status = driver_obj->DriverInit( driver_obj, keyname );
if (WINE_TRACE_ON(relay))
WINE_DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(),
- driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer), status );
+ driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname->Buffer), status );
- WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver_obj );
- WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit );
- WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo );
- WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload );
- WINE_TRACE( "- AddDevice = %p\n", driver_extension.AddDevice );
+ WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(drv_name), driver_obj );
+ WINE_TRACE( "- DriverInit = %p\n", driver_obj->DriverInit );
+ WINE_TRACE( "- DriverStartIo = %p\n", driver_obj->DriverStartIo );
+ WINE_TRACE( "- DriverUnload = %p\n", driver_obj->DriverUnload );
+ WINE_TRACE( "- AddDevice = %p\n", driver_extension->AddDevice );
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
- WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] );
+ WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj->MajorFunction[i] );
return status;
}
/* load the .sys module for a device driver */
-static BOOL load_driver(void)
+static HMODULE load_driver( const WCHAR *drv_name, PDRIVER_OBJECT driver_obj,
+ PDRIVER_EXTENSION driver_extension )
{
static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
static const WCHAR postfixW[] = {'.','s','y','s',0};
@@ -183,20 +192,22 @@ static BOOL load_driver(void)
'\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
'\\','S','e','r','v','i','c','e','s','\\',0};
+ HKEY driver_hkey;
UNICODE_STRING keypath;
HMODULE module;
LPWSTR path = NULL, str;
DWORD type, size;
+ NTSTATUS status;
- str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) );
+ str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(drv_name)*sizeof(WCHAR) );
lstrcpyW( str, servicesW );
- lstrcatW( str, driver_name );
+ lstrcatW( str, drv_name );
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, str + 18 /* skip \registry\machine */, &driver_hkey ))
{
WINE_ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(str), GetLastError() );
HeapFree( GetProcessHeap(), 0, str);
- return FALSE;
+ return NULL;
}
RtlInitUnicodeString( &keypath, str );
@@ -212,7 +223,7 @@ static BOOL load_driver(void)
ExpandEnvironmentStringsW(str,path,size);
}
HeapFree( GetProcessHeap(), 0, str );
- if (!path) return FALSE;
+ if (!path) return NULL;
}
else
{
@@ -220,11 +231,11 @@ static BOOL load_driver(void)
WCHAR buffer[MAX_PATH];
GetSystemDirectoryW(buffer, MAX_PATH);
path = HeapAlloc(GetProcessHeap(),0,
- (strlenW(buffer) + strlenW(driversW) + strlenW(driver_name) + strlenW(postfixW) + 1)
+ (strlenW(buffer) + strlenW(driversW) + strlenW(drv_name) + strlenW(postfixW) + 1)
*sizeof(WCHAR));
lstrcpyW(path, buffer);
lstrcatW(path, driversW);
- lstrcatW(path, driver_name);
+ lstrcatW(path, drv_name);
lstrcatW(path, postfixW);
}
@@ -236,10 +247,32 @@ static BOOL load_driver(void)
module = load_driver_module( str );
HeapFree( GetProcessHeap(), 0, path );
- if (!module) return FALSE;
+ if (!module) return NULL;
- init_driver( module, &keypath );
- return TRUE;
+ status = init_driver( module, &keypath, drv_name, driver_obj, driver_extension );
+ if (status != STATUS_SUCCESS)
+ {
+ FreeLibrary( module );
+ return NULL;
+ }
+ return module;
+}
+
+static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj )
+{
+ if (driver_obj->DriverUnload)
+ {
+ if (WINE_TRACE_ON(relay))
+ WINE_DPRINTF( "%04x:Call driver unload %p (obj=%p)\n",
+ GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj );
+
+ driver_obj->DriverUnload( driver_obj );
+
+ if (WINE_TRACE_ON(relay))
+ WINE_DPRINTF( "%04x:Ret driver unload %p (obj=%p)\n",
+ GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj );
+ }
+ FreeLibrary( module );
}
static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
@@ -264,24 +297,144 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_
SetEvent( stop_event );
return NO_ERROR;
default:
- WINE_FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) );
+ WINE_FIXME( "got service ctrl %x for %s\n", ctrl,
+ wine_dbgstr_w(driver_name) );
status.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus( service_handle, &status );
return NO_ERROR;
}
}
+static int loading_request( WCHAR *event_name )
+{
+ static WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',0};
+
+ WCHAR *driver_process_cmd;
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ HANDLE pipe;
+ DWORD count, len;
+ BOOL ret, loaded;
+
+ /* create winedevice.exe process which will load drivers */
+
+ len = GetSystemDirectoryW( NULL, 0 );
+ driver_process_cmd = HeapAlloc( GetProcessHeap(), 0, sizeof(winedeviceW)
+ + sizeof(WCHAR) * len );
+ if (!driver_process_cmd) return 1;
+ GetSystemDirectoryW( driver_process_cmd, len );
+ strcpyW( driver_process_cmd + len - 1, winedeviceW );
+
+ RtlZeroMemory( &si, sizeof(STARTUPINFOW) );
+ si.cb = sizeof(STARTUPINFOW);
+ ret = CreateProcessW( NULL, driver_process_cmd, NULL, NULL, FALSE, 0,
+ NULL, NULL, &si, &pi );
+ HeapFree( GetProcessHeap(), 0, driver_process_cmd );
+ if (!ret) return 1;
+ CloseHandle( pi.hThread );
+ CloseHandle( pi.hProcess );
+
+ /* send driver and event names and receive loading result */
+
+ do {
+ WaitNamedPipeW( pipe_nameW, NMPWAIT_WAIT_FOREVER );
+ pipe = CreateFileW( pipe_nameW, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
+ } while (pipe == INVALID_HANDLE_VALUE);
+ len = (strlenW(driver_name) + 1) * sizeof(WCHAR);
+ ret = WriteFile( pipe, &len, sizeof(DWORD), &count, NULL );
+ if (!ret || count != sizeof(DWORD)) goto fail;
+ ret = WriteFile( pipe, driver_name, len, &count, NULL );
+ if (!ret || count != len) goto fail;
+ ret = WriteFile( pipe, event_name, EVENT_NAME_LEN, &count, NULL );
+ if (!ret || count != EVENT_NAME_LEN) goto fail;
+ ret = ReadFile( pipe, &loaded, sizeof(BOOL), &count, NULL );
+ if (!ret || count != sizeof(BOOL)) goto fail;
+ if (loaded)
+ {
+ CloseHandle( pipe );
+ return 0;
+ }
+fail:
+ CloseHandle( pipe );
+ return 1;
+}
+
+static HMODULE handle_loading_request( HANDLE pipe, DRIVER_OBJECT *driver_obj,
+ DRIVER_EXTENSION *driver_extension,
+ WCHAR **drv_name, WCHAR **event_name )
+{
+ HMODULE module = NULL;
+ BOOL ret, loaded = FALSE;
+ DWORD count, len;
+
+ *drv_name = NULL;
+ *event_name = NULL;
+ ret = ReadFile( pipe, &len, sizeof(DWORD), &count, NULL );
+ if (!ret || count != sizeof(DWORD)) goto end;
+ *drv_name = HeapAlloc( GetProcessHeap(), 0, len );
+ if (!*drv_name) goto end;
+ ret = ReadFile( pipe, *drv_name, len, &count, NULL );
+ if (!ret || count != len) goto end;
+ *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN );
+ if (!*event_name) goto end;
+ ret = ReadFile( pipe, *event_name, EVENT_NAME_LEN, &count, NULL );
+ if (!ret || count != EVENT_NAME_LEN) goto end;
+ module = load_driver( *drv_name, driver_obj, driver_extension );
+ if (module) loaded = TRUE;
+ ret = WriteFile( pipe, &loaded, sizeof(BOOL), &count, NULL );
+ if (module && (!ret || count != sizeof(BOOL)))
+ {
+ unload_driver( module, driver_obj );
+ module = NULL;
+ }
+end:
+ DisconnectNamedPipe( pipe );
+ CloseHandle( pipe );
+ if (!module)
+ {
+ if (*drv_name) HeapFree( GetProcessHeap(), 0, *drv_name );
+ if (*event_name) HeapFree( GetProcessHeap(), 0, *drv_name );
+ }
+ return module;
+}
+
+static HANDLE create_named_event( WCHAR **event_name )
+{
+ static const WCHAR event_nameW[] = {'_','_','w','i','n','e','_',
+ 'W','i','n','e','d','e','v','i','c','e','_','%','u',0};
+
+ HANDLE event;
+ unsigned int k = 0;
+
+ *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN );
+ if (!*event_name) return NULL;
+ for (;;)
+ {
+ snprintfW( *event_name, EVENT_NAME_LEN / sizeof(WCHAR), event_nameW, k++ );
+ event = CreateEventW( NULL, TRUE, FALSE, *event_name );
+ if (event && GetLastError() != ERROR_ALREADY_EXISTS)
+ return event;
+ CloseHandle( event );
+ }
+}
+
static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
{
SERVICE_STATUS status;
+ WCHAR *event_name;
WINE_TRACE( "starting service %s\n", wine_dbgstr_w(driver_name) );
- stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
-
+ stop_event = create_named_event( &event_name );
+ if (!stop_event)
+ return;
service_handle = RegisterServiceCtrlHandlerExW( driver_name, service_handler, NULL );
if (!service_handle)
+ {
+ HeapFree( GetProcessHeap(), 0, event_name );
return;
+ }
status.dwServiceType = SERVICE_WIN32;
status.dwCurrentState = SERVICE_START_PENDING;
@@ -292,19 +445,45 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
status.dwWaitHint = 10000;
SetServiceStatus( service_handle, &status );
- if (load_driver())
+ if (!loading_request( event_name ))
+ {
+ status.dwCurrentState = SERVICE_RUNNING;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ SetServiceStatus( service_handle, &status );
+
+ WaitForSingleObject( stop_event, INFINITE );
+ }
+ else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) );
+
+ HeapFree( GetProcessHeap(), 0, event_name );
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwControlsAccepted = 0;
+ SetServiceStatus( service_handle, &status );
+ WINE_TRACE( "service %s stopped\n", wine_dbgstr_w(driver_name) );
+}
+
+static DWORD CALLBACK driver_thread( HANDLE pipe )
+{
+ DRIVER_OBJECT driver_obj;
+ DRIVER_EXTENSION driver_extension;
+ WCHAR *drv_name, *event_name;
+ HMODULE module;
+
+ RtlZeroMemory( &driver_obj, sizeof(driver_obj) );
+ RtlZeroMemory( &driver_extension, sizeof(driver_extension) );
+ module = handle_loading_request( pipe, &driver_obj, &driver_extension,
+ &drv_name, &event_name );
+ if (module)
{
UNICODE_STRING drvname;
NTSTATUS ret = STATUS_SUCCESS;
IRP *irp;
IO_STACK_LOCATION *irpsp;
PDRIVER_DISPATCH dispatch;
+ HANDLE loop_event;
- status.dwCurrentState = SERVICE_RUNNING;
- status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- SetServiceStatus( service_handle, &status );
-
- RtlInitUnicodeString( &drvname, driver_name );
+ loop_event = CreateEventW( NULL, TRUE, FALSE, event_name );
+ RtlInitUnicodeString( &drvname, drv_name );
if (driver_extension.AddDevice)
{
@@ -313,7 +492,7 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
PDEVICE_OBJECT pdev_obj = NULL;
UCHAR pdo_info[2 * PATH_MAX + 3 + MAX_DEVICE_ID_LEN];
data_size_t reply_size = 0;
- HANDLE events[2] = {stop_event, NULL};
+ HANDLE events[2] = {loop_event, NULL};
DWORD wait_ret;
while (!reply_size)
@@ -381,25 +560,64 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
ret = STATUS_UNSUCCESSFUL;
}
- wine_ntoskrnl_main_loop( stop_event );
- }
- else WINE_TRACE( "driver %s failed to load\n", wine_dbgstr_w(driver_name) );
+ wine_ntoskrnl_main_loop( loop_event );
+ /* Stop service if wine_ntoskrnl_main_loop exits */
+ SetEvent( loop_event );
stop:
- status.dwCurrentState = SERVICE_STOPPED;
- status.dwControlsAccepted = 0;
- SetServiceStatus( service_handle, &status );
- WINE_TRACE( "service %s stopped\n", wine_dbgstr_w(driver_name) );
+ CloseHandle( loop_event );
+ unload_driver( module, &driver_obj );
+ HeapFree( GetProcessHeap(), 0, drv_name );
+ HeapFree( GetProcessHeap(), 0, event_name );
+ }
+ return 0;
}
-int wmain( int argc, WCHAR *argv[] )
+static int driver_process(void)
{
- SERVICE_TABLE_ENTRYW service_table[2];
+ HANDLE pipe, winedevice_mutex, thread;
- if (!(driver_name = argv[1]))
+ __wine_make_process_system();
+ winedevice_mutex = CreateMutexW( NULL, TRUE, winedevice_mutexW );
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
{
- WINE_ERR( "missing device name, winedevice isn't supposed to be run manually\n" );
+ CloseHandle( winedevice_mutex );
return 1;
}
+ for (;;)
+ {
+ pipe = CreateNamedPipeW( pipe_nameW, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
+ 256, 256, 10000, NULL );
+ if (pipe == INVALID_HANDLE_VALUE)
+ {
+ WINE_ERR( "failed to create pipe\n" );
+ continue;
+ }
+ if (!ConnectNamedPipe( pipe, NULL ) &&
+ GetLastError() != ERROR_PIPE_CONNECTED)
+ {
+ CloseHandle( pipe );
+ continue;
+ }
+
+ thread = CreateThread( NULL, 0, driver_thread, pipe, 0, NULL );
+ if (!thread)
+ {
+ WINE_ERR( "failed to create thread\n" );
+ DisconnectNamedPipe( pipe );
+ CloseHandle( pipe );
+ continue;
+ }
+ CloseHandle( thread );
+ }
+}
+
+int wmain( int argc, WCHAR *argv[] )
+{
+ SERVICE_TABLE_ENTRYW service_table[2];
+
+ if (!argv[1]) return driver_process();
+ driver_name = argv[1];
service_table[0].lpServiceName = argv[1];
service_table[0].lpServiceProc = ServiceMain;
--
1.6.0.2.GIT
Подробная информация о списке рассылки Wine-patches