From 8d49c7c4891938ef244fdbee6708663ea2f4b018 Mon Sep 17 00:00:00 2001 From: Shao Miller Date: Tue, 14 Dec 2010 21:55:55 -0500 Subject: [PATCH] [bus,driver] Introduce bus threading The driver now calls bus__start_thread() on the main bus. One can implement their own bus__thread_func routine and assign it to the bus::thread member. If one does so, one should call bus__process_work_items() within the thread's loop, and one should be responsible for freeing their bus. --- src/include/bus.h | 14 +++++ src/winvblock/bus/bus.c | 112 ++++++++++++++++++++++++++++++++++++---- src/winvblock/driver.c | 7 +++ 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/include/bus.h b/src/include/bus.h index 574fe2f..cb32db7 100644 --- a/src/include/bus.h +++ b/src/include/bus.h @@ -27,6 +27,17 @@ * Bus specifics. */ +/** + * A bus thread routine. + * + * @v bus The bus to be used in the thread routine. + * + * If you implement your own bus thread routine, you should call + * bus__process_work_items() within its loop. + */ +typedef void STDCALL bus__thread_func(IN struct bus__type *); + +/* The bus type. */ struct bus__type { struct device__type * device; PDEVICE_OBJECT LowerDeviceObject; @@ -42,6 +53,8 @@ struct bus__type { winvblock__bool named; LIST_ENTRY work_items; KSPIN_LOCK work_items_lock; + KEVENT work_signal; + bus__thread_func * thread; }; /* Exports. */ @@ -58,5 +71,6 @@ extern winvblock__lib_func winvblock__bool STDCALL bus__add_child( ); extern winvblock__lib_func struct bus__type * bus__get(struct device__type *); extern winvblock__lib_func void bus__process_work_items(struct bus__type *); +extern winvblock__lib_func NTSTATUS bus__start_thread(struct bus__type *); #endif /* _BUS_H */ diff --git a/src/winvblock/bus/bus.c b/src/winvblock/bus/bus.c index 7316e1d..c6ea8b8 100644 --- a/src/winvblock/bus/bus.c +++ b/src/winvblock/bus/bus.c @@ -46,6 +46,7 @@ static device__create_pdo_func bus__create_pdo_; static device__dispatch_func bus__power_; static device__dispatch_func bus__sys_ctl_; static device__pnp_func bus__pnp_dispatch_; +static bus__thread_func bus__default_thread_; /* Globals. */ struct device__irp_mj bus__irp_mj_ = { @@ -253,15 +254,17 @@ winvblock__lib_func struct bus__type * bus__create(void) { /* Populate non-zero device defaults. */ bus_ptr->device = dev_ptr; bus_ptr->prev_free = dev_ptr->ops.free; + bus_ptr->thread = bus__default_thread_; + KeInitializeSpinLock(&bus_ptr->SpinLock); + KeInitializeSpinLock(&bus_ptr->work_items_lock); + InitializeListHead(&bus_ptr->work_items); + KeInitializeEvent(&bus_ptr->work_signal, SynchronizationEvent, FALSE); dev_ptr->ops.create_pdo = bus__create_pdo_; dev_ptr->ops.init = bus__init_; dev_ptr->ops.free = bus__free_; dev_ptr->ext = bus_ptr; dev_ptr->irp_mj = &bus__irp_mj_; dev_ptr->IsBus = TRUE; - KeInitializeSpinLock(&bus_ptr->SpinLock); - KeInitializeSpinLock(&bus_ptr->work_items_lock); - InitializeListHead(&bus_ptr->work_items); return bus_ptr; @@ -390,9 +393,6 @@ static winvblock__bool bus__add_work_item_( struct bus__type * bus, struct bus__work_item_ * work_item ) { - if (!bus || !work_item) - return FALSE; - ExInterlockedInsertTailList( &bus->work_items, &work_item->list_entry, @@ -413,9 +413,6 @@ static struct bus__work_item_ * bus__get_work_item_( ) { PLIST_ENTRY list_entry; - if (!bus) - return NULL; - list_entry = ExInterlockedRemoveHeadList( &bus->work_items, &bus->work_items_lock @@ -450,3 +447,100 @@ winvblock__lib_func void bus__process_work_items(struct bus__type * bus) { } return; } + +/** + * The bus thread wrapper. + * + * @v context The thread context. In our case, it points to + * the bus that the thread should use in processing. + */ +static void STDCALL bus__thread_(IN void *context) { + struct bus__type * bus = context; + + if (!bus || !bus->thread) { + DBG("No bus or no thread!\n"); + return; + } + + bus->thread(bus); + return; + } + +/** + * The default bus thread routine. + * + * @v bus Points to the bus device for the thread to work with. + * + * Note that if you implement your own bus type using this library, + * you can override the thread routine with your own. If you do so, + * your thread routine should call bus__process_work_items() within + * its loop. To start a bus thread, use bus__start_thread() + * If you implement your own thread routine, you are also responsible + * for freeing the bus. + */ +static void STDCALL bus__default_thread_(IN struct bus__type * bus) { + LARGE_INTEGER timeout; + + /* Wake up at least every second. */ + timeout.QuadPart = -10000000LL; + + /* When bus::thread is cleared, we shut down. */ + while (bus->thread) { + DBG("Alive.\n"); + + /* Wait for the work signal or the timeout. */ + KeWaitForSingleObject( + &bus->work_signal, + Executive, + KernelMode, + FALSE, + &timeout + ); + /* Reset the work signal. */ + KeResetEvent(&bus->work_signal); + + bus__process_work_items(bus); + } /* while bus->alive */ + + bus__free_(bus->device); + return; + } + +/** + * Start a bus thread. + * + * @v bus The bus to start a thread for. + * @ret NTSTATUS The status of the thread creation operation. + * + * Also see bus__thread_func in the header for details about the prototype + * for implementing your own bus thread routine. You set bus::thread to + * specify your own thread routine, then call this function to start it. + */ +winvblock__lib_func NTSTATUS bus__start_thread( + struct bus__type * bus + ) { + OBJECT_ATTRIBUTES obj_attrs; + HANDLE thread_handle; + + if (!bus) { + DBG("No bus specified!\n"); + return STATUS_INVALID_PARAMETER; + } + + InitializeObjectAttributes( + &obj_attrs, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + return PsCreateSystemThread( + &thread_handle, + THREAD_ALL_ACCESS, + &obj_attrs, + NULL, + NULL, + bus__thread_, + bus + ); + } diff --git a/src/winvblock/driver.c b/src/winvblock/driver.c index 36c1089..d1eea88 100644 --- a/src/winvblock/driver.c +++ b/src/winvblock/driver.c @@ -194,6 +194,11 @@ static NTSTATUS STDCALL driver__attach_fdo_( DBG("IoAttachDeviceToDeviceStack() failed!\n"); goto err_attach; } + status = bus__start_thread(bus); + if (!NT_SUCCESS(status)) { + DBG("Couldn't start bus thread!\n"); + goto err_thread; + } /* Ok! */ KeAcquireSpinLock(&driver__bus_fdo_lock_, &irql); if (driver__bus_fdo_) { @@ -213,6 +218,8 @@ static NTSTATUS STDCALL driver__attach_fdo_( err_race_failed: + err_thread: + err_attach: IoDeleteSymbolicLink(&bus->dos_dev_name); -- 2.17.1