|
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" |
@@ -743,16 +751,11 @@ static int semu_init(emu_state_t *emu, int argc, char **argv) |
743 | 751 |
|
744 | 752 | /* Initialize coroutine system for SMP mode (n_hart > 1) */ |
745 | 753 | if (vm->n_hart > 1) { |
746 | | - printf("DEBUG: Starting coroutine initialization for %u harts\n", |
747 | | - vm->n_hart); |
748 | | - fflush(stdout); |
749 | 754 | if (!coro_init(vm->n_hart)) { |
750 | 755 | fprintf(stderr, "Failed to initialize coroutine subsystem\n"); |
751 | 756 | fflush(stderr); |
752 | 757 | return 1; |
753 | 758 | } |
754 | | - printf("Initialized %u hart coroutines\n", vm->n_hart); |
755 | | - fflush(stdout); |
756 | 759 |
|
757 | 760 | /* Create coroutine for each hart */ |
758 | 761 | for (uint32_t i = 0; i < vm->n_hart; i++) { |
@@ -901,6 +904,46 @@ static int semu_run(emu_state_t *emu) |
901 | 904 |
|
902 | 905 | /* SMP mode: use coroutine-based scheduling */ |
903 | 906 | if (vm->n_hart > 1) { |
| 907 | +#ifdef __APPLE__ |
| 908 | + /* macOS: create kqueue for timer and I/O events */ |
| 909 | + int kq = kqueue(); |
| 910 | + if (kq < 0) { |
| 911 | + perror("kqueue"); |
| 912 | + return -1; |
| 913 | + } |
| 914 | + |
| 915 | + /* Add 1ms periodic timer */ |
| 916 | + struct kevent kev_timer; |
| 917 | + EV_SET(&kev_timer, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 1, NULL); |
| 918 | + if (kevent(kq, &kev_timer, 1, NULL, 0, NULL) < 0) { |
| 919 | + perror("kevent timer setup"); |
| 920 | + close(kq); |
| 921 | + return -1; |
| 922 | + } |
| 923 | + |
| 924 | + /* Note: UART input is polled via u8250_check_ready(), no need to |
| 925 | + * monitor with kqueue. Timer events are sufficient to wake from WFI. |
| 926 | + */ |
| 927 | +#else |
| 928 | + /* Linux: create timerfd for periodic wakeup */ |
| 929 | + int wfi_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); |
| 930 | + if (wfi_timer_fd < 0) { |
| 931 | + perror("timerfd_create"); |
| 932 | + return -1; |
| 933 | + } |
| 934 | + |
| 935 | + /* Configure 1ms periodic timer */ |
| 936 | + struct itimerspec its = { |
| 937 | + .it_interval = {.tv_sec = 0, .tv_nsec = 1000000}, |
| 938 | + .it_value = {.tv_sec = 0, .tv_nsec = 1000000}, |
| 939 | + }; |
| 940 | + if (timerfd_settime(wfi_timer_fd, 0, &its, NULL) < 0) { |
| 941 | + perror("timerfd_settime"); |
| 942 | + close(wfi_timer_fd); |
| 943 | + return -1; |
| 944 | + } |
| 945 | +#endif |
| 946 | + |
904 | 947 | /* Update peripherals periodically */ |
905 | 948 | while (!emu->stopped) { |
906 | 949 | /* Update peripherals every 64 instructions */ |
@@ -953,13 +996,41 @@ static int semu_run(emu_state_t *emu) |
953 | 996 | } |
954 | 997 | } |
955 | 998 | if (all_waiting) { |
956 | | - /* All harts waiting for interrupt - sleep for 1ms |
| 999 | + /* All harts waiting for interrupt - use event-driven wait |
957 | 1000 | * to reduce CPU usage while maintaining responsiveness |
958 | 1001 | */ |
959 | | - usleep(1000); |
| 1002 | +#ifdef __APPLE__ |
| 1003 | + /* macOS: wait for kqueue events (timer or UART) */ |
| 1004 | + struct kevent events[2]; |
| 1005 | + int nevents = kevent(kq, NULL, 0, events, 2, NULL); |
| 1006 | + /* Events are automatically handled - timer fires every 1ms, |
| 1007 | + * UART triggers on input. No need to explicitly consume. */ |
| 1008 | + (void) nevents; |
| 1009 | +#else |
| 1010 | + /* Linux: poll on timerfd and UART */ |
| 1011 | + struct pollfd pfds[2]; |
| 1012 | + pfds[0] = (struct pollfd){wfi_timer_fd, POLLIN, 0}; |
| 1013 | + pfds[1] = (struct pollfd){emu->uart.in_fd, POLLIN, 0}; |
| 1014 | + poll(pfds, 2, -1); |
| 1015 | + |
| 1016 | + /* Consume timerfd event to prevent accumulation */ |
| 1017 | + if (pfds[0].revents & POLLIN) { |
| 1018 | + uint64_t expirations; |
| 1019 | + ssize_t ret = |
| 1020 | + read(wfi_timer_fd, &expirations, sizeof(expirations)); |
| 1021 | + (void) ret; /* Ignore read errors - timer will retry */ |
| 1022 | + } |
| 1023 | +#endif |
960 | 1024 | } |
961 | 1025 | } |
962 | 1026 |
|
| 1027 | + /* Cleanup event resources */ |
| 1028 | +#ifdef __APPLE__ |
| 1029 | + close(kq); |
| 1030 | +#else |
| 1031 | + close(wfi_timer_fd); |
| 1032 | +#endif |
| 1033 | + |
963 | 1034 | /* Check if execution stopped due to error */ |
964 | 1035 | if (emu->stopped) |
965 | 1036 | return 1; |
|
0 commit comments