Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I interrupt xcb_wait_for_event?

In a separate thread (std::thread), I have an event loop that waits on xcb_wait_for_event. When the program exits, I'd like to shut things down nicely by interrupting (I have a solution that sets a thread-local variable, and checkpoints in the loop throw an exception), and then joining my event thread into the main thread. The issue is xcb_wait_for_event; I need a way to return from it early, or I need an alternative to the function.

Can anyone suggest a solution? Thanks for your help!

like image 248
cdbfoster Avatar asked May 22 '15 01:05

cdbfoster


1 Answers

I believe I've come up with a suitable solution. I've replaced xcb_wait_for_event with the following function:

xcb_generic_event_t *WaitForEvent(xcb_connection_t *XConnection)
{
    xcb_generic_event_t *Event = nullptr;

    int XCBFileDescriptor = xcb_get_file_descriptor(XConnection);
    fd_set FileDescriptors;

    struct timespec Timeout = { 0, 250000000 }; // Check for interruptions every 0.25 seconds

    while (true)
    {
        interruptible<std::thread>::check();

        FD_ZERO(&FileDescriptors);
        FD_SET(XCBFileDescriptor, &FileDescriptors);

        if (pselect(XCBFileDescriptor + 1, &FileDescriptors, nullptr, nullptr, &Timeout, nullptr) > 0)
        {
            if ((Event = xcb_poll_for_event(XConnection)))
                break;
        }
    }

    interruptible<std::thread>::check();

    return Event;
}

Making use of xcb_get_file_descriptor, I can use pselect to wait until there are new events, or until a specified timeout has occurred. This method incurs negligible additional CPU costs, resting at a flat 0.0% (on this i7). The only "downside" is having to wait a maximum of 0.25 seconds to check for interruptions, and I'm sure that limit could be safely lowered.

like image 143
cdbfoster Avatar answered Sep 21 '22 06:09

cdbfoster