SetConsoleCtrlHandler

Hi,

I have written a driver and a console application (called api henceforth).
When i press a CTRL-C or a CTRL-Break key, SetConsoleCtrlHandler helps me handle the signals by means of an application defined function.
Is there any way to detect that signal/event (CTRL-C or a CTRL-Break key press) in the driver that the api is using?

The big picture is this - the api issues a ReadFile in my case. The driver is pending this request because it is waiting on a kernel object to get signalled. In such a scenario, how will i gracefully exit the API?

Any help or pointers to the msdn or other relevant sites are greatly appreciated.

Thanks in advance.

Use CancelIo() when app receives break. Your driver has to support IRP cancellation, of course, but it has to do anyway.

Please do not use standard abbreviations (API) with different meaning; it makes your post hard to read.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]


From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of xxxxx@gmail.com[SMTP:xxxxx@gmail.com]
Reply To: Windows System Software Devs Interest List
Sent: Tuesday, March 27, 2007 9:46 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] SetConsoleCtrlHandler

Hi,

I have written a driver and a console application (called api henceforth).
When i press a CTRL-C or a CTRL-Break key, SetConsoleCtrlHandler helps me handle the signals by means of an application defined function.
Is there any way to detect that signal/event (CTRL-C or a CTRL-Break key press) in the driver that the api is using?

The big picture is this - the api issues a ReadFile in my case. The driver is pending this request because it is waiting on a kernel object to get signalled. In such a scenario, how will i gracefully exit the API?

Any help or pointers to the msdn or other relevant sites are greatly appreciated.

Thanks in advance.


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

xxxxx@gmail.com wrote:

I have written a driver and a console application (called api henceforth).
When i press a CTRL-C or a CTRL-Break key, SetConsoleCtrlHandler helps me handle the signals by means of an application defined function.
Is there any way to detect that signal/event (CTRL-C or a CTRL-Break key press) in the driver that the api is using?

No. Those are all Win32 things that are outside the knowledge of the
kernel.

The big picture is this - the api issues a ReadFile in my case. The driver is pending this request because it is waiting on a kernel object to get signalled. In such a scenario, how will i gracefully exit the API?

This is tricky. The standard ctrl-C handler calls ExitProcess, which
causes I/O requests to be canceled. If you hope to recover and continue
execution, then you will probably have to switch to overlapped I/O.
After calling ReadFile, you can use WaitForMultipleObjects to wait for
the overlapped event plus an “exit” event. Then, your ctrl-C handler
can fire the “exit” event, and the thread can call CancelIo.

Another possibility is to add a “cancel all operations” ioctl to your
driver. You’d have to send that through a second device instance, so
I’m not sure that’s a very good solution.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Michal Vodicka wrote:

Use CancelIo() when app receives break. Your driver has to support IRP cancellation, of course, but it has to do anyway.

The tricky thing about CancelIo is that it can only be called by the
thread that submitted the I/O. Hence, the need for overlapped I/O and a
signalling event of some kind. Vista adds a CancelSynchronousIo API
that lets you cancels an outstanding request in another thread, but
earlier systems don’t have that.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> ----------

From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of Tim Roberts[SMTP:xxxxx@probo.com]
Reply To: Windows System Software Devs Interest List
Sent: Tuesday, March 27, 2007 10:24 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] SetConsoleCtrlHandler

Michal Vodicka wrote:
> Use CancelIo() when app receives break. Your driver has to support IRP cancellation, of course, but it has to do anyway.

The tricky thing about CancelIo is that it can only be called by the
thread that submitted the I/O. Hence, the need for overlapped I/O and a
signalling event of some kind. Vista adds a CancelSynchronousIo API
that lets you cancels an outstanding request in another thread, but
earlier systems don’t have that.

You’re right. I automatically presumed OP uses overlapped IO for reads which can be pended for relatively long time by driver. Which may not be a case.

For synchronous IO your idea with special IOCTL would also solve problem. I don’t see a need for a second device instance. Why don’t use the same handle from console handler or maybe duplicated handle? Maybe I’m missing something as I use overlapped IO almost always.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

If you don’t open a handle for overlapped IO, your requests through that
handle will be synchronized, hence needing a second device instance.

-Jeff

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Michal Vodicka
Sent: Tuesday, March 27, 2007 4:55 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] SetConsoleCtrlHandler


From:
xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com
] on behalf of Tim Roberts[SMTP:xxxxx@probo.com]
Reply To: Windows System Software Devs Interest List
Sent: Tuesday, March 27, 2007 10:24 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] SetConsoleCtrlHandler

Michal Vodicka wrote:
> Use CancelIo() when app receives break. Your driver has to support
IRP cancellation, of course, but it has to do anyway.

The tricky thing about CancelIo is that it can only be called by the
thread that submitted the I/O. Hence, the need for overlapped I/O and
a
signalling event of some kind. Vista adds a CancelSynchronousIo API
that lets you cancels an outstanding request in another thread, but
earlier systems don’t have that.

You’re right. I automatically presumed OP uses overlapped IO for reads
which can be pended for relatively long time by driver. Which may not be
a case.

For synchronous IO your idea with special IOCTL would also solve
problem. I don’t see a need for a second device instance. Why don’t use
the same handle from console handler or maybe duplicated handle? Maybe
I’m missing something as I use overlapped IO almost always.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Michal Vodicka wrote:

For synchronous IO your idea with special IOCTL would also solve problem. I don’t see a need for a second device instance. Why don’t use the same handle from console handler or maybe duplicated handle? Maybe I’m missing something as I use overlapped IO almost always.

Because, unless you use overlapped I/O, you can only have one request
outstanding on a given handle. As long as the non-overlapped ReadFile
is pending, I can’t submit a DeviceIoControl.

I didn’t think a duplicate handle would work around that. Don’t both
handles refer to the same FILE_OBJECT, and isn’t the serialization done
at the FILE_OBJECT level?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hi All,
Thanks for your inputs.
So, if i understand right, this is what i should be doing -

  1. Create the device handle with FILE_FLAG_OVERLAPPED flag set
  2. Create an event event_from_ReadFile in the overlapped structure
  3. Call ReadFile
  4. WaitOnMultipleObjects(event_from_ReadFile, event_from_Ctrl_C)
  5. If event_from_Ctrl_C is signalled, call CancelIo
  6. If event_from_ReadFile is signalled, continue with whatever it is that i have to do

Quick questions, what are the IRP_MJ_CODE (on the driver side) corresponding dispatch_routines to the CancelIo win32 call? Is it DispatchCleanup or DispatchClose or something else? Oh yes, this is a USB driver that i am writing.

Thanks all.

Tim, you are correct, the serialization happens at the file object level and DuplicateHandle will not create a new file object. You must open a 2nd handle explicitly.

vj, there is no IRP_MJ_XXX routine for cancelation of a request, you must set a CancelRoutine in the request and implement cancelation. You should either use KMDF or use an IoCSQ to implement cancelation logic. If you are taking a request from your application and just sending it down the stack to the USB core, it is the USB core’s responsibility to set a cancelation routine (only the current owner of the IRP can set a cancel routine).

d

[Sorry if this post is a dup. For whatever reason, messages I send sometimes have attachments (even when sending “plain text”!), and the list software rightly stops these messages.]

That’s close, but there is one important detail missing. As someone else pointed out, CancelIo can only cancel the IRPs that were created by the calling thread. (CancelIo walks an IRP list whose list head is in the thread structure.) But unfortunately, you don’t have control over which thread runs the handler that you provide to SetConsoleCtrlHandler. The details are uninteresting, but in most cases, the thread that calls your handler function will NOT be the same as the thread that issued the async I/O. Consider this program:

BOOL CALLBACK ControlHandler(DWORD control) {
_tprintf(_T(“[tid %08x] ControlHandler: control = %d\r\n”), GetCurrentThreadId(), control);

switch (control) {
case CTRL_C_EVENT:
_tprintf(_T(“[tid %08x] ControlHandler: Received CTRL_C_EVENT\r\n”), GetCurrentThreadId());
return TRUE;

default:
_tprintf(_T(“[tid %08x] ControlHandler: Received unknown control, ignoring\r\n”), GetCurrentThreadId());
return FALSE;
}
}

int _tmain(int argc, _TCHAR* argv)
{

SetConsoleCtrlHandler(ControlHandler, TRUE);

for (;:wink: {
_tprintf(_T(“[tid %08x] Waiting…\r\n”), GetCurrentThreadId());
SleepEx(INFINITE, TRUE);
}
return 0;
}

If you run this program, and then press control-C, you’ll see that the “Waiting” message is printed with a different thread ID than the “Received CTRL_C_EVENT” message. So you will need to take this into consideration.

On NT kernels that predate the Vista/Longhorn code base, the best solution is to send some sort of message to your main thread, telling it to cancel the async I/O requests. (Even for Vista/LH, this is a good approach.) You can use whatever mechanism you want to accomplish this: APCs, events, PostMessage, I/O completion ports, etc. If you go with events, then you will have some sort of “HANDLE ControlCPressedEvent”, which you create when your app starts. In your control-C handler, you’ll call SetEvent(ControlCPressedEvent), and in your main I/O loop, you’ll monitor that event sing WaitForMultipleObjects. When that event fires, call CancelIo on your file handle (which, as pointed out before, must be opened in async mode).

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Tuesday, March 27, 2007 6:25 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] SetConsoleCtrlHandler

Hi All,
Thanks for your inputs.
So, if i understand right, this is what i should be doing -

  1. Create the device handle with FILE_FLAG_OVERLAPPED flag set 2. Create an event event_from_ReadFile in the overlapped structure 2. Call ReadFile 3. WaitOnMultipleObjects(event_from_ReadFile, event_from_Ctrl_C) 4. If event_from_Ctrl_C is signalled, call CancelIo 5. If event_from_ReadFile is signalled, continue with whatever it is that i have to do

Quick questions, what are the IRP_MJ_CODE (on the driver side) corresponding dispatch_routines to the CancelIo win32 call? Is it DispatchCleanup or DispatchClose or something else? Oh yes, this is a USB driver that i am writing.

Thanks all.


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> ----------

From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of xxxxx@Microsoft.com[SMTP:xxxxx@Microsoft.com]
Reply To: Windows System Software Devs Interest List
Sent: Wednesday, March 28, 2007 12:41 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] SetConsoleCtrlHandler

Tim, you are correct, the serialization happens at the file object level and DuplicateHandle will not create a new file object. You must open a 2nd handle explicitly.

OK, thanks. Thinking about it, I probably haven’t used synchronous IO for past 5 years :slight_smile:

Just curious, is IRP_MJ_CLEANUP also serialized? I.e. when app closes handle from the second thread, would it wait until current sync request is processed?

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

> The big picture is this - the api issues a ReadFile in my case. The driver is

pending this request because it is waiting on a kernel object to get
signalled. In
such a scenario, how will i gracefully exit the API?

Support cancellation of such IRP.

BTW - waiting in dispatch routine is a bad idea. Instead, pend the IRP (in KMDF
queue or such) with cancellation support, and, instead of signaling the kernel
object, take the IRP from the queue and complete it, possibly filling it with
data.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Michal Vodicka wrote:

> ----------
> From: xxxxx@Microsoft.com[SMTP:xxxxx@Microsoft.com]
>
> Tim, you are correct, the serialization happens at the file object level and DuplicateHandle will not create a new file object. You must open a 2nd handle explicitly.
>
OK, thanks. Thinking about it, I probably haven’t used synchronous IO for past 5 years :slight_smile:

Just curious, is IRP_MJ_CLEANUP also serialized? I.e. when app closes handle from the second thread, would it wait until current sync request is processed?

IRP_MJ_CLEANUP won’t be called until the last handle to that file object
is closed, but that last CloseHandle call should be serialized, too.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> I didn’t think a duplicate handle would work around that. Don’t both

handles refer to the same FILE_OBJECT, and isn’t the serialization done
at the FILE_OBJECT level?

Correct. The on-the-knee-made mutex is in FILE_OBJECT fields, and
DuplicateHandle will reuse existing FILE_OBJECT.

Call CreateFile second time to avoid this bottleneck.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com