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