# HG changeset patch # User Paul Boddie # Date 1625782529 -7200 # Node ID 7374a07a6bf8db21c79b3226c41d8c9b2476aca5 # Parent 42959903b97f9ba22657b11ee6cd2658389bd692 Introduced a specialised method for waiting for a single file's notifications. This avoids discarding notifications for other files monitored by the notifier. diff -r 42959903b97f -r 7374a07a6bf8 libfsclient/include/fsclient/notifier.h --- a/libfsclient/include/fsclient/notifier.h Wed Jul 07 00:28:19 2021 +0200 +++ b/libfsclient/include/fsclient/notifier.h Fri Jul 09 00:15:29 2021 +0200 @@ -67,15 +67,19 @@ /* Local operations. */ + virtual long start(); + virtual long subscribe(file_t *file, notify_flags_t flags); virtual long unsubscribe(file_t *file); - virtual void mainloop(); + virtual long wait(file_t **file); + + virtual long wait_file(file_t *file); - virtual long start(); + /* Event handling support. */ - virtual long wait(file_t **file); + virtual void mainloop(); }; diff -r 42959903b97f -r 7374a07a6bf8 libfsclient/lib/src/file.cc --- a/libfsclient/lib/src/file.cc Wed Jul 07 00:28:19 2021 +0200 +++ b/libfsclient/lib/src/file.cc Fri Jul 09 00:15:29 2021 +0200 @@ -394,18 +394,9 @@ long file_notify_wait_file(file_t *file) { - file_t *affected; - - do - { - long err = file_notify_wait_files(&affected); + FileNotifier *notifier = get_notifier(); - if (err) - return err; - } - while (affected != file); - - return L4_EOK; + return notifier->wait_file(file); } /* Wait for notification events on files. */ diff -r 42959903b97f -r 7374a07a6bf8 libfsclient/lib/src/notifier.cc --- a/libfsclient/lib/src/notifier.cc Wed Jul 07 00:28:19 2021 +0200 +++ b/libfsclient/lib/src/notifier.cc Fri Jul 09 00:15:29 2021 +0200 @@ -100,10 +100,18 @@ { std::unique_lock guard(_lock); - /* Record the flags for the file object. */ + /* Record the flags for the file object. Where no flags are already recorded, + the new flags will be recorded and the file object queued. Otherwise, the + new flags will be combined with the recorded flags. */ + + notify_flags_t recorded = _affected_flags[file]; - _affected_flags[file] = _affected_flags[file] | flags; - _affected.push_back(file); + _affected_flags[file] = recorded | flags; + + /* Add a file queue entry for any files without recorded notifications. */ + + if (!recorded) + _affected.push_back(file); /* Notify any waiting caller. */ @@ -195,17 +203,53 @@ while (1) { - if (!_affected.empty()) + /* Obtain queued files until one is found that still has events recorded + for it. (Waiting for events specific to one file will remove recorded + events but not any file queue entries.) */ + + while (!_affected.empty()) { *file = _affected.front(); _affected.pop_front(); - (*file)->notifications = _affected_flags[*file]; - _affected_flags.erase(*file); + notify_flags_t recorded = _affected_flags[*file]; + + if (recorded) + { + (*file)->notifications = recorded; + _affected_flags.erase(*file); + return L4_EOK; + } + } + + /* No queued events. */ + + _notified.wait(guard); + } + + return L4_EOK; +} + +/* Wait for notifications from a single file. */ + +long FileNotifier::wait_file(file_t *file) +{ + std::unique_lock guard(_lock); + + while (1) + { + notify_flags_t recorded = _affected_flags[file]; + + if (recorded) + { + file->notifications = recorded; + _affected_flags.erase(file); return L4_EOK; } - else - _notified.wait(guard); + + /* No recorded events for the file. */ + + _notified.wait(guard); } return L4_EOK;