Skip to content

Commit f458e96

Browse files
authored
Merge pull request #112 from nirs/kqueue
Handle signals with kqueue
2 parents 0f61b07 + f0c6d54 commit f458e96

File tree

1 file changed

+91
-26
lines changed

1 file changed

+91
-26
lines changed

main.c

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
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>
@@ -19,6 +22,8 @@
1922
#error "Requires macOS 10.15 or later"
2023
#endif
2124

25+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
26+
2227
bool debug = false;
2328

2429
static 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-
289288
static 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+
394434
static void on_accept(struct state *state, int accept_fd, interface_ref iface);
395435

396436
int 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;
466528
done:
@@ -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

Comments
 (0)