windows-nt/Source/XPSP1/NT/drivers/parallel/parclass/thread.c
2020-09-26 16:20:57 +08:00

366 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//+-------------------------------------------------------------------------
//
// 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;
}