I am curious about the event parameter that gets passed to IOLockWakeup and IOLockSleep{Deadline}.
i understand that the event is an address that gets passed to both functions. i am assuming this address is used to essentially notify the thread.
so my question is: assuming i is an int, and we are using its address, how do these functions know when to sleep and wakeup?
is the assumption that:
when IOLockWakeup is called, that the contents of event are 0 (which it then changes to a non-zero value), and
when IOLockSleepDeadline is called, that the contents of the event were 0 at the time it was called, and it will stop sleeping because the contents are nonzero
and when we keep calling these functions (in a workloop context) are the contents of the event parameter automatically set to zero when iolocksleep* is called (and when it wakes up), since iolockwakeup presumably changs this to a nonzero value?
You'll notice that the event parameter is of type void*, not int*:
int IOLockSleep( IOLock * lock, void *event, UInt32 interType);
The event parameter is an arbitrary pointer, it’s never dereferenced, and it doesn’t matter what’s stored there, it's used purely for identification purposes: so for example don't pass NULL, because that's not a unique value.
IOLockSleep always suspends the running thread, and IOLockWakeup wakes up any thread that’s sleeping on that address. If no such thread is waiting, nothing at all happens. This is why you’ll usually want to pair the sleep/wakeup with some condition that’s protected by the lock, and send the wakeup while holding the lock - the thing to avoid is going to sleep after the wakeup was sent, in which case your sleeping thread might sleep forever.
So, you'll have some condition for deciding whether or not to sleep, and you'll update that condition before calling wakeup, while holding the lock:
IOLock* myLock;
bool shouldSleep;
…
// sleep code:
IOLockLock(myLock);
while (shouldSleep)
{
IOLockSleep(myLock, &shouldSleep, THREAD_UNINT);
}
IOLockUnlock(myLock);
…
// wakeup code:
IOLockLock(myLock);
shouldSleep = false;
IOLockWakeup(myLock, &shouldSleep, true /* or false, if we want to wake up multiple sleeping threads */);
IOLockUnlock(myLock);
Here, I've used the address of shouldSleep for the event parameter, but this could be anything, it's just convenient to use this because I know no other kext will be using that pointer, as no other kext has access to that variable.
Related
I am using ReadDirectoryChangesW to monitor when a file has changed within a directory. I am using the asynchronous version of it with a completion routine function, (as per the docs).
Everything works fine until I wish to stop monitoring the folder.
To stop the monitoring I call the Close function.
The problem is that I still get one last notification, but by then I have destroyed my LPOVERLAPPED value.
How can I stop ReadDirectoryChangesW and prevent my MyCompletionRoutine function from being called.
// get the handle
_handle = CreateFileW( ... )
void Read()
{
...
ReadDirectoryChangesW( _handle, ..., &MyCompletionRoutine );
...
}
void Close()
{
::CancelIo(_handle );
::CloseHandle(_handle );
}
void __stdcall MyCompletionRoutine (
const unsigned long dwErrorCode,
const unsigned long dwNumberOfBytesTransfered,
_OVERLAPPED* lpOverlapped )
{
// ... do stuff and start a read again
Read();
}
In the code above I might have called Read but I want to stop before MyCompletionRoutine is called.
Not sure if that helps, but the error message I get is 317
You are closing your HANDLE and freeing your OVERLAPPED too soon.
CancelIo() (and its cross-thread brother, CancelIoEx()) simply mark active I/O operations as cancelled and then exit, but you still need to actually wait for those operations to fully complete before you can then free their OVERLAPPED.
If an operation notices the cancellation before completing its work, it will stop its work and report a completion with an error code of ERROR_OPERATION_ABORTED, otherwise it will finish its work normally and report a completion with the appropriate error code.
After calling CancelIo/Ex(), you need to continue waiting on and handling completed operations, until there are no more operations left to wait on.
In other words, MyCompletionRoutine() can indeed be called after CancelIo() is called, and it needs to check for ERROR_OPERATION_ABORTED before calling Read() again. And if there is a pending read in progress when CancelIo() is called, you need to wait for that read to complete.
The MSDN page for SleepConditionVariableCS states that
Condition variables are subject to spurious wakeups (those not
associated with an explicit wake) and stolen wakeups (another thread
manages to run before the woken thread). Therefore, you should recheck
a predicate (typically in a while loop) after a sleep operation
returns.
As a result the conditional wait has to be enclosed in a while loop i.e.
while (check_predicate())
{
SleepConditionVariableCS(...)
}
If I were to use events instead of Conditional Variables can I do away with the while loop while waiting (WaitForSingleObject) for the event to be signaled?
For WaitForSingleObject(), there are no spurious wakeups, so you can eliminate the loop.
If you use WaitForMultipleObjectsEx() with bAlertable=TRUE, MsgWaitForMultipleObjects() with a wake mask, or MsgWaitForMultipleObjectsEx() with bAlertable=TRUE or a wake mask, then the wait can end on other conditions before the event is actually signaled.
What happens if complete_all() is called on a completion object (from task B) before the task A gets to do wait_for_completion() on the completion object? Is there some API to find if object is already completed at time of wait and return right away? One way could be using a mutex which is locked before sending the message and unlocked before the wait. That lock needs to be acquired before complete_all() and released after but wondering if there is a cleaner/better way. Any ideas are welcome.
More context: task A initializes the completion object, sends a request to task B along with the address of the completion object and then waits for the completion. Task B does some processing when it gets the message and then does complete_all() on the completion object.
If complete() or complete_all() is called before wait_for_completion() for a particular completion object, then wait_for_completion() will return immediately. A completion object is roughly like a semaphore:
Internally, a completion object has a done counter that is initialized to 0.
wait_for_completion() sleeps until done > 0 (or proceeds immediately if done is already greater than 0), and atomically decrements done before returning.
complete() increments done and wakes up the first process sleeping in wait_for_completion().
complete_all() sets done to UINT_MAX / 2 (effectively infinity) and wakes up everyone sleeping in wait_for_completion().
So if I'm understanding your question correctly, there is no need for additionaly locking; the completion object's internal wait.lock spinlock already synchronizes the counter access so that the case you're worrying about is handled correctly.
I have the classic IOCP callback that dequeues i/o pending requests, process them, and deallocate them, in this way:
struct MyIoRequest { OVERLAPPED o; /* ... other params ... */ };
bool is_iocp_active = true;
DWORD WINAPI WorkerProc(LPVOID lpParam)
{
ULONG_PTR dwKey;
DWORD dwTrans;
LPOVERLAPPED io_req;
while(is_iocp_active)
{
GetQueuedCompletionStatus((HANDLE)lpParam, &dwTrans, &dwKey, (LPOVERLAPPED*)&io_req, WSA_INFINITE);
// NOTE, i could use GetQueuedCompletionStatusEx() here ^ and set it in the
// alertable state TRUE, so i can wake up the thread with an ACP request from another thread!
printf("dequeued an i/o request\n");
// [ process i/o request ]
...
// [ destroy request ]
destroy_request(io_req);
}
// [ clean up some stuff ]
return 0;
}
Then, in the code I will have somewhere:
MyIoRequest * io_req = allocate_request(...params...);
ReadFile(..., (OVERLAPPED*)io_req);
and this just works perfectly.
Now my question is: What about I want to immediately close the IOCP queue without causing leaks? (e.g. application must exit)
I mean: if i set is_iocp_active to 'false', the next time GetQueuedCompletionStatus() will dequeue a new i/o request, that will be the last i/o request: it will return, causing thread to exit and when a thread exits all of its pending i/o requests are simply canceled by the system, according to MSDN.
But the structures of type 'MyIoRequest' that I have instanced when calling ReadFile() won't be destroyed at all: the system has canceled pending i/o request, but I have to manually destroy those structures I have
created, or I will leak all pending i/o requests when I stop the loop!
So, how I could do this? Am I wrong to stop the IOCP loop with just setting that variable to false? Note that is would happen even if i use APC requests to stop an alertable thread.
The solution that come to my mind is to add every 'MyIoRequest' structures to a queue/list, and then dequeue them when GetQueuedCompletionStatusEx returns, but shouldn't that make some bottleneck, since the enqueue/dequeue process of such MyIoRequest structures must be interlocked? Maybe I've misunderstood how to use the IOCP loop. Can someone bring some light on this topic?
The way I normally shut down an IOCP thread is to post my own 'shut down now please' completion. That way you can cleanly shut down and process all of the pending completions and then shut the threads down.
The way to do this is to call PostQueuedCompletionStatus() with 0 for num bytes, completion key and pOverlapped. This will mean that the completion key is a unique value (you wont have a valid file or socket with a zero handle/completion key).
Step one is to close the sources of completions, so close or abort your socket connections, close files, etc. Once all of those are closed you can't be generating any more completion packets so you then post your special '0' completion; post one for each thread you have servicing your IOCP. Once the thread gets a '0' completion key it exits.
If you are terminating the app, and there's no overriding reason to not do so, (eg. close DB connections, interprocess shared memory issues), call ExitProcess(0).
Failing that, call CancelIO() for all socket handles and process all the cancelled completions as they come in.
Try ExitProcess() first!
According to MSDN:
The WaitForSingleObject function can wait for the following objects:
Change notification
Console input
Event
Memory resource notification
Mutex
Process
Semaphore
Thread
Waitable timer
Then we can use WaitForSingleObject to make the parent-thread wait for child ones.
int main()
{
HANDLE h_child_thread = CreateThread(0,0, child, 0,0,0); //create a thread in VC
WaitForSingleObject(h_child_thread, INFINITE); //So, parent-thread will wait
return 0;
}
Question
Is there any other way to make parent-thread wait for child ones in VC or Windows?
I don't quite understand the usage of WaitForSingleObject here, does it mean that the thread's handle will be available when the thread terminates?
You can establish communication between threads in multiple ways and the terminating thread may somehow signal its waiting thread. It could be as simple as writing some special value to a shared memory location that the waiting thread can check. But this won't guarantee that the terminating thread has terminated when the waiting thread sees the special value (ordering/race conditions) or that the terminating thread terminates shortly after that (it can just hang or block on something) and it won't guarantee that the special value gets ever set before the terminating thread actually terminates (the thread can crash). WaitForSingleObject (and its companion WaitForMultipleObjects) is a sure way to know of a thread termination when it occurs. Just use it.
The handle will still be available in the sense that its value won't be gone. But it is practically useless after the thread has terminated, except you need this handle to get the thread exit code. And you still need to close the handle in the end. That is unless you're OK with handle/memory leaks.
for the first queation - yes. The method commonly used here is "Join". the usage is language dependant.
In .NET C++ you can use the Thread's Join method. this is from the msdn:
Thread* newThread = new Thread(new ThreadStart(0, Test::Work));
newThread->Start();
if(newThread->Join(waitTime + waitTime))
{
Console::WriteLine(S"New thread terminated.");
}
else
{
Console::WriteLine(S"Join timed out.");
}
Secondly, the thread is terminated when when you are signaled with "WaitForSingleObject" but the handle is still valid (for a terminated thread). So you still need to explicitly close the handle with CloseHandle.