|
2 | 2 | #include <errno.h> |
3 | 3 | #include <fcntl.h> |
4 | 4 | #include <getopt.h> |
| 5 | +#include <poll.h> |
5 | 6 | #include <stdio.h> |
6 | 7 | #include <stdlib.h> |
7 | 8 | #include <string.h> |
8 | 9 | #include <sys/mman.h> |
9 | 10 | #include <sys/stat.h> |
10 | 11 | #include <unistd.h> |
11 | 12 |
|
| 13 | +#ifdef __APPLE__ |
| 14 | +#include <sys/event.h> |
| 15 | +#include <sys/time.h> |
| 16 | +#else |
| 17 | +#include <sys/timerfd.h> |
| 18 | +#endif |
| 19 | + |
12 | 20 | #include "coro.h" |
13 | 21 | #include "device.h" |
14 | 22 | #include "mini-gdbstub/include/gdbstub.h" |
@@ -901,6 +909,52 @@ static int semu_run(emu_state_t *emu) |
901 | 909 |
|
902 | 910 | /* SMP mode: use coroutine-based scheduling */ |
903 | 911 | 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 | + |
904 | 958 | /* Update peripherals periodically */ |
905 | 959 | while (!emu->stopped) { |
906 | 960 | /* Update peripherals every 64 instructions */ |
@@ -953,13 +1007,41 @@ static int semu_run(emu_state_t *emu) |
953 | 1007 | } |
954 | 1008 | } |
955 | 1009 | if (all_waiting) { |
956 | | - /* All harts waiting for interrupt - sleep for 1ms |
| 1010 | + /* All harts waiting for interrupt - use event-driven wait |
957 | 1011 | * to reduce CPU usage while maintaining responsiveness |
958 | 1012 | */ |
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 |
960 | 1035 | } |
961 | 1036 | } |
962 | 1037 |
|
| 1038 | + /* Cleanup event resources */ |
| 1039 | +#ifdef __APPLE__ |
| 1040 | + close(kq); |
| 1041 | +#else |
| 1042 | + close(wfi_timer_fd); |
| 1043 | +#endif |
| 1044 | + |
963 | 1045 | /* Check if execution stopped due to error */ |
964 | 1046 | if (emu->stopped) |
965 | 1047 | return 1; |
|
0 commit comments