Last active
August 4, 2023 00:22
-
-
Save daurnimator/8cc2ef09ad72a5577b66f34957559e47 to your computer and use it in GitHub Desktop.
Use your own main loop on OSX. Related blog post: http://daurnimator.com/post/147024385399/using-your-own-main-loop-on-osx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <mach/port.h> /* mach_port_t */ | |
#include <mach/mach.h> /* mach_port_allocate(), mach_task_self(), mach_port_insert_member(), MACH_PORT_RIGHT_PORT_SET */ | |
#include <sys/event.h> /* kqueue(), kevent64(), struct kevent64_s, EVFILT_MACHPORT, EV_SET64, EV_ADD */ | |
#include <sys/time.h> /* struct timespec */ | |
//#include <dispatch/private.h> | |
extern mach_port_t _dispatch_get_main_queue_port_4CF(void); | |
extern void _dispatch_main_queue_callback_4CF(void); | |
#include <stdio.h> | |
#include <errno.h> | |
#include <unistd.h> /* close() */ | |
#include <dispatch/dispatch.h> | |
int main() { | |
int fd; | |
struct kevent64_s event; | |
int n; | |
if (-1 == (fd = kqueue())) | |
return (perror("kqueue"), 1); | |
/* TODO: set cloexec */ | |
mach_port_t x = _dispatch_get_main_queue_port_4CF(); | |
printf("PORT 4CF=%d\n", x); | |
/* EVFILT_MACHPORT does not allow ports; only portsets */ | |
mach_port_t y; | |
if (KERN_SUCCESS != mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &y)) | |
return 1; | |
printf("PORT SET=%d\n", y); | |
EV_SET64(&event, y, EVFILT_MACHPORT, EV_ADD|EV_CLEAR, MACH_RCV_MSG, 0, 0, 0, 0); | |
if (0 != kevent64(fd, &event, 1, NULL, 0, 0, &(struct timespec){0,0})) | |
return (perror("kevent"), 1); | |
/* XXX: a port can only belong to one portset at once. this needs additional hackery when in a CF-using application */ | |
if (KERN_SUCCESS != mach_port_insert_member(mach_task_self(), x, y)) | |
return 1; | |
/* say hello */ | |
dispatch_async( | |
dispatch_get_main_queue(), | |
^{ | |
printf("hello\n"); | |
} | |
); | |
/* in 2 seconds say hello again. */ | |
dispatch_after( | |
dispatch_time(DISPATCH_TIME_NOW, 2LL*NSEC_PER_SEC), | |
dispatch_get_main_queue(), | |
^{ | |
printf("hello from timer\n"); | |
} | |
); | |
while (1) { | |
/* You could poll/select on `fd` now. instead, I'm just going to use a blocking kevent call. */ | |
if (-1 == (n = kevent64(fd, NULL, 0, &event, 1, 0, NULL))) | |
return (perror("kevent"), 1); | |
if (n) { | |
printf("GOT EVENT. ident=%llu filter=%d\n", | |
event.ident, event.filter); | |
_dispatch_main_queue_callback_4CF(); | |
} else | |
return 2; | |
} | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
From https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/event.h
From http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_msg.html