diff --git a/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/CMakeLists.txt b/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/CMakeLists.txt new file mode 100644 index 0000000000..3227344f6b --- /dev/null +++ b/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.20) +project(test-loongarch-timer-rearm C) +include(${CMAKE_CURRENT_LIST_DIR}/../common/starry_arch_filter.cmake) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +starry_arch_filtered_executable( + test-loongarch-timer-rearm + "loongarch64" + "test-loongarch-timer-rearm skipped on unsupported architecture" + src/main.c +) +target_include_directories(test-loongarch-timer-rearm PRIVATE ../common) +target_compile_options(test-loongarch-timer-rearm PRIVATE -Wall -Wextra -Werror) + +install(TARGETS test-loongarch-timer-rearm RUNTIME DESTINATION usr/bin/starry-test-suit) diff --git a/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/src/main.c b/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/src/main.c new file mode 100644 index 0000000000..3fb30ab9cb --- /dev/null +++ b/test-suit/starryos/qemu-smp1/system/bugfix-bug-loongarch-timer-rearm/src/main.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE + +#include "test_framework.h" + +#include +#include +#include +#include +#include +#include + +static int sleep_for_ns(long ns) +{ + struct timespec ts = { + .tv_sec = ns / 1000000000L, + .tv_nsec = ns % 1000000000L, + }; + + while (nanosleep(&ts, &ts) != 0) { + if (errno != EINTR) + return -1; + } + return 0; +} + +static int wait_timerfd_once(int fd) +{ + uint64_t expirations = 0; + ssize_t n = read(fd, &expirations, sizeof expirations); + return n == (ssize_t)sizeof expirations && expirations >= 1 ? 0 : -1; +} + +int main(void) +{ + TEST_START("loongarch64 one-shot timer rearm"); + + /* + * LoongArch uses one-shot timer events. The IRQ path must acknowledge the + * current event before dispatching into code that programs the next event; + * otherwise a late ACK can clear a freshly pending event and leave sleeps + * or timerfd reads blocked forever. Short repeated sleeps exercise the + * kernel's timer reprogramming path without adding much wall-clock time. + */ + for (int i = 0; i < 16; i++) { + char msg[96]; + snprintf(msg, sizeof msg, "nanosleep rearm iteration %d completes", i); + CHECK(sleep_for_ns(2 * 1000 * 1000L) == 0, msg); + } + + int fd = timerfd_create(CLOCK_MONOTONIC, 0); + CHECK(fd >= 0, "timerfd_create CLOCK_MONOTONIC succeeds"); + + struct itimerspec spec = { + .it_interval = {0, 0}, + .it_value = {0, 3 * 1000 * 1000L}, + }; + for (int i = 0; fd >= 0 && i < 8; i++) { + char set_msg[96]; + snprintf(set_msg, sizeof set_msg, "timerfd_settime one-shot iteration %d", i); + CHECK_RET(timerfd_settime(fd, 0, &spec, NULL), 0, set_msg); + + char read_msg[96]; + snprintf(read_msg, sizeof read_msg, "timerfd one-shot iteration %d expires", i); + CHECK(wait_timerfd_once(fd) == 0, read_msg); + } + + if (fd >= 0) + close(fd); + + TEST_DONE(); +}