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.

446 lines
9.9 KiB

  1. #include "internal.h"
  2. #pragma alloc_text(PAGE,InitializePacketQueue)
  3. VOID
  4. InitializePacketQueue(
  5. PPACKET_QUEUE PacketQueue,
  6. PVOID Context,
  7. PACKET_STARTER StarterRoutine
  8. )
  9. {
  10. RtlZeroMemory(PacketQueue,sizeof(*PacketQueue));
  11. KeInitializeSpinLock(&PacketQueue->Lock);
  12. PacketQueue->Context=Context;
  13. PacketQueue->Starter=StarterRoutine;
  14. PacketQueue->Active=TRUE;
  15. KeInitializeEvent(&PacketQueue->InactiveEvent,NotificationEvent,FALSE);
  16. InitializeListHead(&PacketQueue->ListHead);
  17. return;
  18. }
  19. VOID
  20. IrpQueueCancelRoutine(
  21. PDEVICE_OBJECT DeviceObject,
  22. PIRP Irp
  23. )
  24. {
  25. PPACKET_QUEUE PacketQueue;
  26. KIRQL OldIrql;
  27. IoReleaseCancelSpinLock(Irp->CancelIrql);
  28. PacketQueue=Irp->Tail.Overlay.DriverContext[0];
  29. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  30. if (Irp->Tail.Overlay.ListEntry.Flink == NULL) {
  31. //
  32. // the irp has been removed from the queue
  33. //
  34. } else {
  35. //
  36. // the irp is still in the queue, remove it
  37. //
  38. RemoveEntryList(
  39. &Irp->Tail.Overlay.ListEntry
  40. );
  41. }
  42. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  43. Irp->IoStatus.Status=STATUS_CANCELLED;
  44. Irp->IoStatus.Information=0;
  45. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  46. return;
  47. }
  48. PIRP
  49. GetUseableIrp(
  50. PLIST_ENTRY List
  51. )
  52. {
  53. PIRP Packet=NULL;
  54. while ( (Packet == NULL) && !IsListEmpty(List)) {
  55. //
  56. // there is a packet queued
  57. //
  58. PLIST_ENTRY ListEntry;
  59. ListEntry=RemoveTailList(List);
  60. Packet=CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
  61. if (IoSetCancelRoutine(Packet,NULL) == NULL) {
  62. //
  63. // The cancel rountine has run and is waiting on the queue spinlock,
  64. // set the flink to null so the cancel routine knows not to try
  65. // take the irp off the list
  66. //
  67. Packet->Tail.Overlay.ListEntry.Flink=NULL;
  68. Packet=NULL;
  69. //
  70. // try to get another one
  71. //
  72. }
  73. }
  74. return Packet;
  75. }
  76. VOID
  77. QueuePacket(
  78. PPACKET_QUEUE PacketQueue,
  79. PIRP Packet,
  80. BOOLEAN InsertAtFront
  81. )
  82. {
  83. NTSTATUS Status;
  84. KIRQL OldIrql;
  85. KIRQL CancelIrql;
  86. BOOLEAN Canceled=FALSE;
  87. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  88. if ((PacketQueue->CurrentPacket == NULL) && PacketQueue->Active && (IsListEmpty(&PacketQueue->ListHead))) {
  89. //
  90. // not currently handling a packet and the queue is active and there are not other packets
  91. // queued, so handle it now
  92. //
  93. PacketQueue->CurrentPacket=Packet;
  94. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  95. (*PacketQueue->Starter)(
  96. PacketQueue->Context,
  97. Packet
  98. );
  99. return;
  100. }
  101. Packet->Tail.Overlay.DriverContext[0]=PacketQueue;
  102. IoAcquireCancelSpinLock(&CancelIrql);
  103. if (Packet->Cancel) {
  104. //
  105. // the irp has already been canceled
  106. //
  107. Canceled=TRUE;
  108. } else {
  109. IoSetCancelRoutine(
  110. Packet,
  111. IrpQueueCancelRoutine
  112. );
  113. }
  114. IoReleaseCancelSpinLock(CancelIrql);
  115. //
  116. // need to queue the packet
  117. //
  118. if (!Canceled) {
  119. if (InsertAtFront) {
  120. //
  121. // this one is high priorty for some reason, put it at the front
  122. //
  123. InsertTailList(&PacketQueue->ListHead,&Packet->Tail.Overlay.ListEntry);
  124. } else {
  125. InsertHeadList(&PacketQueue->ListHead,&Packet->Tail.Overlay.ListEntry);
  126. }
  127. }
  128. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  129. if (Canceled) {
  130. //
  131. // complete the canceled irp now
  132. //
  133. Packet->IoStatus.Status=STATUS_CANCELLED;
  134. Packet->IoStatus.Information=0;
  135. IoCompleteRequest(Packet,IO_NO_INCREMENT);
  136. }
  137. return;
  138. }
  139. VOID
  140. StartNextPacket(
  141. PPACKET_QUEUE PacketQueue
  142. )
  143. {
  144. KIRQL OldIrql;
  145. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  146. ASSERT(PacketQueue->CurrentPacket != NULL);
  147. //
  148. // done with this one
  149. //
  150. PacketQueue->CurrentPacket=NULL;
  151. if (!PacketQueue->InStartNext) {
  152. //
  153. // not already in this function
  154. //
  155. PacketQueue->InStartNext=TRUE;
  156. while ((PacketQueue->CurrentPacket == NULL) && PacketQueue->Active ) {
  157. //
  158. // there isn't a current packet and the queue is active
  159. //
  160. PIRP Packet;
  161. Packet=GetUseableIrp(&PacketQueue->ListHead);
  162. if (Packet != NULL) {
  163. //
  164. // we got an irp to use
  165. //
  166. // now the current one
  167. //
  168. PacketQueue->CurrentPacket=Packet;
  169. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  170. //
  171. // start the processing
  172. //
  173. (*PacketQueue->Starter)(
  174. PacketQueue->Context,
  175. Packet
  176. );
  177. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  178. } else {
  179. //
  180. // queue is empty, break out of loop
  181. //
  182. break;
  183. }
  184. }
  185. if (!PacketQueue->Active && (PacketQueue->CurrentPacket == NULL)) {
  186. //
  187. // the queue has been paused and we don't have a current packet, signal the event
  188. //
  189. KeSetEvent(
  190. &PacketQueue->InactiveEvent,
  191. IO_NO_INCREMENT,
  192. FALSE
  193. );
  194. }
  195. PacketQueue->InStartNext=FALSE;
  196. }
  197. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  198. return;
  199. }
  200. VOID
  201. PausePacketProcessing(
  202. PPACKET_QUEUE PacketQueue,
  203. BOOLEAN WaitForInactive
  204. )
  205. {
  206. KIRQL OldIrql;
  207. BOOLEAN CurrentlyActive=FALSE;
  208. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  209. PacketQueue->Active=FALSE;
  210. if (PacketQueue->CurrentPacket != NULL) {
  211. //
  212. // there is a packet currently being processed
  213. //
  214. CurrentlyActive=TRUE;
  215. KeClearEvent(&PacketQueue->InactiveEvent);
  216. }
  217. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  218. if (WaitForInactive && CurrentlyActive) {
  219. //
  220. // the caller wants use to wait for the queue to inactive, and it was active when
  221. // theis was called
  222. //
  223. KeWaitForSingleObject(
  224. &PacketQueue->InactiveEvent,
  225. Executive,
  226. KernelMode,
  227. FALSE,
  228. NULL
  229. );
  230. }
  231. return;
  232. }
  233. VOID
  234. ActivatePacketProcessing(
  235. PPACKET_QUEUE PacketQueue
  236. )
  237. {
  238. KIRQL OldIrql;
  239. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  240. PacketQueue->Active=TRUE;
  241. if ((PacketQueue->CurrentPacket == NULL)) {
  242. //
  243. // No packet is currently being used
  244. //
  245. PIRP Packet;
  246. Packet=GetUseableIrp(&PacketQueue->ListHead);
  247. if (Packet != NULL) {
  248. //
  249. // we got an irp to use
  250. //
  251. // now the current one
  252. //
  253. PacketQueue->CurrentPacket=Packet;
  254. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  255. //
  256. // start the processing
  257. //
  258. (*PacketQueue->Starter)(
  259. PacketQueue->Context,
  260. Packet
  261. );
  262. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  263. }
  264. }
  265. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  266. return;
  267. }
  268. VOID
  269. FlushQueuedPackets(
  270. PPACKET_QUEUE PacketQueue,
  271. UCHAR MajorFunction
  272. )
  273. {
  274. KIRQL OldIrql;
  275. PIRP Packet;
  276. LIST_ENTRY TempList;
  277. InitializeListHead(&TempList);
  278. //
  279. // dispose of all of the queue packets, don't touch the current one though
  280. //
  281. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  282. Packet=GetUseableIrp(&PacketQueue->ListHead);
  283. while (Packet != NULL) {
  284. PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Packet);
  285. if ((MajorFunction == 0xff) || (MajorFunction==IrpSp->MajorFunction)) {
  286. //
  287. // either the caller wants all of irps completed, or they just want
  288. // this specific type. In any case this is going to get completed
  289. //
  290. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  291. Packet->IoStatus.Status=STATUS_CANCELLED;
  292. Packet->IoStatus.Information=0;
  293. IoCompleteRequest(Packet,IO_NO_INCREMENT);
  294. KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
  295. } else {
  296. //
  297. // this one does not need to be completed, put it on the temp list
  298. //
  299. InsertHeadList(&TempList,&Packet->Tail.Overlay.ListEntry);
  300. }
  301. Packet=GetUseableIrp(&PacketQueue->ListHead);
  302. }
  303. while (!IsListEmpty(&TempList)) {
  304. //
  305. // move all the irps on the temp queue back to the real queue
  306. //
  307. PLIST_ENTRY ListEntry;
  308. ListEntry=RemoveTailList(&TempList);
  309. InsertHeadList(&PacketQueue->ListHead,ListEntry);
  310. }
  311. KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
  312. return;
  313. }