I wonder whether ObReferenceObjectByHandle() is a blocking operation. Querying the name of a mailslot or pipe can be blocking (thanks to the timeouts if another operation is ongoing), so I need to find out (using the file object flags) whether the file object describes a pipe of mailslot.
āOliver Schneiderā wrote in message news:xxxxx@ntdev⦠> Hi, > > I wonder whether ObReferenceObjectByHandle() is a blocking operation. > Querying the name of a mailslot or pipe can be blocking (thanks to the > timeouts if another operation is ongoing), so I need to find out (using > the file object flags) whether the file object describes a pipe of > mailslot. > > Any hints are welcome, thanks! > > Oliver > > PS: DDKWizard has been updated recently - http://ddkwizard.assarbad.net/ > ā > --------------------------------------------------- > May the source be with you, stranger > > ICQ: #281645 > URL: http://assarbad.info | http://windirstat.info | > http://blog.assarbad.info > >
> I wonder whether ObReferenceObjectByHandle() is a blocking operation
I donāt see how ObRefObjByHandle can āblockā the caller (that is, cause the current thread to voluntarily relinquish control of the CPU as in waiting for a mutex)⦠assuming thatās the question.
The Object Manager references the handle table, looks the handle up, checks the mask of granted access, and (if the access is granted) increments the reference count and then derefs the handle table.
The handle table ref/deref is just for rundown protection.
I donāt see how this can cause a wait.
Of course, itās entirely possible that Iām missing somethingā¦
You didnāt miss anything. It works as you describe and is not affected by currently pended i/o or how the file handle was opened. It is basically a table lookup, type check, and then ref.
>The Object Manager references the handle table, looks the handle up,
ā¦
I donāt see how this can cause a wait.
The handle table entry must be locked, this might results in calling
KeStallExecutionProcessor or KeWaitForSingleObject if the table entry has
been locked by another thread.
So the procedure blocks the caller if the entry has been locked, i.e. calls
the scheduler explicitly.
P.S. Also, ObReferenceObjectByHandle calls the code that might be baged out,
this also results in calling the scheduler.
wrote in message news:xxxxx@ntdev⦠>> I wonder whether ObReferenceObjectByHandle() is a blocking operation > > I donāt see how ObRefObjByHandle can āblockā the caller (that is, cause > the current thread to voluntarily relinquish control of the CPU as in > waiting for a mutex)⦠assuming thatās the question. > > The Object Manager references the handle table, looks the handle up, > checks the mask of granted access, and (if the access is granted) > increments the reference count and then derefs the handle table. > > The handle table ref/deref is just for rundown protection. > > I donāt see how this can cause a wait. > > Of course, itās entirely possible that Iām missing something⦠> > Peter > OSR > >
It MIGHT, but thatās not the way the code is written as far as I can tell. At least not in XP and not in Vista. Itās actually the handle table itself thatās locked, not the handle table entry. But in any case, thatās why I tried to be clear about the type of handle table lock thatās acquired: Itās a Rundown protection lock. This does not block, but rather if thereās a rundown in progress the attempt to lock the handle table will fail, and thus the overall request will fail.
Obviously, but that wasnāt the question. However, in fact, on any practical Windows system even THIS wonāt really happen. The code for the OS will be in a Large Page, and thatās not going to get paged out.
Again, itās always possible that Iām wrong⦠but I donāt see how.
W2k and NT call KeWaitForSingleObject while locking the hash table entry,
and I assume that XP calls KeWaitForSingleObject in ExfUnblockPushLock for
the push lock that is used to lock _HANDLE_TABLE.
The following for XP SP2 installed on my laptop,
ObReferenceObjectByHandle calls ExMapHandleToPointerEx. Then
ExMapHandleToPointerEx calls ExpLookupHandleTableEntry then checks for NULL
and calls ExpBlockOnLockedHandleEntry if InterlockedCompareExchange failed.
ExpBlockOnLockedHandleEntry calls ExBlockPushLock( PushLock,
WaitBlockAllocateOnStack ) and then ExfUnblockPushLock( PushLock,
WaitBlockAllocateOnStack ) with the non NULL wait block and it seems that
the wait bit is set. In ExfUnblockPushLock I see a call to
KeWaitForSingleObject with NULL Timeout if the wait block is not NULL and
another thread is now executing( or has already executed ) the loop for all
_EX_PUSH_WAIT_BLOCKs to set _EX_PUSH_WAIT_BLOCK->WakeEvent in a signal
state.
Am I wrong?
wrote in message news:xxxxx@ntdev⦠>
> > It MIGHT, but thatās not the way the code is written as far as I can tell. > At least not in XP and not in Vista. Itās actually the handle table > itself thatās locked, not the handle table entry. But in any case, thatās > why I tried to be clear about the type of handle table lock thatās > acquired: Itās a Rundown protection lock. This does not block, but rather > if thereās a rundown in progress the attempt to lock the handle table will > fail, and thus the overall request will fail. > >
> > Obviously, but that wasnāt the question. However, in fact, on any > practical Windows system even THIS wonāt really happen. The code for the > OS will be in a Large Page, and thatās not going to get paged out. > > Again, itās always possible that Iām wrong⦠but I donāt see how. > > Peter > OSR >
No, in fact you are entirely right⦠and I stand humbly corrected.
My reading of the code is slightly different (easily explained by different versions of the OS), but youāre essential thesis is correct: There is potentially a wait for a pushlock in the code path.
Thanks for being sufficiently tennacious to āproveā this. Bravo!
> The handle table entry must be locked, this might results in calling
KeStallExecutionProcessor or KeWaitForSingleObject if the table entry has
been locked by another thread.
So the procedure blocks the caller if the entry has been locked, i.e. calls
the scheduler explicitly.
This is not important.
āBlockingā is only important in Windows - unlike Linux - in term that you
cannot block the thread for a long time in dispatch routine, especially you
cannot block the thread till the conditions will occur to complete the IRP. You
must go the STATUS_PENDING way instead.
The reason is that such blocking effectively kills the idea of overlapped IO
and IO completion ports, so, no driver can do this.
It is safe to block in dispatch routine, though, if IoIsOperationSynchronous
returns TRUE. NOTE: this routine requires a valid file object in the IRP stack
location, BSOD otherwise, so, it cannot be used in storage stacks.
In the OPās case - referencing the file object can only block for a tiny amount
of time to access the table. So, it is OK.
I suspected that smb argues that this routine can āblock for a tiny amount
of timeā, this is not relevant to our discussion, the matter was- whether
the thread can voluntary put itself in a wait state and voluntary relinquish
the CPU.
Also, give a criteria of ātiny amountā. Is the blocking in a page fault
handler called to load a handles table is āa tiny amountā? Is waiting in the
push lock release routine is āa tiny amountā?
āMaxim S. Shatskihā wrote in message news:xxxxx@ntdev⦠>> The handle table entry must be locked, this might results in calling >> KeStallExecutionProcessor or KeWaitForSingleObject if the table entry has >> been locked by another thread. >> So the procedure blocks the caller if the entry has been locked, i.e. >> calls >> the scheduler explicitly. > > This is not important. > > āBlockingā is only important in Windows - unlike Linux - in term that you > cannot block the thread for a long time in dispatch routine, especially > you > cannot block the thread till the conditions will occur to complete the > IRP. You > must go the STATUS_PENDING way instead. > > The reason is that such blocking effectively kills the idea of overlapped > IO > and IO completion ports, so, no driver can do this. > > It is safe to block in dispatch routine, though, if > IoIsOperationSynchronous > returns TRUE. NOTE: this routine requires a valid file object in the IRP > stack > location, BSOD otherwise, so, it cannot be used in storage stacks. > > In the OPās case - referencing the file object can only block for a tiny > amount > of time to access the table. So, it is OK. > > ā > Maxim Shatskih, Windows DDK MVP > StorageCraft Corporation > xxxxx@storagecraft.com > http://www.storagecraft.com > >
I think yes, it would be waste of physical memory to save all handle table
entries in nonpaged memory. A process can have up to 256*256*256 handles(
each handle table entry > 8 byte ), so saving all handle entries in the
nonpaged memory would be a really waste of memory.
āMaxim S. Shatskihā wrote in message news:xxxxx@ntdev⦠>> Also, give a criteria of ātiny amountā. Is the blocking in a page fault >> handler called to load a handles table is āa tiny amountā? > > Are you sure that the handle table is pageable? > > ā > Maxim Shatskih, Windows DDK MVP > StorageCraft Corporation > xxxxx@storagecraft.com > http://www.storagecraft.com > >
I believe the functions that manipulate the handle table are marked pagable. I donāt know for certain whether the data structures are, but they probably are, and even if they arenāt, pagable code is enough.
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Wednesday, December 27, 2006 3:07 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Is referencing a file by handle blocking?
Also, give a criteria of ātiny amountā. Is the blocking in a page fault
handler called to load a handles table is āa tiny amountā?