I'm using the code example by David Hamrick to monitor a file using GCD.
int fildes = open("/path/to/config.plist", O_RDONLY);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fildes,
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
queue);
dispatch_source_set_event_handler(source, ^
{
//Reload the config file
});
dispatch_source_set_cancel_handler(source, ^
{
//Handle the cancel
});
dispatch_resume(source);
I want to use to monitor a change of a plist. I get a notification after the first change but not for the following changes. Why?
You can indeed just re-open the file and re-register a source (deleting the previous one) when DISPATCH_VNODE_DELETE is received. Or you can use a call which was devised for just this kind of scenario, namely dispatch_io_create_with_path() - that will not only watch by path, it will open the file for you and let you read the contents asynchronously.
Since you asked (not sure which technique you asked for, but here's the simplest) here's a stand-alone code sample:
#include <dispatch/dispatch.h>
#include <stdio.h>
int main(int ac, char *av[])
{
int fdes = open("/tmp/pleasewatchthis", O_RDONLY);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
void (^eventHandler)(void), (^cancelHandler)(void);
unsigned long mask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE;
__block dispatch_source_t source;
eventHandler = ^{
unsigned long l = dispatch_source_get_data(source);
if (l & DISPATCH_VNODE_DELETE) {
printf("watched file deleted! cancelling source\n");
dispatch_source_cancel(source);
}
else {
// handle the file has data case
printf("watched file has data\n");
}
};
cancelHandler = ^{
int fdes = dispatch_source_get_handle(source);
close(fdes);
// Wait for new file to exist.
while ((fdes = open("/tmp/pleasewatchthis", O_RDONLY)) == -1)
sleep(1);
printf("re-opened target file in cancel handler\n");
source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fdes, mask, queue);
dispatch_source_set_event_handler(source, eventHandler);
dispatch_source_set_cancel_handler(source, cancelHandler);
dispatch_resume(source);
};
source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fdes, mask, queue);
dispatch_source_set_event_handler(source, eventHandler);
dispatch_source_set_cancel_handler(source, cancelHandler);
dispatch_resume(source);
dispatch_main();
}
After a little bit a research I found out :
=> I was getting the flag DISPATCH_VNODE_DELETE
I was monitoring ~/Library/Preferences/com.apple.dock.plist
As I found out, changing the dock orientation, deletes the original file and replaces it with a new one.
Therefore, the monitoring stopped.
The same author proposes a solution where in case of deletion, the GCD block call itself to continue the monitoring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With