Not alertable KeWaitForSingleObject()?

I was asked from some reasons replace inside NDIS driver the NdisWaitEvent() on KeWaitForSingleObject().
I like to keep base algorithm and going inside NdisWaitEvent() dissembler (Windbg) to check which parameters it defines for KeWaitForSingleObject().

I found, that 4th parameter is translated as NULL (FALSE):

NdisWaitEvent(&, 0)
translated to
_ KeWaitForSingleObject( &, 0 /Executive/, 0 /KernelMode/, 0 /FALSE!?!/, &); _

The problem in MSDN 4th parameter described as:
Alertable
Specifies a Boolean value that is TRUE if the wait is alertable and FALSE otherwise.

means the KeWaitForSingleObject() will not be completed by clearing appropriate event. if 4th parameter FALSE (timeout is NULL!) !?!

Is it MSDN mistake?
Or I understand term “alertable” not right?

Thanks & Regards,
Michael.

__

The Alertable parameter has to do with whether the wait can be interrupted for a Usermode APC. Passing FALSE still allows the wait to be ended when the waitable object is signaled. There is an MSDN page Waits and APCs that may help explain a bit more.


Jeremy Hurren

Yes, and understand that APCs are one of the more confusing and less fully documented parts of the Windows kernel. Unless you KNOW you need to be APC-aware, and very few drivers do, you should always specify FALSE.

Jeremy,
Thank you for reference.
Read carefully, but I have low level NDIS Miniport driver which uses KernelMode.
.
I’d suggest that for KernelMode parameter Alterable is not used. And it’s reason way NdisWaitEvent() set it to FALSE.
But I like to be sure, that it is correct!
Other source that I checked is Reactor Project. It uses TRUE for Alertable parameter when maps NdisWaitEvent() to KeWaitForSingleObject(). But it’s not 100% source too.

I don’t understand what the issue is. First, I don’t understand your reluctance to use NdisWaitEvent in an NDIS Miniport. This is, after all, the proper way to wait on an event in a Miniport. What do you care how it’s implemented?

Second, I don’t understand your reluctance to just code the kernel-mode wait with alertable set to FALSE. That’s the right thing to do in any case… unless you want the wait to be alertable.

So…

Peter,
Sorry for abstract answer on 1st question. It is not my or my firm reluctance. It’s one of the steps for some future experiments initiated by M…

Second. According MSDN, TRUE is correct value for Alertable parameter, I guess.
FALSE with timeout NULL means infinite waiting!
Or I not understand term “Alertable”.

Because NdisWaitEvent() is really working, I propose that Alertable FALSE is not valid for Kernel Mode.

You do not understand the purpose of “Alertable” it is not related to the object(s) you are waiting on, it is related to things like user space APC’s which most drivers do not worry about. So waiting for an object with “Alertable” set FALSE will still wake up when the object is ready.

1 Like

Are you simply not reading any of of the carefully worded responses you’ve received? Or do you think we don’t know what we’re talking about?

I will state this as a rule. Always specify alertable as FALSE. Always. When you need to violate this rule, you will know it, but it is extremely unlikely that situation will arise. I’ve been writing Windows drivers for 29 years. I’ve never needed alertable set to TRUE, and you don’t either.

1 Like

Well, I haven’t been writing Windows NT drivers for that long… I only started a year before NT was released, so that would be 1992… So I haven’t been doing it as long as Tim.

But, more to the point: I haven’t set “alertable” to TRUE, ever, either.

Peter

I started driver development from OS/2 and Windows 98, but had few significant breaks on other projects.
In all cases, in my eyes weight “Peter + Tim” significantly more then my and it’s argument for me to set Alertable to FALSE… :)))

Friends,
thanks a lot for discussion and advice! :slight_smile:
Regards,
MG.

The Alertable parameter has to do with whether the wait can be interrupted for a Usermode APC.

Actually, it does. More on it below…

There is an MSDN page Waits and APCs that may help explain a bit more.

Well, as it clearly follows from the article in question, a wait cannot be interrupted if ‘False’ for “alertable” parameter is specified

Passing FALSE still allows the wait to be ended when the waitable object is signaled.

Well, the wait is most certainly going to be ended when the target waitable object gets signaled, which holds true regardless of any other parameters specified in a call. After all, this is what the very definition of waiting is all about, don’t you think…

Anton Bassov

I will state this as a rule. Always specify alertable as FALSE. Always.

…which is simply stupid, as it usually happens with all “absolute”,“ultimate” et al “guidelines” that allow no compromise and are intended to be taken in a dogmatic, religion-like fashion…

In order to prove it in this particular case, consider the scenario when you are waiting on event that normally gets signaled pretty
shortly but, at the same time, may get signaled in some fairly distant future ( or, probably, may not even occur at all) under some circumstances. In this case , a non-alertable KM wait ( the “WaitMode” parameter is, objectively, tricker than the “Alertable” one, so that you should not specify UM in a driver, particularly in context of the arbitrary thread) without a timeout may potentially turn the target app
into a sort of a zombie process that cannot get terminated until the wait condition has been satisfied. It does not really look like the best design in existence, does it…

Surely the “Alertable” parameter may have its own caveats. For example, you may potentially miss a KePulseEvent() call while running a kernel APC (because the target thread resumes the wait, rather than returning STATUS_ALERTED, after having had run the one).
However, IIRC, according to Doron, this API clearly falls into a " broken- by-design" class, and, hence,
should be avoided by all means, in the first place…

Anton Bassov

You do not understand the purpose of “Alertable” it is not related to the object(s) you are waiting on, it is related to things
like user space APC’s which most drivers do not worry about

I guess the following declarations may be of the particular use here

extern NTSTATUS Request( PUNICODE_STRING PosterName, PUNICODE_STRING CompanyName, PUNICODE_STRING ProductName ) ;

#define PUBLISH(x,y,z)
do { \

Request (x,y,z); \

} while (0)

Anton Bassov

In order to prove it in this particular case, consider the scenario when

non-alertable KM wait without a timeout may potentially turn the target app into a sort of a zombie process that cannot get terminated

Mr. Bassov… REALLY?

The problem here isn’t the use of the _Alertable _parameter at all, it’s the overall design of how the driver does the wait, isn’t it. Doing a wait that might never be satisfied isn’t a recipe for creating good code. Yes, you can counter this “wait might never be satisfied” by setting _Alertable _to TRUE. But the problem isn’t, per se, setting Alertable to FALSE… the problem is that the wait might never be terminated. Oh, that and waiting in an arbitrary process/thread context.

Also, if you’re going to quote Mr. Roberts, have the courtesy and good engineering discipline to quote him fully:

I will state this as a rule. Always specify alertable as FALSE. Always. When you need to violate this rule, you will know it, but it is extremely unlikely that situation will arise.

Bolding above is mine.

Have you ever coded an Alertable wait, Mr. Bassov? Do tell us, please. Share with us how you’ve recently done this in your vast Windows kernel-mode development experience.

Peter

Mr. Bassov… REALLY?

Indeed…

The problem here isn’t the use of the Alertable _parameter at all, it’s the overall design of how the driver does the wait, isn’t it.
Doing a wait that might never be satisfied isn’t a recipe for creating good code. Yes, you can counter this
“wait might never be satisfied” by setting _Alertable _to TRUE. But the problem isn’t, per se, setting _Alertable to FALSE…
the problem is that the wait might never be terminated.

Actually, I don’t see any “problem” here - after all, if the (possibly negative) event that you may potentially want to react to does not occur, why do you think it should necessarily pose a problem to anyone? More on it below

Have you ever coded an Alertable wait, Mr. Bassov? Do tell us, please. Share with us how you’ve recently done this in
your vast Windows kernel-mode development experience.

Well, although, luckily for me, my " (not-so) vast Windows kernel-mode development experience" had ended in the early
Windows Vista days, I can easily recall using the Alertable KM wait back in the Windows XP ones…

I had a packet filter that might potentially want to do some data processing in the userland before (possibly, but not necessarily)
re-injecting it into the network stack. Therefore, I had an NDIS IM filter and a userland app that communicated with it via a standalone DO created by NdisIMRegisterDevice().

As far as data capturing path was concerned, my filter handled 2 types of IOCTLs (both used METHOD_BUFFERED IO method). The only thing that IOCTL of the type A was doing was waiting (yes, it was an Alertable wait) on a synch (i.e. auto-reset) event that I was using as a binary semaphore. When my filter’s data-receiving path detected the data of interest it was placing a NDIS packet in question on the list, and signaling the above mentioned event if the list was empty at the moment. After KeWaitForSingleObject() had returned control IOCTL A handler indicated to the app how much (if any at all )data was available on the list at the moment by completing the request. It was doing so regardless of the return value of KeWaitForSingleObject() - the only thing it was concerned about was data availability.

After IOCTL of type A had been completed the app was submitting (possibly multiple) IOCTLs of type B that were actually copying data from NDIS packets on the list to the system buffer until no more packets were left on the list. After that the app signaled the userland event that its actual data-processing part was waiting on, and the infinite ( schematic , of course)

“while(1) { if( IOCTL_A() ==DATA_AVAILABLE) { IOCTL_B(); SetEvent(C);} }”

loop that data-capturing one was based upon continued.

With this approach I could easily handle an app termination without having had to worry even about KeWaitForSingleObject()'s
return value, let alone about when (and if) the data of interest having had arrived. Why do you think it is, in your terms, " isn’t a recipe for creating good code"? What is so terribly wrong with this approach? Could you please explain it to me.

Certainly, you can point out to me that I had to submit unnecessary IOCTLs of type A in (extremely unlikely) case if the wait was interrupted by the user APC at the time when no data was actually available. Even more, I could have done some extra optimisations (like, for example, a shared buffer) for the sake of the extra efficiency. However, this part would come at the cost of the additional code complexity which simply did not make sense, especially taking into the account that the above mentioned “simplistic” approach sufficed for the purpose.

P.S. Please note that all the above took place well before the advent of the “inverted calls”, let alone of “Big Honking IRPs”, so that, objectively, I cannot be blamed for ignoring “the best coding practices” - they simply did not exist at the time .

Also, if you’re going to quote Mr. Roberts, have the courtesy and good engineering discipline to quote him fully:

Well, probably we just happen to be abiding by the totally different “Rules of Thought”, but, in my understanding, the above mentioned statement consists of 2 mutually exclusive parts that simply cannot get reconciled with one another. In my understanding of things, you may either “Always do XYZ. Always.” (i.e. unconditionally do XYZ no matter what), or, alternatively, you may “need to violate this rule”
(i.e. conditionally avoid doing XYZ in some rare cases).

In other words, the statement in question sounds (at least to me) pretty much like

“Always have your cake with you. Always. When you need to eat it at the same time …(etc)”

Therefore, I quoted only the part that I disagreed with…

Anton Bassov