Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools/nolibc: add timerfd functionality

This is used in various selftests and will be handy when integrating
those with nolibc.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Acked-by: Willy Tarreau <w@1wt.eu>
Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-10-3c043eeab06c@linutronix.de
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>

authored by

Thomas Weißschuh and committed by
Thomas Weißschuh
da69cfb1 fa7bf844

+137
+1
tools/include/nolibc/Makefile
··· 53 53 sys/stat.h \ 54 54 sys/syscall.h \ 55 55 sys/time.h \ 56 + sys/timerfd.h \ 56 57 sys/types.h \ 57 58 sys/wait.h \ 58 59 time.h \
+1
tools/include/nolibc/nolibc.h
··· 102 102 #include "sys/stat.h" 103 103 #include "sys/syscall.h" 104 104 #include "sys/time.h" 105 + #include "sys/timerfd.h" 105 106 #include "sys/wait.h" 106 107 #include "ctype.h" 107 108 #include "elf.h"
+87
tools/include/nolibc/sys/timerfd.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * timerfd definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_TIMERFD_H 11 + #define _NOLIBC_SYS_TIMERFD_H 12 + 13 + #include "../sys.h" 14 + #include "../time.h" 15 + 16 + #include <linux/timerfd.h> 17 + 18 + 19 + static __attribute__((unused)) 20 + int sys_timerfd_create(int clockid, int flags) 21 + { 22 + return my_syscall2(__NR_timerfd_create, clockid, flags); 23 + } 24 + 25 + static __attribute__((unused)) 26 + int timerfd_create(int clockid, int flags) 27 + { 28 + return __sysret(sys_timerfd_create(clockid, flags)); 29 + } 30 + 31 + 32 + static __attribute__((unused)) 33 + int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) 34 + { 35 + #if defined(__NR_timerfd_gettime) 36 + return my_syscall2(__NR_timerfd_gettime, fd, curr_value); 37 + #elif defined(__NR_timerfd_gettime64) 38 + struct __kernel_itimerspec kcurr_value; 39 + int ret; 40 + 41 + ret = my_syscall2(__NR_timerfd_gettime64, fd, &kcurr_value); 42 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval); 43 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value); 44 + return ret; 45 + #else 46 + return __nolibc_enosys(__func__, fd, curr_value); 47 + #endif 48 + } 49 + 50 + static __attribute__((unused)) 51 + int timerfd_gettime(int fd, struct itimerspec *curr_value) 52 + { 53 + return __sysret(sys_timerfd_gettime(fd, curr_value)); 54 + } 55 + 56 + 57 + static __attribute__((unused)) 58 + int sys_timerfd_settime(int fd, int flags, 59 + const struct itimerspec *new_value, struct itimerspec *old_value) 60 + { 61 + #if defined(__NR_timerfd_settime) 62 + return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value); 63 + #elif defined(__NR_timerfd_settime64) 64 + struct __kernel_itimerspec knew_value, kold_value; 65 + int ret; 66 + 67 + __nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value); 68 + __nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval); 69 + ret = my_syscall4(__NR_timerfd_settime64, fd, flags, &knew_value, &kold_value); 70 + if (old_value) { 71 + __nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval); 72 + __nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value); 73 + } 74 + return ret; 75 + #else 76 + return __nolibc_enosys(__func__, fd, flags, new_value, old_value); 77 + #endif 78 + } 79 + 80 + static __attribute__((unused)) 81 + int timerfd_settime(int fd, int flags, 82 + const struct itimerspec *new_value, struct itimerspec *old_value) 83 + { 84 + return __sysret(sys_timerfd_settime(fd, flags, new_value, old_value)); 85 + } 86 + 87 + #endif /* _NOLIBC_SYS_TIMERFD_H */
+48
tools/testing/selftests/nolibc/nolibc-test.c
··· 27 27 #include <sys/syscall.h> 28 28 #include <sys/sysmacros.h> 29 29 #include <sys/time.h> 30 + #include <sys/timerfd.h> 30 31 #include <sys/utsname.h> 31 32 #include <sys/wait.h> 32 33 #include <dirent.h> ··· 956 955 return ret; 957 956 } 958 957 958 + int test_timerfd(void) 959 + { 960 + struct itimerspec timerspec; 961 + int timer, ret; 962 + 963 + timer = timerfd_create(CLOCK_MONOTONIC, 0); 964 + if (timer == -1) 965 + return -1; 966 + 967 + timerspec = (struct itimerspec) { 968 + .it_value.tv_sec = 1000000, 969 + }; 970 + ret = timerfd_settime(timer, 0, &timerspec, NULL); 971 + if (ret) 972 + goto err; 973 + 974 + timerspec = (struct itimerspec) { 975 + .it_value.tv_sec = -1, 976 + .it_value.tv_nsec = -1, 977 + .it_interval.tv_sec = -1, 978 + .it_interval.tv_nsec = -1, 979 + }; 980 + ret = timerfd_gettime(timer, &timerspec); 981 + if (ret) 982 + goto err; 983 + 984 + errno = EINVAL; 985 + ret = -1; 986 + 987 + if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec) 988 + goto err; 989 + 990 + if (timerspec.it_value.tv_sec > 1000000) 991 + goto err; 992 + 993 + ret = close(timer); 994 + if (ret) 995 + return ret; 996 + 997 + return 0; 998 + 999 + err: 1000 + close(timer); 1001 + return ret; 1002 + } 1003 + 959 1004 int test_uname(void) 960 1005 { 961 1006 struct utsname buf; ··· 1284 1237 CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; 1285 1238 CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; 1286 1239 CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break; 1240 + CASE_TEST(timerfd); EXPECT_SYSZR(1, test_timerfd()); break; 1287 1241 CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break; 1288 1242 CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break; 1289 1243 CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;