33#include <errno.h>
44#include <grp.h>
55#include <sched.h>
6- #include <setjmp .h>
6+ #include <signal .h>
77#include <stdio.h>
88#include <stdlib.h>
9+ #include <sys/event.h>
910#include <sys/stat.h>
11+ #include <sys/time.h>
12+ #include <sys/types.h>
1013#include <sys/uio.h>
1114#include <sys/un.h>
1215#include <unistd.h>
1922#error "Requires macOS 10.15 or later"
2023#endif
2124
25+ #define ARRAY_SIZE (a ) (sizeof(a) / sizeof(a[0]))
26+
2227bool debug = false;
2328
2429static const char * vmnet_strerror (vmnet_return_t v ) {
@@ -280,12 +285,6 @@ static interface_ref start(struct state *state, struct cli_options *cliopt) {
280285 return iface ;
281286}
282287
283- static sigjmp_buf jmpbuf ;
284- static void signalhandler (int signal ) {
285- INFOF ("Received signal: %s" , strsignal (signal ));
286- siglongjmp (jmpbuf , 1 );
287- }
288-
289288static void stop (struct state * state , interface_ref iface ) {
290289 if (iface == NULL ) {
291290 return ;
@@ -391,11 +390,55 @@ static int create_pidfile(const char *pidfile)
391390 return fd ;
392391}
393392
393+ static int setup_signals (int kq )
394+ {
395+ struct kevent changes [] = {
396+ { .ident = SIGHUP , .filter = EVFILT_SIGNAL , .flags = EV_ADD },
397+ { .ident = SIGINT , .filter = EVFILT_SIGNAL , .flags = EV_ADD },
398+ { .ident = SIGTERM , .filter = EVFILT_SIGNAL , .flags = EV_ADD },
399+ };
400+
401+ // Block signals we want to receive via kqueue.
402+ sigset_t mask ;
403+ sigemptyset (& mask );
404+ for (size_t i = 0 ; i < ARRAY_SIZE (changes ); i ++ ) {
405+ sigaddset (& mask , changes [i ].ident );
406+ }
407+ if (sigprocmask (SIG_BLOCK , & mask , NULL ) != 0 ) {
408+ ERRORN ("sigprocmask" );
409+ return -1 ;
410+ }
411+
412+ // We will receive EPIPE on the socket.
413+ signal (SIGPIPE , SIG_IGN );
414+
415+ if (kevent (kq , changes , ARRAY_SIZE (changes ), NULL , 0 , NULL ) != 0 ) {
416+ ERRORN ("kevent" );
417+ return -1 ;
418+ }
419+ return 0 ;
420+ }
421+
422+ static int add_listen_fd (int kq , int fd )
423+ {
424+ struct kevent changes [] = {
425+ { .ident = fd , .filter = EVFILT_READ , .flags = EV_ADD },
426+ };
427+ if (kevent (kq , changes , ARRAY_SIZE (changes ), NULL , 0 , NULL ) != 0 ) {
428+ ERRORN ("kevent" );
429+ return -1 ;
430+ }
431+ return 0 ;
432+ }
433+
394434static void on_accept (struct state * state , int accept_fd , interface_ref iface );
395435
396436int main (int argc , char * argv []) {
397437 debug = getenv ("DEBUG" ) != NULL ;
398- int rc = 1 , listen_fd = -1 ;
438+ int rc = 1 ;
439+ int listen_fd = -1 ;
440+ int pidfile_fd = -1 ;
441+ int kq = -1 ;
399442 __block interface_ref iface = NULL ;
400443
401444 struct state state = {0 };
@@ -409,7 +452,18 @@ int main(int argc, char *argv[]) {
409452 WARN ("Seems running with SETUID. This is insecure and highly discouraged: See README.md" );
410453 }
411454
412- int pidfile_fd = -1 ;
455+ kq = kqueue ();
456+ if (kq == -1 ) {
457+ ERRORN ("kqueue" );
458+ goto done ;
459+ }
460+
461+ // Setup signals beofre creating the pidfile so the pidfile to ensure removal
462+ // when terminating by signal.
463+ if (setup_signals (kq )) {
464+ goto done ;
465+ }
466+
413467 if (cliopt -> pidfile != NULL ) {
414468 pidfile_fd = create_pidfile (cliopt -> pidfile );
415469 if (pidfile_fd == -1 ) {
@@ -425,16 +479,6 @@ int main(int argc, char *argv[]) {
425479 goto done ;
426480 }
427481
428- if (sigsetjmp (jmpbuf , 1 ) != 0 ) {
429- goto done ;
430- }
431- signal (SIGHUP , signalhandler );
432- signal (SIGINT , signalhandler );
433- signal (SIGTERM , signalhandler );
434-
435- // We will receive EPIPE on the socket.
436- signal (SIGPIPE , SIG_IGN );
437-
438482 state .sem = dispatch_semaphore_create (1 );
439483
440484 // Queue for vm connections, allowing processing vms requests in parallel.
@@ -451,16 +495,34 @@ int main(int argc, char *argv[]) {
451495 goto done ;
452496 }
453497
498+ if (add_listen_fd (kq , listen_fd )) {
499+ goto done ;
500+ }
501+
454502 while (1 ) {
455- int accept_fd = accept (listen_fd , NULL , NULL );
456- if (accept_fd < 0 ) {
457- ERRORN ("accept" );
503+ struct kevent events [1 ];
504+ int n = kevent (kq , NULL , 0 , events , 1 , NULL );
505+ if (n < 0 ) {
506+ ERRORN ("kevent" );
458507 goto done ;
459508 }
460- struct state * state_p = & state ;
461- dispatch_async (state .vms_queue , ^{
462- on_accept (state_p , accept_fd , iface );
463- });
509+
510+ if (events [0 ].filter == EVFILT_SIGNAL ) {
511+ INFOF ("Received signal %s" , strsignal (events [0 ].ident ));
512+ break ;
513+ }
514+
515+ if (events [0 ].filter == EVFILT_READ ) {
516+ int accept_fd = accept (listen_fd , NULL , NULL );
517+ if (accept_fd < 0 ) {
518+ ERRORN ("accept" );
519+ goto done ;
520+ }
521+ struct state * state_p = & state ;
522+ dispatch_async (state .vms_queue , ^{
523+ on_accept (state_p , accept_fd , iface );
524+ });
525+ }
464526 }
465527 rc = 0 ;
466528done :
@@ -479,6 +541,9 @@ int main(int argc, char *argv[]) {
479541 dispatch_release (state .vms_queue );
480542 if (state .host_queue != NULL )
481543 dispatch_release (state .host_queue );
544+ if (kq != -1 ) {
545+ close (kq );
546+ }
482547 cli_options_destroy (cliopt );
483548 return rc ;
484549}
0 commit comments