ReactOS 0.4.16-dev-292-gbbdcc14
csq.c File Reference
#include <ntdef.h>
#include <ntifs.h>
Include dependency graph for csq.c:

Go to the source code of this file.

Macros

#define DECLSPEC_IMPORT
 

Functions

 _Function_class_ (DRIVER_CANCEL)
 Cancel routine that is installed on any IRP that this library manages.
 
NTSTATUS NTAPI IoCsqInitialize (_Out_ PIO_CSQ Csq, _In_ PIO_CSQ_INSERT_IRP CsqInsertIrp, _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp)
 Set up a CSQ struct to initialize the queue.
 
NTSTATUS NTAPI IoCsqInitializeEx (_Out_ PIO_CSQ Csq, _In_ PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx, _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp)
 Set up a CSQ struct to initialize the queue (extended version)
 
VOID NTAPI IoCsqInsertIrp (_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context)
 Insert an IRP into the CSQ.
 
NTSTATUS NTAPI IoCsqInsertIrpEx (_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context, _In_opt_ PVOID InsertContext)
 Insert an IRP into the CSQ, with additional tracking context.
 
PIRP NTAPI IoCsqRemoveIrp (_Inout_ PIO_CSQ Csq, _Inout_ PIO_CSQ_IRP_CONTEXT Context)
 Remove anb IRP from the queue.
 
PIRP NTAPI IoCsqRemoveNextIrp (_Inout_ PIO_CSQ Csq, _In_opt_ PVOID PeekContext)
 IoCsqRemoveNextIrp - Removes the next IRP from the queue.
 

Macro Definition Documentation

◆ DECLSPEC_IMPORT

#define DECLSPEC_IMPORT

Definition at line 29 of file csq.c.

Function Documentation

◆ _Function_class_()

_Function_class_ ( DRIVER_CANCEL  )

Cancel routine that is installed on any IRP that this library manages.

Parameters
DeviceObject
Irp
Note
  • We assume that Irp->Tail.Overlay.DriverContext[3] has either a IO_CSQ or an IO_CSQ_IRP_CONTEXT in it, but we have to figure out which it is
  • By the time this routine executes, the I/O Manager has already cleared the cancel routine pointer in the IRP, so it will only be canceled once
  • Because of this, we're guaranteed that Irp is valid the whole time
  • Don't forget to release the cancel spinlock ASAP --> #1 hot lock in the system
  • May be called at high IRQL

Definition at line 49 of file csq.c.

56{
58 KIRQL Irql;
59
60 /* First things first: */
61 IoReleaseCancelSpinLock(Irp->CancelIrql);
62
63 /* We could either get a context or just a csq */
64 Csq = (PIO_CSQ)Irp->Tail.Overlay.DriverContext[3];
65
67 {
69 Csq = Context->Csq;
70
71 /* clean up context while we're here */
72 Context->Irp = NULL;
73 }
74
75 /* Now that we have our CSQ, complete the IRP */
79
81}
struct _IO_CSQ_IRP_CONTEXT * PIO_CSQ_IRP_CONTEXT
_In_ PIRP Irp
Definition: csq.h:116
struct _IO_CSQ * PIO_CSQ
Definition: csq.h:69
_Out_ PKIRQL Irql
Definition: csq.h:179
#define IO_TYPE_CSQ_IRP_CONTEXT
Definition: csq.h:78
IO_CSQ Csq
Definition: csqrtns.c:46
#define NULL
Definition: types.h:112
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
Definition: csq.h:222
PIO_CSQ_RELEASE_LOCK CsqReleaseLock
Definition: csq.h:228
PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock
Definition: csq.h:227
PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
Definition: csq.h:229
PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: csq.h:225
ULONG Type
Definition: csq.h:223

◆ IoCsqInitialize()

NTSTATUS NTAPI IoCsqInitialize ( _Out_ PIO_CSQ  Csq,
_In_ PIO_CSQ_INSERT_IRP  CsqInsertIrp,
_In_ PIO_CSQ_REMOVE_IRP  CsqRemoveIrp,
_In_ PIO_CSQ_PEEK_NEXT_IRP  CsqPeekNextIrp,
_In_ PIO_CSQ_ACQUIRE_LOCK  CsqAcquireLock,
_In_ PIO_CSQ_RELEASE_LOCK  CsqReleaseLock,
_In_ PIO_CSQ_COMPLETE_CANCELED_IRP  CsqCompleteCanceledIrp 
)

Set up a CSQ struct to initialize the queue.

Parameters
Csq- Caller-allocated non-paged space for our IO_CSQ to be initialized
CsqInsertIrp- Insert routine
CsqRemoveIrp- Remove routine
CsqPeekNextIrp- Routine to paeek at the next IRP in queue
CsqAcquireLock- Acquire the queue's lock
CsqReleaseLock- Release the queue's lock
CsqCompleteCanceledIrp- Routine to complete IRPs when they are canceled
Returns
  • STATUS_SUCCESS in all cases
Note
  • Csq must be non-paged, as the queue is manipulated with a held spinlock

Definition at line 103 of file csq.c.

111{
120
121 return STATUS_SUCCESS;
122}
#define IO_TYPE_CSQ
Definition: csq.h:79
#define STATUS_SUCCESS
Definition: shellext.h:65
PVOID ReservePointer
Definition: csq.h:230
PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: csq.h:226
PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: csq.h:224
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK _In_ PIO_CSQ_RELEASE_LOCK _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
Definition: iofuncs.h:1893
_In_ PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: iofuncs.h:1888
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: iofuncs.h:1890
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock
Definition: iofuncs.h:1891
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: iofuncs.h:1889
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock
Definition: iofuncs.h:1892

Referenced by DriverEntry(), MsfsCreateMailslot(), and USBPORT_StartDevice().

◆ IoCsqInitializeEx()

NTSTATUS NTAPI IoCsqInitializeEx ( _Out_ PIO_CSQ  Csq,
_In_ PIO_CSQ_INSERT_IRP_EX  CsqInsertIrpEx,
_In_ PIO_CSQ_REMOVE_IRP  CsqRemoveIrp,
_In_ PIO_CSQ_PEEK_NEXT_IRP  CsqPeekNextIrp,
_In_ PIO_CSQ_ACQUIRE_LOCK  CsqAcquireLock,
_In_ PIO_CSQ_RELEASE_LOCK  CsqReleaseLock,
_In_ PIO_CSQ_COMPLETE_CANCELED_IRP  CsqCompleteCanceledIrp 
)

Set up a CSQ struct to initialize the queue (extended version)

Parameters
Csq- Caller-allocated non-paged space for our IO_CSQ to be initialized
CsqInsertIrpEx- Extended insert routine
CsqRemoveIrp- Remove routine
CsqPeekNextIrp- Routine to paeek at the next IRP in queue
CsqAcquireLock- Acquire the queue's lock
CsqReleaseLock- Release the queue's lock
CsqCompleteCanceledIrp- Routine to complete IRPs when they are canceled
Returns
  • STATUS_SUCCESS in all cases
Note
  • Csq must be non-paged, as the queue is manipulated with a held spinlock

Definition at line 143 of file csq.c.

151{
160
161 return STATUS_SUCCESS;
162}
IO_CSQ_INSERT_IRP * PIO_CSQ_INSERT_IRP
Definition: csq.h:117
#define IO_TYPE_CSQ_EX
Definition: csq.h:238
NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
Definition: csqtest.c:82

Referenced by FsRtlPrivateLock(), and InitializeMessageWaiterQueue().

◆ IoCsqInsertIrp()

VOID NTAPI IoCsqInsertIrp ( _Inout_ PIO_CSQ  Csq,
_Inout_ PIRP  Irp,
_Out_opt_ PIO_CSQ_IRP_CONTEXT  Context 
)

Insert an IRP into the CSQ.

Parameters
Csq- Pointer to the initialized CSQ
Irp- Pointer to the IRP to queue
Context- Context record to track the IRP while queued
Returns
  • Just passes through to IoCsqInsertIrpEx, with no InsertContext

Definition at line 177 of file csq.c.

181{
183}
NTSTATUS NTAPI IoCsqInsertIrpEx(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context, _In_opt_ PVOID InsertContext)
Insert an IRP into the CSQ, with additional tracking context.
Definition: csq.c:205

Referenced by DeviceIoctl(), DispatchReadWrite(), MsfsRead(), ReadWrite(), USBPORT_DoIdleNotificationCallback(), USBPORT_HandleSubmitURB(), and USBPORT_IdleNotification().

◆ IoCsqInsertIrpEx()

NTSTATUS NTAPI IoCsqInsertIrpEx ( _Inout_ PIO_CSQ  Csq,
_Inout_ PIRP  Irp,
_Out_opt_ PIO_CSQ_IRP_CONTEXT  Context,
_In_opt_ PVOID  InsertContext 
)

Insert an IRP into the CSQ, with additional tracking context.

Parameters
Csq- Pointer to the initialized CSQ
Irp- Pointer to the IRP to queue
Context- Context record to track the IRP while queued
InsertContext- additional data that is passed through to CsqInsertIrpEx
Note
  • Passes the additional context through to the driver-supplied callback, which can be used with more sophistocated queues
  • Marks the IRP pending in all cases
  • Guaranteed to not queue a canceled IRP
  • This is complicated logic, and is patterend after the Microsoft library. I'm sure I have gotten the details wrong on a fine point or two, but basically this works with the MS-supplied samples.

Definition at line 205 of file csq.c.

210{
211 NTSTATUS Retval = STATUS_SUCCESS;
212 KIRQL Irql;
213
215
216 do
217 {
218 /* mark all irps pending -- says so in the cancel sample */
220
221 /* set up the context if we have one */
222 if(Context)
223 {
225 Context->Irp = Irp;
226 Context->Csq = Csq;
227 Irp->Tail.Overlay.DriverContext[3] = Context;
228 }
229 else
230 Irp->Tail.Overlay.DriverContext[3] = Csq;
231
232 /*
233 * NOTE! This is very sensitive to order. If you set the cancel routine
234 * *before* you queue the IRP, our cancel routine will get called back for
235 * an IRP that isn't in its queue.
236 *
237 * There are three possibilities:
238 * 1) We get an IRP, we queue it, and it is valid the whole way
239 * 2) We get an IRP, and the IO manager cancels it before we're done here
240 * 3) We get an IRP, queue it, and the IO manager cancels it.
241 *
242 * #2 is is a booger.
243 *
244 * When the IO manger receives a request to cancel an IRP, it sets the cancel
245 * bit in the IRP's control byte to TRUE. Then, it looks to see if a cancel
246 * routine is set. If it isn't, the IO manager just returns to the caller.
247 * If there *is* a routine, it gets called.
248 *
249 * If we test for cancel first and then set the cancel routine, there is a spot
250 * between test and set that the IO manager can cancel us without our knowledge,
251 * so we miss a cancel request. That is bad.
252 *
253 * If we set a routine first and then test for cancel, we race with our completion
254 * routine: We set the routine, the IO Manager sets cancel, we test cancel and find
255 * it is TRUE. Meanwhile the IO manager has called our cancel routine already, so
256 * we can't complete the IRP because it'll rip it out from under the cancel routine.
257 *
258 * The IO manager does us a favor though: it nulls out the cancel routine in the IRP
259 * before calling it. Therefore, if we test to see if the cancel routine is NULL
260 * (after we have just set it), that means our own cancel routine is already working
261 * on the IRP, and we can just return quietly. Otherwise, we have to de-queue the
262 * IRP and cancel it ourselves.
263 *
264 * We have to go through all of this mess because this API guarantees that we will
265 * never return having left a canceled IRP in the queue.
266 */
267
268 /* Step 1: Queue the IRP */
269 if(Csq->Type == IO_TYPE_CSQ)
271 else
272 {
274 Retval = pCsqInsertIrpEx(Csq, Irp, InsertContext);
275 if(Retval != STATUS_SUCCESS)
276 break;
277 }
278
279 /* Step 2: Set our cancel routine */
280 (void)IoSetCancelRoutine(Irp, IopCsqCancelRoutine);
281
282 /* Step 3: Deal with an IRP that is already canceled */
283 if(!Irp->Cancel)
284 break;
285
286 /*
287 * Since we're canceled, see if our cancel routine is already running
288 * If this is NULL, the IO Manager has already called our cancel routine
289 */
291 break;
292
293
294 Irp->Tail.Overlay.DriverContext[3] = 0;
295
296 /* OK, looks like we have to de-queue and complete this ourselves */
299
300 if(Context)
301 Context->Irp = NULL;
302 }
303 while(0);
304
306
307 return Retval;
308}
LONG NTSTATUS
Definition: precomp.h:26
_In_ PIRP _In_ PVOID InsertContext
Definition: csq.h:258
IO_CSQ_INSERT_IRP_EX * PIO_CSQ_INSERT_IRP_EX
Definition: csq.h:259
IoMarkIrpPending(Irp)
IoSetCancelRoutine(Irp, CancelRoutine)

Referenced by FsRtlFastUnlockSingle(), FsRtlPrivateLock(), and IoCsqInsertIrp().

◆ IoCsqRemoveIrp()

PIRP NTAPI IoCsqRemoveIrp ( _Inout_ PIO_CSQ  Csq,
_Inout_ PIO_CSQ_IRP_CONTEXT  Context 
)

Remove anb IRP from the queue.

Parameters
Csq- Queue to remove the IRP from
Context- Context record containing the IRP to be dequeued
Returns
  • Pointer to an IRP if we found it
Note
  • Don't forget that we can be canceled any time up to the point where we unset our cancel routine

Definition at line 326 of file csq.c.

329{
330 KIRQL Irql;
331 PIRP Irp = NULL;
332
334
335 do
336 {
337 /* It's possible that this IRP could have been canceled */
338 Irp = Context->Irp;
339
340 if(!Irp)
341 break;
342
343 ASSERT(Context->Csq == Csq);
344
345 /* Unset the cancel routine and see if it has already been canceled */
347 {
348 /*
349 * already gone, return NULL --> NOTE that we cannot touch this IRP *or* the context,
350 * since the context is being simultaneously twiddled by the cancel routine
351 */
352 Irp = NULL;
353 break;
354 }
355
356 ASSERT(Context == Irp->Tail.Overlay.DriverContext[3]);
357
358 /* This IRP is valid and is ours. Dequeue it, fix it up, and return */
360
361 Context = (PIO_CSQ_IRP_CONTEXT)InterlockedExchangePointer(&Irp->Tail.Overlay.DriverContext[3], NULL);
362
364 {
365 Context->Irp = NULL;
366
367 ASSERT(Context->Csq == Csq);
368 }
369
370 Irp->Tail.Overlay.DriverContext[3] = 0;
371 }
372 while(0);
373
375
376 return Irp;
377}
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
#define ASSERT(a)
Definition: mode.c:44

Referenced by MsfsTimeout().

◆ IoCsqRemoveNextIrp()

PIRP NTAPI IoCsqRemoveNextIrp ( _Inout_ PIO_CSQ  Csq,
_In_opt_ PVOID  PeekContext 
)

IoCsqRemoveNextIrp - Removes the next IRP from the queue.

Parameters
Csq- Queue to remove the IRP from
PeekContext- Identifier of the IRP to be removed
Returns
Pointer to the IRP that was removed, or NULL if one could not be found
Note
  • This function is sensitive to yet another race condition. The basic idea is that we have to return the first IRP that we get that matches the PeekContext >that is not already canceled<. Therefore, we have to do a trick similar to the one done in Insert above.

Definition at line 398 of file csq.c.

401{
402 KIRQL Irql;
403 PIRP Irp = NULL;
405
407
408 while((Irp = Csq->CsqPeekNextIrp(Csq, Irp, PeekContext)))
409 {
410 /*
411 * If the cancel routine is gone, we're already canceled,
412 * and are spinning on the queue lock in our own cancel
413 * routine. Move on to the next candidate. It'll get
414 * removed by the cance routine.
415 */
417 continue;
418
420
421 /* Unset the context stuff and return */
422 Context = (PIO_CSQ_IRP_CONTEXT)InterlockedExchangePointer(&Irp->Tail.Overlay.DriverContext[3], NULL);
423
425 {
426 Context->Irp = NULL;
427
428 ASSERT(Context->Csq == Csq);
429 }
430
431 Irp->Tail.Overlay.DriverContext[3] = 0;
432
433 break;
434 }
435
437
438 return Irp;
439}
_In_opt_ PIRP _In_opt_ PVOID PeekContext
Definition: csq.h:160

Referenced by DispatchCreateCloseCleanup(), DispatchIoctl(), FsRtlFastUnlockSingle(), FsRtlUninitializeFileLock(), MsfsWrite(), QueueThread(), USBPORT_BadRequestFlush(), USBPORT_CompletePendingIdleIrp(), and USBPORT_DoIdleNotificationCallback().