|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: thread.c
//
//--------------------------------------------------------------------------
//
// This file contains functions associated with ParClass worker threads
//
#include "pch.h"
#include "readwrit.h"
VOID ParallelThread( IN PVOID Context )
/*++
Routine Description:
This is the parallel thread routine. Loops performing I/O operations.
Arguments:
Context -- Really the extension
Return Value:
None
--*/
{ PDEVICE_EXTENSION Extension; LONG ThreadPriority; KIRQL OldIrql; NTSTATUS Status; LARGE_INTEGER Timeout; PIRP CurrentIrp; BOOLEAN bRetry = TRUE; // REVISIT, dvrh's big usbly hack.
Extension = Context;
ParDumpV( ("Enter ParallelThread(...) - %wZ\r\n", &Extension->SymbolicLinkName) );
//
// Lower ourselves down just at tad so that we compete a
// little less.
//
// If the registry indicates we should be running at the old
// priority, don't lower our priority as much.
//
ThreadPriority = -2;
if(Extension->UseNT35Priority) { ThreadPriority = -1; } // dvtw,
// dvrh Wants higher prioroity on threads.
#if 0
ThreadPriority = 16; KeSetBasePriorityThread( KeGetCurrentThread(), ThreadPriority ); #endif
do {
Timeout = Extension->IdleTimeout; // Timeout = - (250*10*1000);
// dvdr we try to aquire this twice after we have locked the port
// when we try to unlock the port this gets called also and we already have
// mutex so we hang
// ExAcquireFastMutex (&Extension->LockPortMutex);
ParallelThread_WaitRetry: Status = KeWaitForSingleObject( &Extension->RequestSemaphore, UserRequest, KernelMode, FALSE, &Timeout ); // dvdr
// ExReleaseFastMutex (&Extension->LockPortMutex);
if (Status == STATUS_TIMEOUT) {
if ((TRUE == Extension->P12843DL.bEventActive) ) { if (ParHaveReadData(Extension)) { ParDump2(PARINFO, ("ParallelThread: Signaling Event [%x]\n", Extension->P12843DL.Event) ); // D D(("-- thread::timeout - set event\n"));
KeSetEvent(Extension->P12843DL.Event, 0, FALSE); ParDump2(PARINFO, ("ParallelThread: Event was signaled\n") ); } }
// dvrh's big ugly hack
if (Extension->IsCritical) { ParDumpV( ("We're critical and want to terminate threads\n") ); if (bRetry) { ParDumpV( ("Gonna give the thread more time\n") ); bRetry = FALSE; goto ParallelThread_WaitRetry; } ParDumpV( ("Gonna hose our periph since we're killing threads\n") ); // __asm int 3
} // dvrh, Test hypothesis of potential port contention problems between
// spooler and those going through.
// if (!Extension->Connected)
if (Extension->QueryNumWaiters(Extension->PortContext) != 0) { #define PAR_USE_TERMINATE_FUNCTION 1
#if PAR_USE_TERMINATE_FUNCTION
ParTerminate(Extension); #else
if (afpForward[Extension->IdxForwardProtocol].fnDisconnect) { ParDump2(PARINFO, ("ParallelThread: STATUS_TIMEOUT: Calling afpForward.fnDisconnect\r\n")); afpForward[Extension->IdxForwardProtocol].fnDisconnect (Extension); } #endif
ParFreePort(Extension); continue; } }
// wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
KeWaitForSingleObject(&Extension->PauseEvent, Executive, KernelMode, FALSE, 0);
if ( Extension->TimeToTerminateThread ) {
//
// If we are currently connected...disconnect.
//
if (Extension->Connected) {
#if PAR_USE_TERMINATE_FUNCTION
ParTerminate(Extension); #else
if (afpForward[Extension->IdxForwardProtocol].fnDisconnect) { ParDump2(PARINFO, ("ParallelThread: TimeToTerminateThread: Calling afpForward.fnDisconnect\r\n")); afpForward[Extension->IdxForwardProtocol].fnDisconnect (Extension); } #endif
ParFreePort(Extension); }
ParDumpV( ( "%wZ thread killing self\r\n", &Extension->SymbolicLinkName) ); PsTerminateSystemThread( STATUS_SUCCESS ); }
//
// While we are manipulating the queue we capture the
// cancel spin lock.
//
IoAcquireCancelSpinLock(&OldIrql);
ASSERT(!Extension->CurrentOpIrp);
while (!IsListEmpty(&Extension->WorkQueue)) {
// get next IRP from our list of work items
PLIST_ENTRY HeadOfList; HeadOfList = RemoveHeadList(&Extension->WorkQueue); CurrentIrp = CONTAINING_RECORD(HeadOfList, IRP, Tail.Overlay.ListEntry);
// we have started processing, this IRP can no longer be cancelled
IoSetCancelRoutine(CurrentIrp, NULL); ASSERT(NULL == CurrentIrp->CancelRoutine); ASSERT(!CurrentIrp->Cancel);
Extension->CurrentOpIrp = CurrentIrp;
IoReleaseCancelSpinLock(OldIrql);
//
// Do the Io.
//
ParStartIo(Extension);
if ((TRUE == Extension->P12843DL.bEventActive) && (ParHaveReadData(Extension))) { ParDump2(PARINFO, ("ParallelThread: Signaling Event [%x]\n", Extension->P12843DL.Event) ); ASSERT(Extension->P12843DL.Event); KeSetEvent(Extension->P12843DL.Event, 0, FALSE); ParDump2(PARINFO, ("ParallelThread: Event was signaled\n") ); }
// wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
KeWaitForSingleObject(&Extension->PauseEvent, Executive, KernelMode, FALSE, 0);
IoAcquireCancelSpinLock(&OldIrql); } IoReleaseCancelSpinLock(OldIrql);
} while (TRUE); }
NTSTATUS ParCreateSystemThread( PDEVICE_EXTENSION Extension )
{ NTSTATUS Status; HANDLE ThreadHandle; OBJECT_ATTRIBUTES objAttrib;
ParDump2(PARTHREAD, ("Enter ParCreateSystemThread(...)\r\n") );
//
// Start the thread and capture the thread handle into the extension
//
InitializeObjectAttributes( &objAttrib, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
Status = PsCreateSystemThread( &ThreadHandle, THREAD_ALL_ACCESS, &objAttrib, NULL, NULL, ParallelThread, Extension );
if (!NT_ERROR(Status)) {
//
// We've got the thread. Now get a pointer to it.
//
// assert that this DO does not already have a thread
ASSERT(!Extension->ThreadObjectPointer);
Status = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &Extension->ThreadObjectPointer, NULL );
if (NT_ERROR(Status)) {
ParDump2(PARTHREAD, ("Bad status on open from ref by handle: %x\r\n", Status) );
Extension->TimeToTerminateThread = TRUE;
KeReleaseSemaphore( &Extension->RequestSemaphore, 0, 1, FALSE );
} else {
//
// Now that we have a reference to the thread
// we can simply close the handle.
//
ZwClose(ThreadHandle);
}
} else { ParDump2(PARTHREAD, ("Bad status on open from ref by handle: %x\r\n", Status) ); }
return Status; }
VOID ParStartIo( IN PDEVICE_EXTENSION Extension )
/*++
Routine Description:
This routine starts an I/O operation for the driver and then returns
Arguments:
Extension - The parallel device extension
Return Value:
None
--*/
{ PIRP Irp; PIO_STACK_LOCATION IrpSp; KIRQL CancelIrql; NTSTATUS NtStatus;
// ParDumpV( ("Enter ParStartIo\r\n") );
Irp = Extension->CurrentOpIrp; IrpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
if (!Extension->Connected && !ParAllocPort(Extension)) { #pragma message( "dvrh Left bad stuff in thread.c")
ParDump2(PARTHREAD, ("Threads are hosed\n") ); // __asm int 3
//
// If the allocation didn't succeed then fail this IRP.
//
goto CompleteIrp; }
switch (IrpSp->MajorFunction) {
case IRP_MJ_WRITE: ParDump2(PARTHREAD, ("ParStartIo: IRP \t[%x]\t Calling ParWriteIrp\n", Irp) ); ParTimerMainCheck( ("SIo: IRP \t[%x]\t Pre WrtIrp\r\n", Irp) ); Extension->IsCritical = TRUE; ParWriteIrp(Extension); Extension->IsCritical = FALSE; ParTimerMainCheck( ("SIo: IRP \t[%x]\t Post WrtIrp\r\n", Irp) ); break;
case IRP_MJ_READ: ParDump2(PARTHREAD, ("ParStartIo: IRP \t[%x]\t Calling ParReadIrp\n", Irp) ); ParTimerMainCheck( ("SIo: IRP \t[%x]\t Pre RdIrp\r\n", Irp) ); Extension->IsCritical = TRUE; ParReadIrp(Extension); Extension->IsCritical = FALSE; ParTimerMainCheck( ("SIo: IRP \t[%x]\t Post RdIrp\r\n", Irp) ); break;
default: ParDump2(PARTHREAD, ("ParStartIo: IRP \t[%x]\t Calling ParDeviceIo\n", Irp) ); ParTimerMainCheck( ("SIo: IRP \t[%x]\t Pre DevIo\r\n", Irp) ); ParDeviceIo(Extension); ParTimerMainCheck( ("SIo: IRP \t[%x]\t Post DevIo\r\n", Irp) ); break;
}
if (!Extension->Connected && !Extension->AllocatedByLockPort) { // if we're not connected in a 1284 mode, then release host port
// otherwise let the watchdog timer do it.
ParFreePort(Extension); }
CompleteIrp:
IoAcquireCancelSpinLock(&CancelIrql); Extension->CurrentOpIrp = NULL; IoReleaseCancelSpinLock(CancelIrql);
ParCompleteRequest(Irp, (CCHAR)(NT_SUCCESS(Irp->IoStatus.Status) ? IO_PARALLEL_INCREMENT : IO_NO_INCREMENT));
return; }
|