Source code of Windows XP (NT5)
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.

276 lines
7.7 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: thread.c
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // This file contains functions associated with ParClass worker threads
  12. //
  13. #include "pch.h"
  14. VOID
  15. PptPdoThread(
  16. IN PVOID Context
  17. )
  18. /*++
  19. Routine Description:
  20. This is the parallel thread routine. Loops performing I/O operations.
  21. Arguments:
  22. Context -- Really the extension
  23. Return Value:
  24. None
  25. --*/
  26. {
  27. PPDO_EXTENSION pdx = Context;
  28. KIRQL OldIrql;
  29. NTSTATUS Status;
  30. LARGE_INTEGER Timeout;
  31. PIRP CurrentIrp;
  32. DD((PCE)pdx,DDT,"PptPdoThread - %s - enter\n",pdx->Location);
  33. do {
  34. Timeout = pdx->IdleTimeout;
  35. Status = KeWaitForSingleObject( &pdx->RequestSemaphore, UserRequest, KernelMode, FALSE, &Timeout );
  36. if( Status == STATUS_TIMEOUT ) {
  37. if( pdx->P12843DL.bEventActive ) {
  38. // Dot4.sys has a worker thread blocked on this event
  39. // waiting for us to signal if the peripheral has data
  40. // available for dot4 to read. When we signal this
  41. // event dot4.sys generates a read request to retrieve
  42. // the data from the peripheral.
  43. if( ParHaveReadData( pdx ) ) {
  44. // the peripheral has data - signal dot4.sys
  45. DD((PCE)pdx,DDT,"PptPdoThread: Signaling Event [%x]\n", pdx->P12843DL.Event);
  46. KeSetEvent(pdx->P12843DL.Event, 0, FALSE);
  47. }
  48. }
  49. if( pdx->QueryNumWaiters( pdx->PortContext ) != 0 ) {
  50. // someone else is waiting on the port - give up the
  51. // port - we'll attempt to reaquire the port later
  52. // when we have a request to process
  53. ParTerminate(pdx);
  54. ParFreePort(pdx);
  55. continue;
  56. }
  57. } // endif STATUS_TIMEOUT
  58. // wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
  59. KeWaitForSingleObject(&pdx->PauseEvent, Executive, KernelMode, FALSE, 0);
  60. if ( pdx->TimeToTerminateThread ) {
  61. // A dispatch thread has signalled us that we should clean
  62. // up any communication with our peripheral and then
  63. // terminate self. The dispatch thread is blocked waiting
  64. // for us to terminate self.
  65. if( pdx->Connected ) {
  66. // We currently have the port acquired and have the
  67. // peripheral negotiated into an IEEE mode. Terminate
  68. // the peripheral back to Compatibility mode forward
  69. // idle and release the port.
  70. ParTerminate( pdx );
  71. ParFreePort( pdx );
  72. }
  73. // terminate self
  74. PsTerminateSystemThread( STATUS_SUCCESS );
  75. }
  76. //
  77. // process the next request from the work queue - use the
  78. // Cancel SpinLock to protect the queue
  79. //
  80. IoAcquireCancelSpinLock(&OldIrql);
  81. ASSERT(!pdx->CurrentOpIrp);
  82. while (!IsListEmpty(&pdx->WorkQueue)) {
  83. // get next IRP from our list of work items
  84. PLIST_ENTRY HeadOfList;
  85. HeadOfList = RemoveHeadList(&pdx->WorkQueue);
  86. CurrentIrp = CONTAINING_RECORD(HeadOfList, IRP, Tail.Overlay.ListEntry);
  87. // we have started processing, this IRP can no longer be cancelled
  88. #pragma warning( push )
  89. #pragma warning( disable : 4054 4055 )
  90. IoSetCancelRoutine(CurrentIrp, NULL);
  91. #pragma warning( pop )
  92. ASSERT(NULL == CurrentIrp->CancelRoutine);
  93. ASSERT(!CurrentIrp->Cancel);
  94. pdx->CurrentOpIrp = CurrentIrp;
  95. IoReleaseCancelSpinLock(OldIrql);
  96. //
  97. // Do the Io - PptPdoStartIo will exectute and complete the IRP: pdx->CurrentIrp
  98. //
  99. PptPdoStartIo(pdx);
  100. if( pdx->P12843DL.bEventActive ) {
  101. // Dot4.sys has a worker thread blocked on this event
  102. // waiting for us to signal if the peripheral has data
  103. // available for dot4 to read. When we signal this
  104. // event dot4.sys generates a read request to retrieve
  105. // the data from the peripheral.
  106. if( ParHaveReadData( pdx ) ) {
  107. // the peripheral has data - signal dot4.sys
  108. DD((PCE)pdx,DDT,"PptPdoThread: Signaling Eventb [%x]\n", pdx->P12843DL.Event);
  109. KeSetEvent(pdx->P12843DL.Event, 0, FALSE);
  110. }
  111. }
  112. // wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
  113. KeWaitForSingleObject(&pdx->PauseEvent, Executive, KernelMode, FALSE, 0);
  114. IoAcquireCancelSpinLock(&OldIrql);
  115. }
  116. IoReleaseCancelSpinLock(OldIrql);
  117. } while (TRUE);
  118. }
  119. NTSTATUS
  120. ParCreateSystemThread(
  121. PPDO_EXTENSION Pdx
  122. )
  123. {
  124. NTSTATUS Status;
  125. HANDLE ThreadHandle;
  126. OBJECT_ATTRIBUTES objAttrib;
  127. DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s - enter\n",Pdx->Location);
  128. // Start the thread - save referenced pointer to thread in our extension
  129. InitializeObjectAttributes( &objAttrib, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  130. Status = PsCreateSystemThread( &ThreadHandle, THREAD_ALL_ACCESS, &objAttrib, NULL, NULL, PptPdoThread, Pdx );
  131. if (!NT_ERROR(Status)) {
  132. // We've got the thread. Now get a pointer to it.
  133. Status = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &Pdx->ThreadObjectPointer, NULL );
  134. if (NT_ERROR(Status)) {
  135. Pdx->TimeToTerminateThread = TRUE;
  136. KeReleaseSemaphore( &Pdx->RequestSemaphore, 0, 1, FALSE );
  137. } else {
  138. // Now that we have a reference to the thread we can simply close the handle.
  139. ZwClose(ThreadHandle);
  140. }
  141. DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s - SUCCESS\n",Pdx->Location);
  142. } else {
  143. DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s FAIL - status = %x\n",Pdx->Location, Status);
  144. }
  145. return Status;
  146. }
  147. VOID
  148. PptPdoStartIo(
  149. IN PPDO_EXTENSION Pdx
  150. )
  151. /*++
  152. Routine Description:
  153. This routine starts an I/O operation for the driver and
  154. then returns
  155. Arguments:
  156. Pdx - The parallel device extension
  157. Return Value:
  158. None
  159. --*/
  160. {
  161. PIRP Irp;
  162. PIO_STACK_LOCATION IrpSp;
  163. KIRQL CancelIrql;
  164. Irp = Pdx->CurrentOpIrp;
  165. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  166. Irp->IoStatus.Information = 0;
  167. if (!Pdx->Connected && !ParAllocPort(Pdx)) {
  168. // #pragma message( "dvrh Left bad stuff in thread.c")
  169. DD((PCE)Pdx,DDE,"PptPdoStartIo - %s - threads are hosed\n",Pdx->Location);
  170. // __asm int 3
  171. //
  172. // If the allocation didn't succeed then fail this IRP.
  173. //
  174. goto CompleteIrp;
  175. }
  176. switch (IrpSp->MajorFunction) {
  177. case IRP_MJ_WRITE:
  178. ParWriteIrp(Pdx);
  179. break;
  180. case IRP_MJ_READ:
  181. ParReadIrp(Pdx);
  182. break;
  183. default:
  184. ParDeviceIo(Pdx);
  185. break;
  186. }
  187. if (!Pdx->Connected && !Pdx->AllocatedByLockPort) {
  188. // if we're not connected in a 1284 mode, then release host port
  189. // otherwise let the watchdog timer do it.
  190. ParFreePort(Pdx);
  191. }
  192. CompleteIrp:
  193. IoAcquireCancelSpinLock(&CancelIrql);
  194. Pdx->CurrentOpIrp = NULL;
  195. IoReleaseCancelSpinLock(CancelIrql);
  196. P4CompleteRequest( Irp, Irp->IoStatus.Status, Irp->IoStatus.Information );
  197. return;
  198. }