Closed domfarolino closed 3 years ago
This is getting close. There is some cleaning up I'd like to do, but @musgravejw can you give it a quick once-over sanity check to see if this all makes sense to you?
I think this is all set to land! I've added some TODOs to follow up on, but I'd like to not block this any longer on those. Feel free to take a look but I'll probably aim to land this soon.
Again this is macOS only, so the next priority will be getting cross-platform build flag support so we can make more platform-specific TaskLoop bits.
Outstanding concerns:
Closes #24. First stab at TaskLoopForIO (macOS only for now), mostly based on the Chromium's base::MessagePumpKqueue, which is Chrome's IO thread implementation in macOS (I think; there also exists a message pump implementation that uses libevent though...). It uses the kqueue to listen to operating system events.
TaskLoopForIO supports user-posted tasks just like TaskLoopForWorker, however it implements this a little differently, since we don't relying on base::ConditionVariable to wake the sleeping TaskLoopForIO up. Because we're using kqueue for now on macOS, when other threads post a task to TaskLoopForIO, we need to wake the TaskLoopForIO up with a kernel event. We do this by having TaskLoopForIO always listen to a given mach port named
wakeup_
, and after PostTask() pushes a task to thequeue_
, it writes an empty message towakeup_
to wake up the sleeping thread on which TaskLoop is "bound". When the sleeping thread wakes up, TaskLoopForIO::Run will be resumed (just after thekevent64()
system call), and we take a look at the event that we've been woken up for, and take one of two paths:wakeup_
, then we know that there is at least user-posted task inqueue_
, so we remove it, run it, and continue.In addition to supporting user-posted tasks like TaskLoopForWorker (described above), TaskLoopForIO exposes the ability to listen to a file descriptor via the base::TaskLoopForIO::SocketReader interface. A SocketReader registers itself with the TaskLoopForIO and associates itself with a given file descriptor it cares about. The SocketReader is inserted into the loop's
async_socket_readers_
map. When a file descriptor that the TaskLoop knows about is written to, the TaskLoopForIO wakes up, finds the SocketReader associated with the file descriptor (viaasync_socket_readers_
), and notifies the reader so it can read from the descriptor.The kernel queue (kqueue) is interesting because if, while a TaskLoopForIO is busy executing a big task for example, multiple events with different filters (types, more-or-less) get pushed to the kqueue, once the TaskLoopForIO queries
kevent64
again next, we can read them all of the events in the kqueue that have been posted since our last query. The return value ofkevent64
tells us how many events are ready to be read/processed, and TaskLoopForIO supports this with an innerfor
loop that iterates over the return value ofkevent64
, and processes all given events. This is also why we resize theevents_
vector upon every event loop iteration.~Before this PR is finished, TaskLoopIO needs to support watching for file descriptor writes. That's the only way we'll be able to support mage.~