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.
Related
I'm trying to figure out how to use FindFirstChangeNotification in order to do some file monitoring (in this case, for hot-reloading settings). I'm a bit a confused about what this function returns. From the docs, it creates a "change notification handle". Ok, sure. But then "A wait on a notification handle succeeds when...". In this context, what is a "wait"?
In this context, the "wait" refers to wait for the "change notification handle", which is a kind of HANDLE that you can wait until it is in signaled state by using Wait Functions.
A minimal example would be like this:
static void MyNotifyDirChange(HWND hwnd, LPCWSTR szPath)
{
HANDLE hWaitNotify = ::FindFirstChangeNotificationW(
szPath, TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY);
if (hWaitNotify == INVALID_HANDLE_VALUE)
{
::MessageBoxW(hwnd,
L"FindFirstChangeNotificationW failed.",
nullptr, MB_ICONERROR);
return;
}
::WaitForSingleObject(hWaitNotify, INFINITE);
::MessageBoxW(hwnd, L"Dir change notify.",
L"Notify", MB_ICONINFORMATION);
}
WaitForSingleObject waits until the specified object is in the signaled state or the time-out interval elapses. Since I've specified INFINITE, it will stay at there forever until the handle became signaled. And when the handle became signaled, it means something has happened; the files in the directory have changed or whatnot.
From Wait Functions on MSDN:
Wait functions allow a thread to block its own execution. The wait functions do not return until the specified criteria have been met.
Most of the wait functions (the notable exception being WaitOnAddress) accept one or more handles that determine the criteria for returning from the wait. To wait on a handle means to pass the handle to one of these wait functions. It is also common to refer to waiting on an object, which has the same meaning as waiting on a handle to that object.
Synchronization Objects lists the various kinds of objects you can wait on: events, mutexes, semaphore and waitable timers; change and memory resource notifications; jobs, processes and threads; and (subject to some caveats) I/O handles.
Lets say I have written a very simple program in an operating system which supports UI. My program looks like below:-
#include <os_specific_ui.h>
int main()
{
// Create a button using os specific API
object my_button = add_button("I am a button");
// Register for a mouse down call back on that button
mouse_down_handler = register_mouse_down_cb(my_button, func_to_be_called_on_mouse_down);
// do something...
// have a lot of functions which keep calling each other for a long period of time
}
void func_to_be_called_on_mouse_down(void)
{
print("my_button got clicked");
}
The program is clearly a single threaded program. When I run it, it keeps on doing something. In the mean time if there is a mouse down event, then callback registered for it will get hit and start executing.
I want to know how can another process (which handles mouse movements) can call a function in my process? And what happens to the state of my process when such a callback is hit. I mean my program was doing something when callback was hit. So it just stops doing that and starts executing callback or what? And what after the callback function finishes executing? Does my program go back to do whatever it was doing before callback was hit?
Pretty much all GUI programs run some form of event/main loop. That is, as the last part in main() it enters a loop, which reads events from the OS, and dispatches those events to your callback handlers and performs other tasks to realize the GUI.
i.e. the code you have in // have a lot of functions which keep calling each other just isn't possible unless you do that in a separate thread. Your own execution flow isn't stopped and taken over by some other process.
A GUI program is more or less done like this:
#include <os_specific_ui.h>
void func_to_be_called_on_mouse_down(void)
{
print("my_button got clicked");
}
int main()
{
// Create a button using os specific API
object my_button = add_button("I am a button");
// Register for a mouse down call back on that button
mouse_down_handler = register_mouse_down_cb(my_button, func_to_be_called_on_mouse_down);
for (;;) {
Event e
read_event_from_OS(&e);
handle_event(&e);
}
}
Where read_event_from_OS() fetches mouse/keyboard/redraw/etc. events from the operating system, and handle_event() figures out what to do with that event, such as redraw a window, or call one of the callback functions that your program has registered.
If the OS you're working on does things differently, you'll have to tell us more about it
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!
I'm getting an error I really don't understand when reading or writing files using a PCIe block device driver. I seem to be hitting an issue in swiotlb_unmap_sg_attrs(), which appears to be doing a NULL dereference of the sg pointer, but I don't know where this is coming from, as the only scatterlist I use myself is allocated as part of the device info structure and persists as long as the driver does.
There is a stacktrace to go with the problem. It tends to vary a bit in exact details, but it always crashes in swiotlb_unmap_sq_attrs().
I think it's likely I have a locking issue, as I am not sure how to handle the locks around the IO functions. The lock is already held when the request function is called, I release it before the IO functions themselves are called, as they need an (MSI) IRQ to complete. The IRQ handler updates a "status" value, which the IO function is waiting for. When the IO function returns, I then take the lock back up and return to request queue handling.
The crash happens in blk_fetch_request() during the following:
if (!__blk_end_request(req, res, bytes)){
printk(KERN_ERR "%s next request\n", DRIVER_NAME);
req = blk_fetch_request(q);
} else {
printk(KERN_ERR "%s same request\n", DRIVER_NAME);
}
where bytes is updated by the request handler to be the total length of IO (summed length of each scatter-gather segment).
It turned out this was due to re-entrancy of the request function. Because I was unlocking in the middle to allow IRQs to come in, the request function could be called again, would take the lock (while the original request handler was waiting on IO) and then the wrong handler would get the IRQ and everything went south with stacks of failed IO.
The way I solved this was to set a "busy" flag at the start of the request function, clear it at the end and return immediately at the start of the function if this is set:
static void mydev_submit_req(struct request_queue *q){
struct mydevice *dev = q->queuedata;
// We are already processing a request
// so reentrant calls can take a hike
// They'll be back
if (dev->has_request)
return;
// We own the IO now, new requests need to wait
// Queue lock is held when this function is called
// so no need for an atomic set
dev->has_request = 1;
// Access request queue here, while queue lock is held
spin_unlock_irq(q->queue_lock);
// Perform IO here, with IRQs enabled
// You can't access the queue or request here, make sure
// you got the info you need out before you release the lock
spin_lock_irq(q->queue_lock);
// you can end the requests as needed here, with the lock held
// allow new requests to be processed after we return
dev->has_request = 0;
// lock is held when the function returns
}
I am still not sure why I consistently got the stacktrace from swiotlb_unmap_sq_attrs(), however.
I'm calling a subroutine form the WndProc function in a windows app. WndProc was called from the message processing loop when a button was pushed. The subroutine takes a fair amount of time to run so it sends periodic messages using SendMessage(WM_USER). These messages should cause screen updates. Unfortunately, the updates are all held until the subroutine returns; at that time all the messages are processed and the screen updated. The handler for the message is in WndProc; it invalidates the window which should cause a paint message to be generated.
Do I need to run the subroutine as a separate thread?
If you want your UI to remain responsive while the subroutine runs, you either have to pump messages within the subroutine (which can itself get you into re-entrancy nasties), or move the subroutine out to a thread. The preferred way to do this is with a Worker thread.
There's an intro to worker threads on my website here. When the thread finishes its work, you can post a registered message back to your main window. Worker threads are pretty easy.
Anticipating your next question about cancelling a lengthy operation, there's a discussion of the options available to you for doing that on my site here. Warning, some of them are very silly, but I do try to be complete :-)
The best would be to use a separate thread.
But you could run the message loop in your handler function too:
HWND hwnd;
BOOL fDone;
MSG msg;
// Begin the operation and continue until it is complete
// or until the user clicks the mouse or presses a key.
fDone = FALSE;
while (!fDone)
{
fDone = DoLengthyOperation(); // application-defined function
// Remove any messages that may be in the queue. If the
// queue contains any mouse or keyboard
// messages, end the operation.
while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
{
switch(msg.message)
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_KEYDOWN:
//
// Perform any required cleanup.
//
fDone = TRUE;
}
}
}