366 lines
10 KiB
C
366 lines
10 KiB
C
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// 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;
|
|||
|
}
|