Skip to content

Commit 151baa4

Browse files
committed
Replace usleep with timerfd/kqueue event-driven wait
- Linux: Use timerfd + poll for 1ms timer and UART monitoring - macOS: Use kqueue + kevent for timer and I/O events - Reduces CPU usage from ~5-10% to 1.6% on macOS - UART input now has zero latency (event-driven) - Event-based architecture easier to extend Tested on macOS with kqueue - 4-core boot succeeds, CPU at 1.6% Tested on Linux with timerfd - 4-core boot succeeds, no warnings
1 parent 88ac8c4 commit 151baa4

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

main.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@
22
#include <errno.h>
33
#include <fcntl.h>
44
#include <getopt.h>
5+
#include <poll.h>
56
#include <stdio.h>
67
#include <stdlib.h>
78
#include <string.h>
89
#include <sys/mman.h>
910
#include <sys/stat.h>
1011
#include <unistd.h>
1112

13+
#ifdef __APPLE__
14+
#include <sys/event.h>
15+
#include <sys/time.h>
16+
#else
17+
#include <sys/timerfd.h>
18+
#endif
19+
1220
#include "coro.h"
1321
#include "device.h"
1422
#include "mini-gdbstub/include/gdbstub.h"
@@ -901,6 +909,52 @@ static int semu_run(emu_state_t *emu)
901909

902910
/* SMP mode: use coroutine-based scheduling */
903911
if (vm->n_hart > 1) {
912+
#ifdef __APPLE__
913+
/* macOS: create kqueue for timer and I/O events */
914+
int kq = kqueue();
915+
if (kq < 0) {
916+
perror("kqueue");
917+
return -1;
918+
}
919+
920+
/* Add 1ms periodic timer */
921+
struct kevent kev_timer;
922+
EV_SET(&kev_timer, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 1, NULL);
923+
if (kevent(kq, &kev_timer, 1, NULL, 0, NULL) < 0) {
924+
perror("kevent timer setup");
925+
close(kq);
926+
return -1;
927+
}
928+
929+
/* Add UART input fd */
930+
struct kevent kev_uart;
931+
EV_SET(&kev_uart, emu->uart.in_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
932+
0, NULL);
933+
if (kevent(kq, &kev_uart, 1, NULL, 0, NULL) < 0) {
934+
perror("kevent uart setup");
935+
close(kq);
936+
return -1;
937+
}
938+
#else
939+
/* Linux: create timerfd for periodic wakeup */
940+
int wfi_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
941+
if (wfi_timer_fd < 0) {
942+
perror("timerfd_create");
943+
return -1;
944+
}
945+
946+
/* Configure 1ms periodic timer */
947+
struct itimerspec its = {
948+
.it_interval = {.tv_sec = 0, .tv_nsec = 1000000},
949+
.it_value = {.tv_sec = 0, .tv_nsec = 1000000},
950+
};
951+
if (timerfd_settime(wfi_timer_fd, 0, &its, NULL) < 0) {
952+
perror("timerfd_settime");
953+
close(wfi_timer_fd);
954+
return -1;
955+
}
956+
#endif
957+
904958
/* Update peripherals periodically */
905959
while (!emu->stopped) {
906960
/* Update peripherals every 64 instructions */
@@ -953,13 +1007,41 @@ static int semu_run(emu_state_t *emu)
9531007
}
9541008
}
9551009
if (all_waiting) {
956-
/* All harts waiting for interrupt - sleep for 1ms
1010+
/* All harts waiting for interrupt - use event-driven wait
9571011
* to reduce CPU usage while maintaining responsiveness
9581012
*/
959-
usleep(1000);
1013+
#ifdef __APPLE__
1014+
/* macOS: wait for kqueue events (timer or UART) */
1015+
struct kevent events[2];
1016+
int nevents = kevent(kq, NULL, 0, events, 2, NULL);
1017+
/* Events are automatically handled - timer fires every 1ms,
1018+
* UART triggers on input. No need to explicitly consume. */
1019+
(void) nevents;
1020+
#else
1021+
/* Linux: poll on timerfd and UART */
1022+
struct pollfd pfds[2];
1023+
pfds[0] = (struct pollfd){wfi_timer_fd, POLLIN, 0};
1024+
pfds[1] = (struct pollfd){emu->uart.in_fd, POLLIN, 0};
1025+
poll(pfds, 2, -1);
1026+
1027+
/* Consume timerfd event to prevent accumulation */
1028+
if (pfds[0].revents & POLLIN) {
1029+
uint64_t expirations;
1030+
ssize_t ret =
1031+
read(wfi_timer_fd, &expirations, sizeof(expirations));
1032+
(void) ret; /* Ignore read errors - timer will retry */
1033+
}
1034+
#endif
9601035
}
9611036
}
9621037

1038+
/* Cleanup event resources */
1039+
#ifdef __APPLE__
1040+
close(kq);
1041+
#else
1042+
close(wfi_timer_fd);
1043+
#endif
1044+
9631045
/* Check if execution stopped due to error */
9641046
if (emu->stopped)
9651047
return 1;

0 commit comments

Comments
 (0)