|
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> |
|
12 | 13 | #include <sys/time.h> |
13 | 14 | #endif |
14 | 15 |
|
| 16 | +#ifdef __APPLE__ |
| 17 | +#include <sys/event.h> |
| 18 | +#include <sys/time.h> |
| 19 | +#else |
| 20 | +#include <sys/timerfd.h> |
| 21 | +#endif |
| 22 | + |
15 | 23 | #include "coro.h" |
16 | 24 | #include "device.h" |
17 | 25 | #include "mini-gdbstub/include/gdbstub.h" |
@@ -742,16 +750,11 @@ static int semu_init(emu_state_t *emu, int argc, char **argv) |
742 | 750 |
|
743 | 751 | /* Initialize coroutine system for SMP mode (n_hart > 1) */ |
744 | 752 | if (vm->n_hart > 1) { |
745 | | - printf("DEBUG: Starting coroutine initialization for %u harts\n", |
746 | | - vm->n_hart); |
747 | | - fflush(stdout); |
748 | 753 | if (!coro_init(vm->n_hart)) { |
749 | 754 | fprintf(stderr, "Failed to initialize coroutine subsystem\n"); |
750 | 755 | fflush(stderr); |
751 | 756 | return 1; |
752 | 757 | } |
753 | | - printf("Initialized %u hart coroutines\n", vm->n_hart); |
754 | | - fflush(stdout); |
755 | 758 |
|
756 | 759 | /* Create coroutine for each hart */ |
757 | 760 | for (uint32_t i = 0; i < vm->n_hart; i++) { |
@@ -950,6 +953,46 @@ static int semu_run(emu_state_t *emu) |
950 | 953 |
|
951 | 954 | /* SMP mode: use coroutine-based scheduling */ |
952 | 955 | if (vm->n_hart > 1) { |
| 956 | +#ifdef __APPLE__ |
| 957 | + /* macOS: create kqueue for timer and I/O events */ |
| 958 | + int kq = kqueue(); |
| 959 | + if (kq < 0) { |
| 960 | + perror("kqueue"); |
| 961 | + return -1; |
| 962 | + } |
| 963 | + |
| 964 | + /* Add 1ms periodic timer */ |
| 965 | + struct kevent kev_timer; |
| 966 | + EV_SET(&kev_timer, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 1, NULL); |
| 967 | + if (kevent(kq, &kev_timer, 1, NULL, 0, NULL) < 0) { |
| 968 | + perror("kevent timer setup"); |
| 969 | + close(kq); |
| 970 | + return -1; |
| 971 | + } |
| 972 | + |
| 973 | + /* Note: UART input is polled via u8250_check_ready(), no need to |
| 974 | + * monitor with kqueue. Timer events are sufficient to wake from WFI. |
| 975 | + */ |
| 976 | +#else |
| 977 | + /* Linux: create timerfd for periodic wakeup */ |
| 978 | + int wfi_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); |
| 979 | + if (wfi_timer_fd < 0) { |
| 980 | + perror("timerfd_create"); |
| 981 | + return -1; |
| 982 | + } |
| 983 | + |
| 984 | + /* Configure 1ms periodic timer */ |
| 985 | + struct itimerspec its = { |
| 986 | + .it_interval = {.tv_sec = 0, .tv_nsec = 1000000}, |
| 987 | + .it_value = {.tv_sec = 0, .tv_nsec = 1000000}, |
| 988 | + }; |
| 989 | + if (timerfd_settime(wfi_timer_fd, 0, &its, NULL) < 0) { |
| 990 | + perror("timerfd_settime"); |
| 991 | + close(wfi_timer_fd); |
| 992 | + return -1; |
| 993 | + } |
| 994 | +#endif |
| 995 | + |
953 | 996 | /* Update peripherals periodically */ |
954 | 997 | while (!emu->stopped) { |
955 | 998 | /* Update peripherals every 64 instructions */ |
@@ -1002,13 +1045,41 @@ static int semu_run(emu_state_t *emu) |
1002 | 1045 | } |
1003 | 1046 | } |
1004 | 1047 | if (all_waiting) { |
1005 | | - /* All harts waiting for interrupt - sleep for 1ms |
| 1048 | + /* All harts waiting for interrupt - use event-driven wait |
1006 | 1049 | * to reduce CPU usage while maintaining responsiveness |
1007 | 1050 | */ |
1008 | | - usleep(1000); |
| 1051 | +#ifdef __APPLE__ |
| 1052 | + /* macOS: wait for kqueue events (timer or UART) */ |
| 1053 | + struct kevent events[2]; |
| 1054 | + int nevents = kevent(kq, NULL, 0, events, 2, NULL); |
| 1055 | + /* Events are automatically handled - timer fires every 1ms, |
| 1056 | + * UART triggers on input. No need to explicitly consume. */ |
| 1057 | + (void) nevents; |
| 1058 | +#else |
| 1059 | + /* Linux: poll on timerfd and UART */ |
| 1060 | + struct pollfd pfds[2]; |
| 1061 | + pfds[0] = (struct pollfd){wfi_timer_fd, POLLIN, 0}; |
| 1062 | + pfds[1] = (struct pollfd){emu->uart.in_fd, POLLIN, 0}; |
| 1063 | + poll(pfds, 2, -1); |
| 1064 | + |
| 1065 | + /* Consume timerfd event to prevent accumulation */ |
| 1066 | + if (pfds[0].revents & POLLIN) { |
| 1067 | + uint64_t expirations; |
| 1068 | + ssize_t ret = |
| 1069 | + read(wfi_timer_fd, &expirations, sizeof(expirations)); |
| 1070 | + (void) ret; /* Ignore read errors - timer will retry */ |
| 1071 | + } |
| 1072 | +#endif |
1009 | 1073 | } |
1010 | 1074 | } |
1011 | 1075 |
|
| 1076 | + /* Cleanup event resources */ |
| 1077 | +#ifdef __APPLE__ |
| 1078 | + close(kq); |
| 1079 | +#else |
| 1080 | + close(wfi_timer_fd); |
| 1081 | +#endif |
| 1082 | + |
1012 | 1083 | /* Check if execution stopped due to error */ |
1013 | 1084 | if (emu->stopped) |
1014 | 1085 | return 1; |
|
0 commit comments