Leaked source code of windows server 2003
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.

287 lines
8.3 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. if (!Pdx->TimeToTerminateThread)
  136. {
  137. // set the flag for the worker thread to kill itself
  138. Pdx->TimeToTerminateThread = TRUE;
  139. // wake up the thread so it can kill itself
  140. KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE );
  141. }
  142. // error, go ahead and close the thread handle
  143. ZwClose(ThreadHandle);
  144. } else {
  145. // Now that we have a reference to the thread we can simply close the handle.
  146. ZwClose(ThreadHandle);
  147. }
  148. DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s - SUCCESS\n",Pdx->Location);
  149. } else {
  150. DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s FAIL - status = %x\n",Pdx->Location, Status);
  151. }
  152. return Status;
  153. }
  154. VOID
  155. PptPdoStartIo(
  156. IN PPDO_EXTENSION Pdx
  157. )
  158. /*++
  159. Routine Description:
  160. This routine starts an I/O operation for the driver and
  161. then returns
  162. Arguments:
  163. Pdx - The parallel device extension
  164. Return Value:
  165. None
  166. --*/
  167. {
  168. PIRP Irp;
  169. PIO_STACK_LOCATION IrpSp;
  170. KIRQL CancelIrql;
  171. Irp = Pdx->CurrentOpIrp;
  172. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  173. Irp->IoStatus.Information = 0;
  174. if (!Pdx->Connected && !ParAllocPort(Pdx)) {
  175. // #pragma message( "dvrh Left bad stuff in thread.c")
  176. DD((PCE)Pdx,DDE,"PptPdoStartIo - %s - threads are hosed\n",Pdx->Location);
  177. // __asm int 3
  178. //
  179. // If the allocation didn't succeed then fail this IRP.
  180. //
  181. goto CompleteIrp;
  182. }
  183. switch (IrpSp->MajorFunction) {
  184. case IRP_MJ_WRITE:
  185. ParWriteIrp(Pdx);
  186. break;
  187. case IRP_MJ_READ:
  188. ParReadIrp(Pdx);
  189. break;
  190. default:
  191. ParDeviceIo(Pdx);
  192. break;
  193. }
  194. if (!Pdx->Connected && !Pdx->AllocatedByLockPort) {
  195. // if we're not connected in a 1284 mode, then release host port
  196. // otherwise let the watchdog timer do it.
  197. ParFreePort(Pdx);
  198. }
  199. CompleteIrp:
  200. IoAcquireCancelSpinLock(&CancelIrql);
  201. Pdx->CurrentOpIrp = NULL;
  202. IoReleaseCancelSpinLock(CancelIrql);
  203. P4CompleteRequest( Irp, Irp->IoStatus.Status, Irp->IoStatus.Information );
  204. return;
  205. }