Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

379 lines
9.5 KiB

/*
* Worker thread functions
*
*
*/
#include "pch.h"
KSPIN_LOCK ACPIWorkerSpinLock;
WORK_QUEUE_ITEM ACPIWorkItem;
LIST_ENTRY ACPIDeviceWorkQueue;
BOOLEAN ACPIWorkerBusy;
KEVENT ACPIWorkToDoEvent;
KEVENT ACPITerminateEvent;
LIST_ENTRY ACPIWorkQueue;
HANDLE ACPIThread;
VOID
ACPIWorkerThread (
IN PVOID Context
);
VOID
ACPIWorker(
IN PVOID StartContext
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, ACPIInitializeWorker)
#endif
VOID
ACPIInitializeWorker (
VOID
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ThreadHandle;
PETHREAD *Thread;
KeInitializeSpinLock (&ACPIWorkerSpinLock);
ExInitializeWorkItem (&ACPIWorkItem, ACPIWorkerThread, NULL);
InitializeListHead (&ACPIDeviceWorkQueue);
//
// Initialize the ACPI worker thread. This thread is for use by the AML
// interpreter and must not page-fault or have its stack swapped.
//
KeInitializeEvent(&ACPIWorkToDoEvent, NotificationEvent, FALSE);
KeInitializeEvent(&ACPITerminateEvent, NotificationEvent, FALSE);
InitializeListHead(&ACPIWorkQueue);
//
// Create the worker thread
//
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
ACPIWorker,
NULL);
if (Status != STATUS_SUCCESS) {
ACPIInternalError( ACPI_WORKER );
}
Status = ObReferenceObjectByHandle (ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
(PVOID *)&Thread,
NULL);
if (Status != STATUS_SUCCESS) {
ACPIInternalError( ACPI_WORKER );
}
}
VOID
ACPISetDeviceWorker (
IN PDEVICE_EXTENSION DevExt,
IN ULONG Events
)
{
BOOLEAN QueueWorker;
KIRQL OldIrql;
//
// Synchronize with worker thread
//
KeAcquireSpinLock (&ACPIWorkerSpinLock, &OldIrql);
QueueWorker = FALSE;
//
// Set the devices pending events
//
DevExt->WorkQueue.PendingEvents |= Events;
//
// If this device is not being processed, start now
//
if (!DevExt->WorkQueue.Link.Flink) {
//
// Queue to worker thread
//
InsertTailList (&ACPIDeviceWorkQueue, &DevExt->WorkQueue.Link);
QueueWorker = !ACPIWorkerBusy;
ACPIWorkerBusy = TRUE;
}
//
// Drop lock, and if needed get a worker thread
//
KeReleaseSpinLock (&ACPIWorkerSpinLock, OldIrql);
if (QueueWorker) {
ExQueueWorkItem (&ACPIWorkItem, DelayedWorkQueue);
}
}
VOID
ACPIWorkerThread (
IN PVOID Context
)
{
KIRQL OldIrql;
PDEVICE_EXTENSION DevExt;
ULONG Events;
PLIST_ENTRY Link;
KeAcquireSpinLock (&ACPIWorkerSpinLock, &OldIrql);
ACPIWorkerBusy = TRUE;
//
// Loop and handle each queue device
//
while (!IsListEmpty(&ACPIDeviceWorkQueue)) {
Link = ACPIDeviceWorkQueue.Flink;
RemoveEntryList (Link);
Link->Flink = NULL;
DevExt = CONTAINING_RECORD (Link, DEVICE_EXTENSION, WorkQueue.Link);
//
// Dispatch the pending events
//
Events = DevExt->WorkQueue.PendingEvents;
DevExt->WorkQueue.PendingEvents = 0;
KeReleaseSpinLock (&ACPIWorkerSpinLock, OldIrql);
DevExt->DispatchTable->Worker (DevExt, Events);
KeAcquireSpinLock (&ACPIWorkerSpinLock, &OldIrql);
}
ACPIWorkerBusy = FALSE;
KeReleaseSpinLock (&ACPIWorkerSpinLock, OldIrql);
}
#if DBG
EXCEPTION_DISPOSITION
ACPIWorkerThreadFilter(
IN PWORKER_THREAD_ROUTINE WorkerRoutine,
IN PVOID Parameter,
IN PEXCEPTION_POINTERS ExceptionInfo
)
{
KdPrint(("ACPIWORKER: exception in worker routine %lx(%lx)\n", WorkerRoutine, Parameter));
KdPrint((" exception record at %lx\n", ExceptionInfo->ExceptionRecord));
KdPrint((" context record at %lx\n",ExceptionInfo->ContextRecord));
try {
DbgBreakPoint();
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// No kernel debugger attached, so let the system thread
// exception handler call KeBugCheckEx.
//
return(EXCEPTION_CONTINUE_SEARCH);
}
return(EXCEPTION_EXECUTE_HANDLER);
}
#endif
typedef enum _ACPI_WORKER_OBJECT {
ACPIWorkToDo,
ACPITerminate,
ACPIMaximumObject
} ACPI_WORKER_OBJECT;
VOID
ACPIWorker(
IN PVOID StartContext
)
{
PLIST_ENTRY Entry;
WORK_QUEUE_TYPE QueueType;
PWORK_QUEUE_ITEM WorkItem;
KIRQL OldIrql;
NTSTATUS Status;
static KWAIT_BLOCK WaitBlockArray[ACPIMaximumObject];
PVOID WaitObjects[ACPIMaximumObject];
ACPIThread = PsGetCurrentThread ();
//
// Wait for the modified page writer event AND the PFN mutex.
//
WaitObjects[ACPIWorkToDo] = (PVOID)&ACPIWorkToDoEvent;
WaitObjects[ACPITerminate] = (PVOID)&ACPITerminateEvent;
//
// Loop forever waiting for a work queue item, calling the processing
// routine, and then waiting for another work queue item.
//
do {
//
// Wait until something is put in the queue.
//
// By specifying a wait mode of KernelMode, the thread's kernel stack is
// not swappable
//
Status = KeWaitForMultipleObjects(ACPIMaximumObject,
&WaitObjects[0],
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
&WaitBlockArray[0]);
//
// Switch on the wait status.
//
switch (Status) {
case ACPIWorkToDo:
break;
case ACPITerminate:
// Stephane - you need to clear out any pending requests,
// wake people up, etc. here.
//
// Also make sure you free up any allocated pool, etc.
PsTerminateSystemThread (STATUS_SUCCESS);
break;
default:
break;
}
KeAcquireSpinLock(&ACPIWorkerSpinLock, &OldIrql);
ASSERT(!IsListEmpty(&ACPIWorkQueue));
Entry = RemoveHeadList(&ACPIWorkQueue);
if (IsListEmpty(&ACPIWorkQueue)) {
KeClearEvent(&ACPIWorkToDoEvent);
}
KeReleaseSpinLock(&ACPIWorkerSpinLock, OldIrql);
WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
//
// Execute the specified routine.
//
#if DBG
try {
PVOID WorkerRoutine;
PVOID Parameter;
WorkerRoutine = WorkItem->WorkerRoutine;
Parameter = WorkItem->Parameter;
(WorkItem->WorkerRoutine)(WorkItem->Parameter);
if (KeGetCurrentIrql() != 0) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"ACPIWORKER: worker exit at IRQL %d, worker routine %x, "
"parameter %x, item %x\n",
KeGetCurrentIrql(),
WorkerRoutine,
Parameter,
WorkItem
) );
DbgBreakPoint();
}
} except( ACPIWorkerThreadFilter(WorkItem->WorkerRoutine,
WorkItem->Parameter,
GetExceptionInformation() )) {
}
#else
(WorkItem->WorkerRoutine)(WorkItem->Parameter);
if (KeGetCurrentIrql() != 0) {
KeBugCheckEx(
IRQL_NOT_LESS_OR_EQUAL,
(ULONG_PTR)WorkItem->WorkerRoutine,
(ULONG_PTR)KeGetCurrentIrql(),
(ULONG_PTR)WorkItem->WorkerRoutine,
(ULONG_PTR)WorkItem
);
}
#endif
} while(TRUE);
}
VOID
OSQueueWorkItem(
IN PWORK_QUEUE_ITEM WorkItem
)
/*++
Routine Description:
This function inserts a work item into a work queue that is processed
by the ACPI worker thread
Arguments:
WorkItem - Supplies a pointer to the work item to add the the queue.
This structure must be located in NonPagedPool. The work item
structure contains a doubly linked list entry, the address of a
routine to call and a parameter to pass to that routine.
Return Value:
None
--*/
{
KIRQL OldIrql;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
//
// Insert the work item
//
KeAcquireSpinLock(&ACPIWorkerSpinLock, &OldIrql);
if (IsListEmpty(&ACPIWorkQueue)) {
KeSetEvent(&ACPIWorkToDoEvent, 0, FALSE);
}
InsertTailList(&ACPIWorkQueue, &WorkItem->List);
KeReleaseSpinLock(&ACPIWorkerSpinLock, OldIrql);
return;
}