How to add a `kevent` to a `kqueue`while `kevent()` is locked?

651 Views Asked by At

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?

  1. 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.

  2. 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
1

There are 1 best solutions below

0
On

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.