Let suppose a kqueue
listening for files modifications:
(Note: error management is removed for convenience in the example)
#include <sys/types.h>
#include <sys/event.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <vector>
#include <array>
#include <fstream>
using namespace std;
auto main() ->int
{
constexpr static int keventsMode = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE;
// Create the queue
auto kernelQueue = kqueue();
// Open the file descriptor to be monitored
auto file = open("./test.txt", O_EVTONLY);
// Create the structures of kevents to monitor
std::vector<struct kevent> keventsToMonitor;
keventsToMonitor.emplace_back();
EV_SET( &(*keventsToMonitor.rbegin()), file, EVFILT_VNODE, EV_ADD | EV_CLEAR, keventsMode, 0, nullptr);
// Create a structure to get events
std::array<struct kevent, 10> keventsData;
// Event loop
while( true )
{
// Blocking function!!! HOW TO UNBLOCK?
auto eventCount = kevent(kernelQueue, keventsToMonitor.data(),
keventsToMonitor.size(), keventsData.data(), keventsData.size(), nullptr/*&timeout*/);
// .. manage events here
if (eventCount) cout << "Some events" << endl;
else cout << "timeout" << endl;
}
}
Let suppose we move the while
loop in a thread, and we want to add an additional file to the kqueue
.
The problem is that kevent()
function will block until a new event arrive, so adding a file cannot take effect until kevent()
unblock and a new call is performed with the new entry in keventsToMonitor
.
How to avoid this?
Use a timeout: if we use a long timeout (e.g. 10s), adding a file will take too long to take place; if we use a short timeout (e.g. 50ms), CPU usage will be inefficient.
Signal
kevent
somehow, but how?
A "listening" file could be created, and modified to unblock the kevent()
function, but I expect a simpler solution to exists, unfortunately, I found not information about this.
How to unblock kevent()
so that a new file can be added to the list to monitor? or is there any other solution to efficiently add new files to monitor?
The ideal solution would be something like:
ksignal(kernelQueue); //ksignal does not exists
Create a pipe, and add the reading fd in kqueue with EV_READ. Writing to the pipe in another thread will cause kevent() to return.