diff --git a/repos/gems/run/depot_autopilot.run b/repos/gems/run/depot_autopilot.run index cd043e3e61..f97c01e993 100644 --- a/repos/gems/run/depot_autopilot.run +++ b/repos/gems/run/depot_autopilot.run @@ -681,6 +681,7 @@ set default_test_pkgs { test-libc_fifo_pipe test-libc_fork test-libc_getenv + test-libc_alarm test-libc_pipe test-libc_vfs test-libc_vfs_audit diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk index e491954a97..687b903433 100644 --- a/repos/libports/lib/mk/libc.mk +++ b/repos/libports/lib/mk/libc.mk @@ -12,7 +12,7 @@ LIBS += base vfs # Back end # SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \ - issetugid.cc errno.cc gai_strerror.cc time.cc \ + issetugid.cc errno.cc gai_strerror.cc time.cc alarm.cc \ malloc.cc progname.cc fd_alloc.cc file_operations.cc \ plugin.cc plugin_registry.cc select.cc exit.cc environ.cc sleep.cc \ pread_pwrite.cc readv_writev.cc poll.cc \ diff --git a/repos/libports/recipes/pkg/test-libc_alarm/README b/repos/libports/recipes/pkg/test-libc_alarm/README new file mode 100644 index 0000000000..77680bcf90 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/README @@ -0,0 +1 @@ +Libc alarm() test. diff --git a/repos/libports/recipes/pkg/test-libc_alarm/archives b/repos/libports/recipes/pkg/test-libc_alarm/archives new file mode 100644 index 0000000000..170cda551e --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/archives @@ -0,0 +1,5 @@ +_/src/init +_/src/test-libc_alarm +_/src/libc +_/src/posix +_/src/vfs diff --git a/repos/libports/recipes/pkg/test-libc_alarm/hash b/repos/libports/recipes/pkg/test-libc_alarm/hash new file mode 100644 index 0000000000..a6e2dbe4ac --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-08-30 ca6e62da4a88ade9338dea365858d83409150c78 diff --git a/repos/libports/recipes/pkg/test-libc_alarm/runtime b/repos/libports/recipes/pkg/test-libc_alarm/runtime new file mode 100644 index 0000000000..24bf4b4bce --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/runtime @@ -0,0 +1,22 @@ + + + + + + triggered_alarms=3 + + + + + + + + + + + + + + + + diff --git a/repos/libports/recipes/src/test-libc_alarm/content.mk b/repos/libports/recipes/src/test-libc_alarm/content.mk new file mode 100644 index 0000000000..7a6c4ee906 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/content.mk @@ -0,0 +1,2 @@ +SRC_DIR := src/test/libc_alarm +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/libports/recipes/src/test-libc_alarm/hash b/repos/libports/recipes/src/test-libc_alarm/hash new file mode 100644 index 0000000000..0a11eb8f7c --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-08-30 49e1a2b9ef6049be7c0fcee964324fbda54cbed7 diff --git a/repos/libports/recipes/src/test-libc_alarm/used_apis b/repos/libports/recipes/src/test-libc_alarm/used_apis new file mode 100644 index 0000000000..0c483273a8 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/used_apis @@ -0,0 +1,2 @@ +libc +posix diff --git a/repos/libports/src/lib/libc/alarm.cc b/repos/libports/src/lib/libc/alarm.cc new file mode 100644 index 0000000000..250de9a3d6 --- /dev/null +++ b/repos/libports/src/lib/libc/alarm.cc @@ -0,0 +1,118 @@ +/* + * \brief Libc interval timer + * \author Norman Feske + * \date 2024-08-00 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc includes */ +#include + +/* libc-internal includes */ +#include +#include +#include +#include + + +static Libc::Timer_accessor *_timer_accessor_ptr; +static Libc::Signal *_signal_ptr; + +void Libc::init_alarm(Timer_accessor &timer_accessor, Signal &signal) +{ + _timer_accessor_ptr = &timer_accessor; + _signal_ptr = &signal; +} + + +namespace Libc { struct Itimer_real; } + + +struct Libc::Itimer_real : Noncopyable +{ + struct Handler : Timeout_handler + { + Signal &_signal; + + virtual void handle_timeout() override { _signal.charge(SIGALRM); } + + Handler(Signal &signal) : _signal(signal) { } + + } _handler; + + Timer_accessor &_timer_accessor; + + Constructible _timeout { }; + + void arm_or_disarm(timeval tv) + { + Libc::uint64_t const ms = tv.tv_sec*1000 + tv.tv_usec/1000; + + if (ms) { + _timeout.construct(_timer_accessor, _handler); + _timeout->start(ms); + } else { + _timeout.destruct(); + } + } + + timeval current() + { + if (!_timeout.constructed()) + return { }; + + Libc::uint64_t const ms = _timeout->duration_left(); + + return { .tv_sec = long(ms/1000), + .tv_usec = long((ms % 1000)*1000) }; + } + + Itimer_real(Timer_accessor &timer_accessor, Signal &signal) + : + _handler(signal), _timer_accessor(timer_accessor) + { } +}; + + +using namespace Libc; + + +static Itimer_real &itimer_real() +{ + struct Missing_call_of_init_alarm : Exception { }; + if (!_timer_accessor_ptr || !_signal_ptr) + throw Missing_call_of_init_alarm(); + + static Itimer_real itimer { *_timer_accessor_ptr, *_signal_ptr }; + return itimer; +} + + +extern "C" int setitimer(int which, const itimerval *new_value, itimerval *old_value) +{ + if (which != ITIMER_REAL) { + warning("setitimer: timer %d unsupported"); + return Errno(EINVAL); + } + + if (!new_value) + return Errno(EFAULT); + + if (new_value->it_interval.tv_sec || new_value->it_interval.tv_usec) + warning("setitimer: argument 'new_value->it_interval' not handled"); + + if (old_value) { + old_value->it_interval = { }; + old_value->it_value = itimer_real().current(); + } + + itimer_real().arm_or_disarm(new_value->it_value); + + return 0; +} diff --git a/repos/libports/src/lib/libc/dummies.cc b/repos/libports/src/lib/libc/dummies.cc index 8d3606d5ac..1f55acbd58 100644 --- a/repos/libports/src/lib/libc/dummies.cc +++ b/repos/libports/src/lib/libc/dummies.cc @@ -141,7 +141,6 @@ DUMMY(int , -1, seteuid, (uid_t)) DUMMY(int , -1, setgid, (gid_t)) DUMMY(int , -1, setuid, (uid_t)) DUMMY(int , -1, setgroups, (int, const gid_t *)) -DUMMY(int , -1, setitimer, (int, const itimerval *, itimerval *)) DUMMY(int , -1, setpgid, (pid_t, pid_t)) DUMMY(int , -1, setpriority, (int, int, int)) DUMMY(int , -1, setregid, (gid_t, gid_t)) diff --git a/repos/libports/src/lib/libc/internal/init.h b/repos/libports/src/lib/libc/internal/init.h index 433ff7136c..bd3d880bb9 100644 --- a/repos/libports/src/lib/libc/internal/init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -108,6 +108,7 @@ namespace Libc { */ void init_sleep(Monitor &); void init_time(Current_time &, Current_real_time &); + void init_alarm(Timer_accessor &, Signal &); /** * Socket fs diff --git a/repos/libports/src/lib/libc/internal/signal.h b/repos/libports/src/lib/libc/internal/signal.h index e3675f9259..823c352f83 100644 --- a/repos/libports/src/lib/libc/internal/signal.h +++ b/repos/libports/src/lib/libc/internal/signal.h @@ -16,10 +16,13 @@ /* Genode includes */ #include +#include #include +#include /* libc includes */ #include +#include /* libc-internal includes */ #include diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index e37fee0a93..be38ebe987 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -508,6 +508,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) init_vfs_plugin(*this, _env.rm()); init_file_operations(*this, _libc_env); init_time(*this, *this); + init_alarm(_timer_accessor, _signal); init_poll(_signal, *this); init_select(*this); init_socket_fs(*this, *this); diff --git a/repos/libports/src/test/libc_alarm/main.c b/repos/libports/src/test/libc_alarm/main.c new file mode 100644 index 0000000000..e5a61d9c56 --- /dev/null +++ b/repos/libports/src/test/libc_alarm/main.c @@ -0,0 +1,52 @@ +/* + * \brief Libc alarm test + * \author Norman Feske + * \date 2024-08-30 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +static unsigned triggered_alarms; + +static void sigalarm_handler(int) +{ + triggered_alarms++; +} + +int main(int, char **) +{ + static struct sigaction sa; + sa.sa_handler = sigalarm_handler; + + int ret = sigaction(SIGALRM, &sa, NULL); + if (ret < 0) { + printf("sigaction unexpectedly returned %d\n", ret); + return 1; + } + + signal(SIGALRM, sigalarm_handler); + + unsigned observed_alarms = 0; + + alarm(2); + + while (observed_alarms != 3) { + sleep(1); + printf("triggered_alarms=%u\n", triggered_alarms); + + if (triggered_alarms != observed_alarms) { + observed_alarms = triggered_alarms; + alarm(2); + } + } + return 0; +} diff --git a/repos/libports/src/test/libc_alarm/target.mk b/repos/libports/src/test/libc_alarm/target.mk new file mode 100644 index 0000000000..77a61b5d6e --- /dev/null +++ b/repos/libports/src/test/libc_alarm/target.mk @@ -0,0 +1,3 @@ +TARGET = test-libc_alarm +SRC_C = main.c +LIBS = posix