tools/nolibc: add timer functions

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-9-3c043eeab06c@linutronix.de
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
This commit is contained in:
Thomas Weißschuh
2025-05-21 15:32:09 +02:00
committed by Thomas Weißschuh
parent 50647213e1
commit fa7bf84486
3 changed files with 138 additions and 0 deletions
+86
View File
@@ -15,6 +15,7 @@
#include "types.h"
#include "sys.h"
#include <linux/signal.h>
#include <linux/time.h>
static __inline__
@@ -120,4 +121,89 @@ time_t time(time_t *tptr)
return tv.tv_sec;
}
/*
* int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
* int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
* int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
*/
static __attribute__((unused))
int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
return my_syscall3(__NR_timer_create, clockid, evp, timerid);
}
static __attribute__((unused))
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
return __sysret(sys_timer_create(clockid, evp, timerid));
}
static __attribute__((unused))
int sys_timer_delete(timer_t timerid)
{
return my_syscall1(__NR_timer_delete, timerid);
}
static __attribute__((unused))
int timer_delete(timer_t timerid)
{
return __sysret(sys_timer_delete(timerid));
}
static __attribute__((unused))
int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
{
#if defined(__NR_timer_gettime)
return my_syscall2(__NR_timer_gettime, timerid, curr_value);
#elif defined(__NR_timer_gettime64)
struct __kernel_itimerspec kcurr_value;
int ret;
ret = my_syscall2(__NR_timer_gettime64, timerid, &kcurr_value);
__nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval);
__nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value);
return ret;
#else
return __nolibc_enosys(__func__, timerid, curr_value);
#endif
}
static __attribute__((unused))
int timer_gettime(timer_t timerid, struct itimerspec *curr_value)
{
return __sysret(sys_timer_gettime(timerid, curr_value));
}
static __attribute__((unused))
int sys_timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
#if defined(__NR_timer_settime)
return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#elif defined(__NR_timer_settime64)
struct __kernel_itimerspec knew_value, kold_value;
int ret;
__nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value);
__nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval);
ret = my_syscall4(__NR_timer_settime64, timerid, flags, &knew_value, &kold_value);
if (old_value) {
__nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval);
__nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value);
}
return ret;
#else
return __nolibc_enosys(__func__, timerid, flags, new_value, old_value);
#endif
}
static __attribute__((unused))
int timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
return __sysret(sys_timer_settime(timerid, flags, new_value, old_value));
}
#endif /* _NOLIBC_TIME_H */
+1
View File
@@ -188,6 +188,7 @@ struct stat {
};
typedef __kernel_clockid_t clockid_t;
typedef int timer_t;
/* WARNING, it only deals with the 4096 first majors and 256 first minors */
#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
@@ -905,6 +905,56 @@ int test_stat_timestamps(void)
return 0;
}
int test_timer(void)
{
struct itimerspec timerspec;
struct sigevent evp;
timer_t timer;
int ret;
evp.sigev_notify = SIGEV_NONE;
ret = timer_create(CLOCK_MONOTONIC, &evp, &timer);
if (ret)
return ret;
timerspec = (struct itimerspec) {
.it_value.tv_sec = 1000000,
};
ret = timer_settime(timer, 0, &timerspec, NULL);
if (ret)
goto err;
timerspec = (struct itimerspec) {
.it_value.tv_sec = -1,
.it_value.tv_nsec = -1,
.it_interval.tv_sec = -1,
.it_interval.tv_nsec = -1,
};
ret = timer_gettime(timer, &timerspec);
if (ret)
goto err;
errno = EINVAL;
ret = -1;
if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec)
goto err;
if (timerspec.it_value.tv_sec > 1000000)
goto err;
ret = timer_delete(timer);
if (ret)
return ret;
return 0;
err:
timer_delete(timer);
return ret;
}
int test_uname(void)
{
struct utsname buf;
@@ -1186,6 +1236,7 @@ int run_syscall(int min, int max)
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break;
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break;
CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break;
CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break;
CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;