Using IRP to notify user

Hello,
My app calls DeviceIoControl, the driver marks the IRP as STATUS_PENDING and copies the IRP pointer to a global variable.

if( g_notificationIrp == NULL )
{
	IoMarkIrpPending(Irp);
	g_notificationIrp = Irp;
	return STATUS_PENDING;
}

The app waits for notification. When the driver wants to send the notification, it grabs the global IRP pointer, puts the data in it and completes it via IoCompleteRequest.

if( g_notificationIrp != NULL )
{
  RtlCopyBytes(g_notificationIrp->AssociatedIrp.SystemBuffer, &notificationData, sizeof(Notification_t));
  g_notificationIrp->IoStatus.Information = sizeof(Notification_t);
  g_notificationIrp->IoStatus.Status = STATUS_SUCCESS;
  IoCompleteRequest(g_notificationIrp, IO_NO_INCREMENT);
  g_notificationIrp = NULL; // is this a problem?
}

The app receives the data and calls DeviceIoControl again immediately to wait for the next notification.
Can I set my global IRP pointer to NULL right after calling IoCompleteRequest, before my app calls DeviceIoControl again? I am asking about the race condition here. Is it possible that setting the global IRP pointer to NULL happen after my app calls DeviceIoControl?

P.S. I set my global IRP pointer to NULL using IoSetCancelRoutine in case of cancellation.

Yes sure you need to protect g_notificationIrp from concurrent access.

1 Like

Thank you. So I have to use ExInitializeFastMutex, ExAcquireFastMutex and ExReleaseFastMutex but I coudn't find the API for closing the handle to the fast mutex like ExCloseFastMutex. Do you know how to close the fast mutex handle by any chance? Should I use ZwClose for it?

No. You can use _InterlockedExchangePointer for this. It's a compiler intrinsic.

PIRP pTemp = _InterlockedExchangePointer( &g_notificationIrp, 0 );
if( pTemp )
{
   ...
}
2 Likes

Thank you. Is it fine to use _InterlockedExchangePointer at the cancel routine of IoSetCancelRoutine? Or I should use KeInitializeSpinLock?

Yes. It’s perfectly OK.

1 Like

Thank you. In the Microsoft example the KeAcquireSpinLock was used, so I thought that's something special for the IRP queue.

A global isn’t a queue. Why not use an IOCQ and not roll your own buggy cancel handling logic ?

1 Like

Because I'm noob. Can you please tell me a few keywords so I can research on them?

1 Like

Thank you. Btw should a cancelled request go through IoCompleteRequest?

Once it is safe to complete it, yes

1 Like

As I said, "_InterlockedExchangePointer" is a compiler intrinsic. It compiles to a single CPU instruction. It has no operating system impact at all. You can use it anywhere.

1 Like