Skip to content

Commit 1f9a368

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 1f9a368

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

main.c

Lines changed: 83 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,51 @@ 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+
if (timerfd_settime(wfi_timer_fd, 0, &its, NULL) < 0) {
951+
perror("timerfd_settime");
952+
close(wfi_timer_fd);
953+
return -1;
954+
}
955+
#endif
956+
904957
/* Update peripherals periodically */
905958
while (!emu->stopped) {
906959
/* Update peripherals every 64 instructions */
@@ -953,13 +1006,41 @@ static int semu_run(emu_state_t *emu)
9531006
}
9541007
}
9551008
if (all_waiting) {
956-
/* All harts waiting for interrupt - sleep for 1ms
1009+
/* All harts waiting for interrupt - use event-driven wait
9571010
* to reduce CPU usage while maintaining responsiveness
9581011
*/
959-
usleep(1000);
1012+
#ifdef __APPLE__
1013+
/* macOS: wait for kqueue events (timer or UART) */
1014+
struct kevent events[2];
1015+
int nevents = kevent(kq, NULL, 0, events, 2, NULL);
1016+
/* Events are automatically handled - timer fires every 1ms,
1017+
* UART triggers on input. No need to explicitly consume. */
1018+
(void) nevents;
1019+
#else
1020+
/* Linux: poll on timerfd and UART */
1021+
struct pollfd pfds[2];
1022+
pfds[0] = (struct pollfd){wfi_timer_fd, POLLIN, 0};
1023+
pfds[1] = (struct pollfd){emu->uart.in_fd, POLLIN, 0};
1024+
poll(pfds, 2, -1);
1025+
1026+
/* Consume timerfd event to prevent accumulation */
1027+
if (pfds[0].revents & POLLIN) {
1028+
uint64_t expirations;
1029+
ssize_t ret = read(wfi_timer_fd, &expirations,
1030+
sizeof(expirations));
1031+
(void) ret; /* Ignore read errors - timer will retry */
1032+
}
1033+
#endif
9601034
}
9611035
}
9621036

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

0 commit comments

Comments
 (0)