diff options
author | 2022-08-28 21:28:05 -0700 | |
---|---|---|
committer | 2022-08-28 21:28:05 -0700 | |
commit | c1734c6ec5ef709ee4126b3474c7bee0a377a1fa (patch) | |
tree | 097710a13a1d85228efadf6d57823bb3a4f1c011 /src/io/io_darwin.cpp | |
parent | b2141a204fbc351a40467037138168aea23a6930 (diff) | |
download | bun-c1734c6ec5ef709ee4126b3474c7bee0a377a1fa.tar.gz bun-c1734c6ec5ef709ee4126b3474c7bee0a377a1fa.tar.zst bun-c1734c6ec5ef709ee4126b3474c7bee0a377a1fa.zip |
More reliable macOS event loop (#1166)
* More reliable macOS event loop
* Reduce CPU usage of idling
* Add another implementation
* Add benchmark
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/io/io_darwin.cpp')
-rw-r--r-- | src/io/io_darwin.cpp | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/io/io_darwin.cpp b/src/io/io_darwin.cpp new file mode 100644 index 000000000..74a763812 --- /dev/null +++ b/src/io/io_darwin.cpp @@ -0,0 +1,65 @@ + +#ifdef __APPLE__ + +#include <sys/event.h> + +#include <mach/mach.h> +// errno +#include <errno.h> + +extern "C" mach_port_t io_darwin_create_machport(uint64_t wakeup, int32_t fd, + void *wakeup_buffer_, + size_t nbytes) { + + mach_port_t port; + // Create a Mach port that will be used to wake up the pump + kern_return_t kr = + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); + if (kr != KERN_SUCCESS) { + return 0; + } + + // Configure the event to directly receive the Mach message as part of the + // kevent64() call. + kevent64_s event{}; + event.ident = port; + event.filter = EVFILT_MACHPORT; + event.flags = EV_ADD | EV_ENABLE; + event.fflags = MACH_RCV_MSG | MACH_RCV_OVERWRITE; + event.ext[0] = reinterpret_cast<uint64_t>(wakeup_buffer_); + event.ext[1] = nbytes; + + while (true) { + int rv = kevent64(fd, &event, 1, NULL, 0, 0, NULL); + if (rv == -1) { + if (errno == EINTR) { + continue; + } + + return 0; + } + + return port; + } +} + +extern "C" bool io_darwin_schedule_wakeup(mach_port_t waker) { + mach_msg_empty_send_t message{}; + message.header.msgh_size = sizeof(message); + message.header.msgh_bits = + MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND_ONCE); + message.header.msgh_remote_port = waker; + kern_return_t kr = mach_msg_send(&message.header); + if (kr != KERN_SUCCESS) { + // If io_darwin_schedule_wakeup() is being called by other threads faster + // than the pump can dispatch work, the kernel message queue for the wakeup + // port can fill The kernel does return a SEND_ONCE right in the case of + // failure, which must be destroyed to avoid leaking. + mach_msg_destroy(&message.header); + return false; + } + + return true; +} + +#endif
\ No newline at end of file |