diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 3fe0626c2a2f..26a8c9000cda 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2552,7 +2552,6 @@ Utilities: - tests/unit/list/ - tests/unit/intmath/ - tests/unit/pot/ - - tests/lib/time/ - tests/lib/onoff/ - tests/lib/sys_util/ - tests/lib/sprintf/ diff --git a/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index adbf8f106066..930eafa72ac3 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -217,6 +217,9 @@ New APIs and options * :c:func:`util_eq` * :c:func:`util_memeq` + * :c:func:`sys_clock_gettime` + * :c:func:`sys_clock_settime` + * :c:func:`sys_clock_nanosleep` * LoRaWAN * :c:func:`lorawan_request_link_check` diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 7f944b7db97a..df2980601722 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -60,13 +60,14 @@ struct itimerspec { #include #include #include +#include #ifdef __cplusplus extern "C" { #endif #ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 1 +#define CLOCK_REALTIME SYS_CLOCK_REALTIME #endif #ifndef CLOCK_PROCESS_CPUTIME_ID @@ -78,11 +79,11 @@ extern "C" { #endif #ifndef CLOCK_MONOTONIC -#define CLOCK_MONOTONIC 4 +#define CLOCK_MONOTONIC SYS_CLOCK_MONOTONIC #endif #ifndef TIMER_ABSTIME -#define TIMER_ABSTIME 4 +#define TIMER_ABSTIME SYS_TIMER_ABSTIME #endif int clock_gettime(clockid_t clock_id, struct timespec *ts); diff --git a/include/zephyr/sys/clock.h b/include/zephyr/sys/clock.h new file mode 100644 index 000000000000..7a35bd6593a7 --- /dev/null +++ b/include/zephyr/sys/clock.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System clock APIs + * + * APIs for getting, setting, and sleeping with respect to system clocks. + */ + +#ifndef ZEPHYR_INCLUDE_SYSCLOCK_H_ +#define ZEPHYR_INCLUDE_SYSCLOCK_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup clock_apis + * @{ + */ + +/** + * @brief The real-time clock (i.e. "wall clock") + * + * This clock is used to measure time since the epoch (1970-01-01 00:00:00 UTC). + * + * It is not a steady clock; i.e. it may be adjusted for a number of reasons from initialization + * of a hardware real-time-clock, to network-time synchronization, to manual adjustment from the + * application. + */ +#define SYS_CLOCK_REALTIME 1 + +/** + * @brief The monotonic clock + * + * This steady clock is used to measure time since the system booted. Time from this clock is + * always monotonically increasing, modulo the upper bound of `{.tv_sec = INT64_MAX, .tv_nsec = + * 1000000000}`. + */ +#define SYS_CLOCK_MONOTONIC 4 + +/** + * @brief The flag used for specifying absolute timeouts + * + * This flag may be passed to @ref sys_clock_nanosleep to indicate the requested timeout is an + * absolute time with respect to the specified clock. + */ +#define SYS_TIMER_ABSTIME 4 + +/** + * @brief Get the current time from the specified clock + * + * @param clock_id The clock from which to query time. + * @param tp Pointer to memory where time will be written. + * @retval 0 on success. + * @retval -EINVAL when an invalid @a clock_id is specified. + */ +__syscall int sys_clock_gettime(int clock_id, struct timespec *tp); + +/** + * @brief Set the current time for the specified clock + * + * @param clock_id The clock for which the time should be set. + * @param tp Pointer to memory specifying the desired time. + * @retval 0 on success. + * @retval -EINVAL when an invalid @a clock_id is specified or when @a tp contains nanoseconds + * outside of the range `[0, 999999999]`. + */ +__syscall int sys_clock_settime(int clock_id, const struct timespec *tp); + +/** + * @brief Sleep for the specified amount of time with respect to the specified clock. + * + * This function will cause the calling thread to sleep either + * - until the absolute time specified by @a rqtp (if @a flags includes @ref SYS_TIMER_ABSTIME), or + * - until the relative time specified by @a rqtp (if @a flags does not include + * @ref SYS_TIMER_ABSTIME). + * + * The accepted values for @a clock_id include + * - @ref SYS_CLOCK_REALTIME + * - @ref SYS_CLOCK_MONOTONIC + * + * If @a rmtp is not NULL, and the thread is awoken prior to the time specified by @a rqtp, then + * any remaining time will be written to @a rmtp. If the thread has slept for at least the time + * specified by @a rqtp, then @a rmtp will be set to zero. + * + * @param clock_id The clock to by which to sleep. + * @param flags Flags to modify the behavior of the sleep operation. + * @param rqtp Pointer to the requested time to sleep. + * @param rmtp Pointer to memory into which to copy the remaining time, if any. + * + * @retval 0 on success. + * @retval -EINVAL when an invalid @a clock_id, when @a rqtp contains nanoseconds outside of the + * range `[0, 999999999]`, or when @a rqtp contains a negative value. + */ +__syscall int sys_clock_nanosleep(int clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp); + +/** + * @} + */ + +#include + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 5d981e4719b0..3157fbd99c33 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -84,6 +84,7 @@ config MINIMAL_LIBC imply COMMON_LIBC_MALLOC imply COMMON_LIBC_CALLOC imply COMMON_LIBC_REALLOCARRAY + imply COMMON_LIBC_TIME help Build with minimal C library. @@ -96,6 +97,7 @@ config PICOLIBC select TC_PROVIDES_POSIX_C_LANG_SUPPORT_R imply COMMON_LIBC_MALLOC imply COMMON_LIBC_ABORT + imply COMMON_LIBC_TIME depends on PICOLIBC_SUPPORTED help Build with picolibc library. The picolibc library is built as @@ -116,6 +118,7 @@ config NEWLIB_LIBC imply POSIX_FILE_SYSTEM_ALIAS_FSTAT imply POSIX_MULTI_PROCESS_ALIAS_GETPID imply POSIX_SIGNALS_ALIAS_KILL + imply COMMON_LIBC_TIME help Build with newlib library. The newlib library is expected to be part of the SDK in this case. @@ -137,7 +140,7 @@ config IAR_LIBC depends on IAR_LIBC_SUPPORTED depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "iar" select COMMON_LIBC_STRNLEN - select COMMON_LIBC_TIME if POSIX_TIMERS + select COMMON_LIBC_TIME help Use the full IAR Compiler runtime libraries. A reduced Zephyr minimal libc will be used for library functionality diff --git a/lib/libc/common/source/thrd/thrd.c b/lib/libc/common/source/thrd/thrd.c index d811fe31ce6b..ad2cb72b602f 100644 --- a/lib/libc/common/source/thrd/thrd.c +++ b/lib/libc/common/source/thrd/thrd.c @@ -10,6 +10,7 @@ #include #include #include +#include struct thrd_trampoline_arg { thrd_start_t func; @@ -44,7 +45,11 @@ thrd_t thrd_current(void) int thrd_sleep(const struct timespec *duration, struct timespec *remaining) { - return nanosleep(duration, remaining); + if (sys_clock_nanosleep(SYS_CLOCK_REALTIME, 0, duration, remaining) != 0) { + return thrd_error; + } + + return thrd_success; } void thrd_yield(void) diff --git a/lib/libc/common/source/time/time.c b/lib/libc/common/source/time/time.c index 85840fa8cd94..5eccd733d97b 100644 --- a/lib/libc/common/source/time/time.c +++ b/lib/libc/common/source/time/time.c @@ -1,22 +1,23 @@ /* * Copyright (c) 2021 Golioth, Inc. + * Copyright (c) 2025 Tenstorrent AI ULC * * SPDX-License-Identifier: Apache-2.0 */ +#include #include -/* clock_gettime() prototype */ -#include +#include time_t time(time_t *tloc) { struct timespec ts; int ret; - ret = clock_gettime(CLOCK_REALTIME, &ts); + ret = sys_clock_gettime(SYS_CLOCK_REALTIME, &ts); if (ret < 0) { - /* errno is already set by clock_gettime */ + errno = -ret; return (time_t) -1; } diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 80f5f16f5d79..c8c56d7e0728 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -1,11 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/sys/clock.h ${ZEPHYR_BASE}/include/zephyr/sys/mutex.h ) zephyr_sources( cbprintf_packaged.c + clock.c printk.c sem.c thread_entry.c diff --git a/lib/os/clock.c b/lib/os/clock.c new file mode 100644 index 000000000000..2ded3601cb96 --- /dev/null +++ b/lib/os/clock.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018 Friedt Professional Engineering Services, Inc + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * `k_uptime_get` returns a timestamp based on an always increasing + * value from the system start. To support the `SYS_CLOCK_REALTIME` + * clock, this `rt_clock_base` records the time that the system was + * started. This can either be set via 'sys_clock_settime', or could be + * set from a real time clock, if such hardware is present. + */ +static struct timespec rt_clock_base; +static struct k_spinlock rt_clock_base_lock; + +static inline bool is_valid_clock_id(int clock_id) +{ + switch (clock_id) { + case SYS_CLOCK_MONOTONIC: + case SYS_CLOCK_REALTIME: + return true; + default: + return false; + } +} + +static inline void timespec_from_ticks(uint64_t ticks, struct timespec *ts) +{ + uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + uint64_t nremainder = ticks - elapsed_secs * CONFIG_SYS_CLOCK_TICKS_PER_SEC; + + ts->tv_sec = (time_t)elapsed_secs; + /* For ns 32 bit conversion can be used since its smaller than 1sec. */ + ts->tv_nsec = (int32_t)k_ticks_to_ns_floor32(nremainder); +} + +int z_impl_sys_clock_gettime(int clock_id, struct timespec *ts) +{ + struct timespec base; + + if (!is_valid_clock_id(clock_id)) { + return -EINVAL; + } + + if (clock_id == SYS_CLOCK_REALTIME) { + K_SPINLOCK(&rt_clock_base_lock) { + base = rt_clock_base; + } + } else { + base = (struct timespec){0}; + } + + timespec_from_ticks(k_uptime_ticks(), ts); + if (!timespec_add(ts, &base)) { + return -EOVERFLOW; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy_sys_clock_gettime(int clock_id, struct timespec *ts) +{ + K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); + return z_impl_sys_clock_gettime(clock_id, ts); +} +#include +#endif /* CONFIG_USERSPACE */ + +int z_impl_sys_clock_settime(int clock_id, const struct timespec *tp) +{ + struct timespec base; + + if (clock_id != SYS_CLOCK_REALTIME) { + return -EINVAL; + } + + if (!timespec_is_valid(tp)) { + return -EINVAL; + } + + uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks()); + int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec - elapsed_nsecs; + + base.tv_sec = delta / NSEC_PER_SEC; + base.tv_nsec = delta % NSEC_PER_SEC; + + K_SPINLOCK(&rt_clock_base_lock) { + rt_clock_base = base; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy_sys_clock_settime(int clock_id, const struct timespec *ts) +{ + K_OOPS(K_SYSCALL_MEMORY_READ(ts, sizeof(*ts))); + return z_impl_sys_clock_settime(clock_id, ts); +} +#include +#endif /* CONFIG_USERSPACE */ + +int z_impl_sys_clock_nanosleep(int clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp) +{ + uint64_t ns; + uint64_t uptime_ns; + const bool update_rmtp = rmtp != NULL; + const bool abstime = (flags & SYS_TIMER_ABSTIME) != 0; + + if (!is_valid_clock_id(clock_id)) { + return -EINVAL; + } + + if ((rqtp->tv_sec < 0) || !timespec_is_valid(rqtp)) { + return -EINVAL; + } + + if (!abstime && unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { + ns = rqtp->tv_nsec + NSEC_PER_SEC + + (uint64_t)k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC; + } else { + ns = (uint64_t)rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; + } + + uptime_ns = k_ticks_to_ns_ceil64(sys_clock_tick_get()); + + if (abstime && (clock_id == SYS_CLOCK_REALTIME)) { + K_SPINLOCK(&rt_clock_base_lock) { + ns -= rt_clock_base.tv_sec * NSEC_PER_SEC + rt_clock_base.tv_nsec; + } + } + + if (!abstime) { + ns += uptime_ns; + } + + if (ns <= uptime_ns) { + goto do_rmtp_update; + } + + do { + ns = k_sleep(K_TIMEOUT_ABS_NS(ns)) * NSEC_PER_MSEC; + } while (ns != 0); + +do_rmtp_update: + if (update_rmtp) { + rmtp->tv_sec = 0; + rmtp->tv_nsec = 0; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy_sys_clock_nanosleep(int clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp) +{ + K_OOPS(K_SYSCALL_MEMORY_READ(rqtp, sizeof(*rqtp))); + if (rmtp != NULL) { + K_OOPS(K_SYSCALL_MEMORY_WRITE(rmtp, sizeof(*rmtp))); + } + return z_impl_sys_clock_nanosleep(clock_id, flags, rqtp, rmtp); +} +#include +#endif /* CONFIG_USERSPACE */ + +#ifdef CONFIG_ZTEST +#include +static void reset_clock_base(void) +{ + K_SPINLOCK(&rt_clock_base_lock) { + rt_clock_base = (struct timespec){0}; + } +} + +static void clock_base_reset_rule_after(const struct ztest_unit_test *test, void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + reset_clock_base(); +} + +ZTEST_RULE(clock_base_reset_rule, NULL, clock_base_reset_rule_after); +#endif /* CONFIG_ZTEST */ diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index d62108b66f00..9a40cad191b2 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,4 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 -add_subdirectory(options) +# zephyr-keep-sorted-start +add_subdirectory_ifdef(CONFIG_EVENTFD eventfd) +add_subdirectory_ifdef(CONFIG_POSIX_C_LANG_SUPPORT_R c_lang_support_r) +add_subdirectory_ifdef(CONFIG_POSIX_C_LIB_EXT c_lib_ext) add_subdirectory_ifdef(CONFIG_POSIX_SHELL shell) +add_subdirectory_ifdef(CONFIG_POSIX_SYSTEM_INTERFACES options) +# zephyr-keep-sorted-stop diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 534baf08cd24..4b93901ae17a 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -1,10 +1,45 @@ # Copyright (c) 2024 Meta +# Copyright (c) 2025 Tenstorrent AI ULC # # SPDX-License-Identifier: Apache-2.0 menu "POSIX API Support" +# POSIX Subprofile Definitions +rsource "Kconfig.profile" + +# Toolchain hooks for external implementations +rsource "Kconfig.toolchain" + +# POSIX C Library Extensions +# This menu is for POSIX Option Groups that do not require OS support. +menu "POSIX C Library Extensions" +rsource "c_lang_support_r/Kconfig" +rsource "c_lib_ext/Kconfig" +endmenu + +# POSIX System Interfaces +menuconfig POSIX_SYSTEM_INTERFACES + bool "POSIX System Interfaces" + depends on !NATIVE_APPLICATION + select NATIVE_LIBC_INCOMPATIBLE + help + Select 'y' here to support POSIX System Interfaces within Zephyr. + + Options in this menu are organized by POSIX subprofiling Option Group. + + For more information, see + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html + + +if POSIX_SYSTEM_INTERFACES rsource "options/Kconfig" + +# POSIX Shell utilities rsource "shell/Kconfig" +endif + +endmenu -endmenu # "POSIX API Support" +# Eventfd Support (not officially POSIX) +rsource "eventfd/Kconfig" diff --git a/lib/posix/options/Kconfig.profile b/lib/posix/Kconfig.profile similarity index 78% rename from lib/posix/options/Kconfig.profile rename to lib/posix/Kconfig.profile index 9fdbe71de74e..5d887558dac5 100644 --- a/lib/posix/options/Kconfig.profile +++ b/lib/posix/Kconfig.profile @@ -3,9 +3,8 @@ # SPDX-License-Identifier: Apache-2.0 config POSIX_API - bool "POSIX APIs" - depends on !NATIVE_APPLICATION - select NATIVE_LIBC_INCOMPATIBLE + bool "POSIX API (legacy)" + select POSIX_SYSTEM_INTERFACES select POSIX_BASE_DEFINITIONS # clock_gettime(), pthread_create(), sem_get(), etc select POSIX_AEP_REALTIME_MINIMAL # CLOCK_MONOTONIC, pthread_attr_setstack(), etc select POSIX_NETWORKING if NETWORKING # inet_ntoa(), socket(), etc @@ -21,7 +20,7 @@ config POSIX_API choice POSIX_AEP_CHOICE prompt "POSIX Subprofile" - default POSIX_AEP_CHOICE_NONE + default POSIX_AEP_CHOICE_ZEPHYR help This choice is intended to help users select the correct POSIX profile for their application. Choices are based on IEEE 1003.13-2003 (now inactive / reserved) and @@ -32,14 +31,35 @@ choice POSIX_AEP_CHOICE https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html config POSIX_AEP_CHOICE_NONE - bool "No pre-defined POSIX subprofile" + bool "No POSIX subprofile" help - No pre-defined POSIX profile is selected. + No POSIX subprofile is selected. + +config POSIX_AEP_CHOICE_ZEPHYR + bool "Minimal Zephyr System Profile" + select POSIX_C_LIB_EXT + select POSIX_C_LANG_SUPPORT_R + help + Zephyr expects certain POSIX functions to be available throughout the build environment, + such as gmtime_r(), strnlen(), strtok_r(), and possibly others. + + These functions are divided into two standalone Option Groups that may be enabled + independently of the remainder of the POSIX API implementation; namely POSIX_C_LIB_EXT and + POSIX_C_LANG_SUPPORT_R. If not referenced by the Zephyr kernel or application, there are no + resource implications for enabling these option groups. + + Unlike pre-defined, standard POSIX subprofiles, this subprofile is custom to Zephyr and + therefore does not need to include the base definitions or system interfaces that would + otherwise be required for a conformant POSIX system or subprofile. This system profile + does not itself meet the requirements for POSIX implementation conformance. + + For more information, see + https://docs.zephyrproject.org/latest/contribute/coding_guidelines/index.html + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html config POSIX_AEP_CHOICE_BASE - bool "Base definitions (system interfaces)" - depends on !NATIVE_APPLICATION - select NATIVE_LIBC_INCOMPATIBLE + bool "Minimal POSIX System Profile" + depends on POSIX_SYSTEM_INTERFACES select POSIX_BASE_DEFINITIONS help Only enable the base definitions required for all POSIX systems. @@ -49,8 +69,7 @@ config POSIX_AEP_CHOICE_BASE config POSIX_AEP_CHOICE_PSE51 bool "Minimal Realtime System Profile (PSE51)" - depends on !NATIVE_APPLICATION - select NATIVE_LIBC_INCOMPATIBLE + depends on POSIX_SYSTEM_INTERFACES select POSIX_BASE_DEFINITIONS select POSIX_AEP_REALTIME_MINIMAL help @@ -63,8 +82,7 @@ config POSIX_AEP_CHOICE_PSE51 config POSIX_AEP_CHOICE_PSE52 bool "Realtime Controller System Profile (PSE52)" - depends on !NATIVE_APPLICATION - select NATIVE_LIBC_INCOMPATIBLE + depends on POSIX_SYSTEM_INTERFACES select POSIX_BASE_DEFINITIONS select POSIX_AEP_REALTIME_MINIMAL select POSIX_AEP_REALTIME_CONTROLLER @@ -78,8 +96,7 @@ config POSIX_AEP_CHOICE_PSE52 config POSIX_AEP_CHOICE_PSE53 bool "Dedicated Realtime System Profile (PSE53)" - depends on !NATIVE_APPLICATION - select NATIVE_LIBC_INCOMPATIBLE + depends on POSIX_SYSTEM_INTERFACES select POSIX_BASE_DEFINITIONS select POSIX_AEP_REALTIME_MINIMAL select POSIX_AEP_REALTIME_CONTROLLER @@ -96,7 +113,9 @@ config POSIX_AEP_CHOICE_PSE53 endchoice # POSIX_AEP_CHOICE -# Base Definitions (System Interfaces) +if POSIX_SYSTEM_INTERFACES + +# Mandatory POSIX System Interfaces (base profile) config POSIX_BASE_DEFINITIONS bool select POSIX_ASYNCHRONOUS_IO @@ -184,3 +203,5 @@ config POSIX_AEP_REALTIME_DEDICATED For more information, please see https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html + +endif # POSIX_SYSTEM_INTERFACE diff --git a/lib/posix/options/Kconfig.toolchain b/lib/posix/Kconfig.toolchain similarity index 100% rename from lib/posix/options/Kconfig.toolchain rename to lib/posix/Kconfig.toolchain diff --git a/lib/posix/c_lang_support_r/CMakeLists.txt b/lib/posix/c_lang_support_r/CMakeLists.txt new file mode 100644 index 000000000000..636bc1a8abf9 --- /dev/null +++ b/lib/posix/c_lang_support_r/CMakeLists.txt @@ -0,0 +1 @@ +# intentionally empty diff --git a/lib/posix/options/Kconfig.c_lang_r b/lib/posix/c_lang_support_r/Kconfig similarity index 100% rename from lib/posix/options/Kconfig.c_lang_r rename to lib/posix/c_lang_support_r/Kconfig diff --git a/lib/posix/c_lib_ext/CMakeLists.txt b/lib/posix/c_lib_ext/CMakeLists.txt new file mode 100644 index 000000000000..95b594cbb5b8 --- /dev/null +++ b/lib/posix/c_lib_ext/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(getopt) + +if (CONFIG_TC_PROVIDES_POSIX_C_LIB_EXT) + return() +endif() + +zephyr_library() +zephyr_library_sources( + fnmatch.c + getentropy.c + getopt/getopt.c + getopt/getopt_common.c + getopt/getsubopt.c +) + +zephyr_library_sources_ifdef(CONFIG_GETOPT_LONG getopt/getopt_long.c) diff --git a/lib/posix/options/Kconfig.c_lib_ext b/lib/posix/c_lib_ext/Kconfig similarity index 92% rename from lib/posix/options/Kconfig.c_lib_ext rename to lib/posix/c_lib_ext/Kconfig index 9dc4ae52520e..b32988a9c35e 100644 --- a/lib/posix/options/Kconfig.c_lib_ext +++ b/lib/posix/c_lib_ext/Kconfig @@ -26,4 +26,8 @@ config GETOPT_LONG for other threads by extending function getopt_state_get in getopt_common.c file. +module = GETOPT +module-str = getopt +source "subsys/logging/Kconfig.template.log_config" + endif # POSIX_C_LIB_EXT diff --git a/lib/posix/options/fnmatch.c b/lib/posix/c_lib_ext/fnmatch.c similarity index 100% rename from lib/posix/options/fnmatch.c rename to lib/posix/c_lib_ext/fnmatch.c diff --git a/lib/posix/options/getentropy.c b/lib/posix/c_lib_ext/getentropy.c similarity index 100% rename from lib/posix/options/getentropy.c rename to lib/posix/c_lib_ext/getentropy.c diff --git a/lib/posix/options/getopt/README b/lib/posix/c_lib_ext/getopt/README similarity index 100% rename from lib/posix/options/getopt/README rename to lib/posix/c_lib_ext/getopt/README diff --git a/lib/posix/options/getopt/getopt.c b/lib/posix/c_lib_ext/getopt/getopt.c similarity index 98% rename from lib/posix/options/getopt/getopt.c rename to lib/posix/c_lib_ext/getopt/getopt.c index c34e7fd7dccd..2e53a3783e2d 100644 --- a/lib/posix/options/getopt/getopt.c +++ b/lib/posix/c_lib_ext/getopt/getopt.c @@ -39,7 +39,7 @@ #include "getopt_common.h" #include -LOG_MODULE_REGISTER(getopt); +LOG_MODULE_REGISTER(getopt, CONFIG_GETOPT_LOG_LEVEL); #define BADCH ((int)'?') #define BADARG ((int)':') diff --git a/lib/posix/options/getopt/getopt.h b/lib/posix/c_lib_ext/getopt/getopt.h similarity index 100% rename from lib/posix/options/getopt/getopt.h rename to lib/posix/c_lib_ext/getopt/getopt.h diff --git a/lib/posix/options/getopt/getopt_common.c b/lib/posix/c_lib_ext/getopt/getopt_common.c similarity index 100% rename from lib/posix/options/getopt/getopt_common.c rename to lib/posix/c_lib_ext/getopt/getopt_common.c diff --git a/lib/posix/options/getopt/getopt_common.h b/lib/posix/c_lib_ext/getopt/getopt_common.h similarity index 100% rename from lib/posix/options/getopt/getopt_common.h rename to lib/posix/c_lib_ext/getopt/getopt_common.h diff --git a/lib/posix/options/getopt/getopt_long.c b/lib/posix/c_lib_ext/getopt/getopt_long.c similarity index 99% rename from lib/posix/options/getopt/getopt_long.c rename to lib/posix/c_lib_ext/getopt/getopt_long.c index bb77a1f0ea81..6378c0bc3734 100644 --- a/lib/posix/options/getopt/getopt_long.c +++ b/lib/posix/c_lib_ext/getopt/getopt_long.c @@ -54,7 +54,7 @@ #include "getopt_common.h" #include -LOG_MODULE_DECLARE(getopt); +LOG_MODULE_DECLARE(getopt, CONFIG_GETOPT_LOG_LEVEL); #define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ diff --git a/lib/posix/c_lib_ext/getopt/getsubopt.c b/lib/posix/c_lib_ext/getopt/getsubopt.c new file mode 100644 index 000000000000..cfa2130a84c0 --- /dev/null +++ b/lib/posix/c_lib_ext/getopt/getsubopt.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(getopt, CONFIG_GETOPT_LOG_LEVEL); + +int getsubopt(char **optionp, char *const *keylist, char **valuep) +{ + size_t i, len; + char *begin, *end, *eq, *key, *val; + + if (optionp == NULL || keylist == NULL) { + LOG_DBG("optionp or keylist is NULL"); + return -1; + } + + if (valuep != NULL) { + *valuep = NULL; + } + + for (i = 0, begin = *optionp, end = begin, eq = NULL, len = strlen(*optionp); i <= len; + ++i, ++end) { + + char c = *end; + + if ((c == '=') && (eq == NULL)) { + eq = end; + } else if (c == ',') { + *end = '\0'; + *optionp = end + 1; + break; + } else if (c == '\0') { + *optionp = end; + break; + } + } + + key = begin; + if (eq == NULL) { + len = end - begin; + if (valuep != NULL) { + *valuep = NULL; + } + LOG_DBG("key: %.*s", (int)len, key); + } else { + len = eq - begin; + val = eq + 1; + if (valuep != NULL) { + *valuep = val; + } + LOG_DBG("key: %.*s val: %.*s", (int)len, key, (int)(end - val), val); + } + + if (len == 0) { + LOG_DBG("zero-length key"); + return -1; + } + + for (i = 0; true; ++i) { + if (keylist[i] == NULL) { + LOG_DBG("end of keylist of length %zu reached", i); + break; + } + + if (strncmp(key, keylist[i], len) != 0) { + continue; + } + + if (keylist[i][len] != '\0') { + LOG_DBG("key %.*s does not match keylist[%zu]: %s", (int)len, key, i, + keylist[i]); + continue; + } + + return (int)i; + } + + return -1; +} diff --git a/lib/posix/c_lib_ext/stpcpy.c b/lib/posix/c_lib_ext/stpcpy.c new file mode 100644 index 000000000000..4ed96d0aba4f --- /dev/null +++ b/lib/posix/c_lib_ext/stpcpy.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +char *stpncpy(char *ZRESTRICT s1, const char *ZRESTRICT s2, size_t n) +{ + char *ret = NULL; + + for (; n != 0; ++s1, ++s2, --n) { + *s1 = *s2; + if (*s2 == '\0') { + ret = s1; + } + } + + for (; n != 0; --n) { + *s1++ = '\0'; + } + + if (ret == NULL) { + ret = s1; + } + + return ret; +} + +char *stpcpy(char *ZRESTRICT s1, const char *ZRESTRICT s2) +{ + return stpncpy(s1, s2, strlen(s2) + 1); +} diff --git a/lib/posix/c_lib_ext/strcasecmp.c b/lib/posix/c_lib_ext/strcasecmp.c new file mode 100644 index 000000000000..26fc365ed0d6 --- /dev/null +++ b/lib/posix/c_lib_ext/strcasecmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + int c1, c2; + + for (; n != 0; --n) { + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0') { + return c1 - c2; + } + if (c2 == '\0') { + return c1 - c2; + } + + c1 = tolower(c1); + c2 = tolower(c2); + + if (c1 != c2) { + return c1 - c2; + } + } + + return 0; +} + +int strcasecmp(const char *s1, const char *s2) +{ + return strncasecmp(s1, s2, MIN(strlen(s1), strlen(s2))); +} diff --git a/lib/posix/c_lib_ext/strdup.c b/lib/posix/c_lib_ext/strdup.c new file mode 100644 index 000000000000..0a9da656eef5 --- /dev/null +++ b/lib/posix/c_lib_ext/strdup.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +char *strndup(const char *s, size_t n) +{ + size_t len = strlen(s); + char *ret = malloc(n); + + if (ret != NULL) { + strncpy(ret, s, n); + ret[n - 1] = '\0'; + } + + return ret; +} + +char *strdup(const char *s) +{ + return strndup(s, strlen(s) + 1); +} diff --git a/lib/posix/c_lib_ext/strnlen.c b/lib/posix/c_lib_ext/strnlen.c new file mode 100644 index 000000000000..d94463d10a2c --- /dev/null +++ b/lib/posix/c_lib_ext/strnlen.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +size_t strnlen(const char *s, size_t maxlen) +{ + size_t len; + + for (len = 0; len < maxlen && s[len] != '\0'; ++len) { + /* nothing to do */ + } + + return len; +} diff --git a/lib/posix/eventfd/CMakeLists.txt b/lib/posix/eventfd/CMakeLists.txt new file mode 100644 index 000000000000..2736572dd006 --- /dev/null +++ b/lib/posix/eventfd/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(eventfd.c) diff --git a/lib/posix/options/Kconfig.compat b/lib/posix/eventfd/Kconfig similarity index 88% rename from lib/posix/options/Kconfig.compat rename to lib/posix/eventfd/Kconfig index a07c2b125795..16c086762f44 100644 --- a/lib/posix/options/Kconfig.compat +++ b/lib/posix/eventfd/Kconfig @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: Apache-2.0 -menu "Miscellaneous POSIX-related options" - config EVENTFD bool "Support for eventfd" depends on !NATIVE_APPLICATION @@ -14,5 +12,3 @@ config EVENTFD Enable support for event file descriptors, eventfd. An eventfd can be used as an event wait/notify mechanism together with POSIX calls like read, write and poll. - -endmenu diff --git a/lib/posix/options/eventfd.c b/lib/posix/eventfd/eventfd.c similarity index 100% rename from lib/posix/options/eventfd.c rename to lib/posix/eventfd/eventfd.c diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index f12904aefb60..47e392a28ac0 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -2,10 +2,6 @@ set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) -zephyr_syscall_header_ifdef(CONFIG_POSIX_CLOCK_SELECTION posix_clock.h) -zephyr_syscall_header_ifdef(CONFIG_POSIX_TIMERS posix_clock.h) -zephyr_syscall_header_ifdef(CONFIG_XSI_SINGLE_PROCESS posix_clock.h) - if(CONFIG_POSIX_API) zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) endif() @@ -27,8 +23,8 @@ if (NOT CONFIG_TC_PROVIDES_POSIX_SIGNALS) endif() if(CONFIG_POSIX_API OR CONFIG_POSIX_THREADS OR CONFIG_POSIX_TIMERS OR - CONFIG_POSIX_MESSAGE_PASSING OR CONFIG_POSIX_FILE_SYSTEM OR CONFIG_EVENTFD OR - CONFIG_POSIX_C_LIB_EXT OR CONFIG_POSIX_SINGLE_PROCESS) + CONFIG_POSIX_MESSAGE_PASSING OR CONFIG_POSIX_FILE_SYSTEM OR + CONFIG_POSIX_SINGLE_PROCESS) # This is a temporary workaround so that Newlib declares the appropriate # types for us. POSIX features to be formalized as part of #51211 zephyr_compile_options($<$:-D_POSIX_THREADS>) @@ -36,7 +32,6 @@ if(CONFIG_POSIX_API OR CONFIG_POSIX_THREADS OR CONFIG_POSIX_TIMERS OR endif() zephyr_library() -zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) if (NOT CONFIG_TC_PROVIDES_POSIX_ASYNCHRONOUS_IO) zephyr_library_sources_ifdef(CONFIG_POSIX_ASYNCHRONOUS_IO aio.c) @@ -47,19 +42,7 @@ if (NOT CONFIG_TC_PROVIDES_POSIX_BARRIERS) endif() if (NOT CONFIG_TC_PROVIDES_POSIX_CLOCK_SELECTION) - zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK_SELECTION - clock_common.c - clock_selection.c - ) -endif() - -if (NOT CONFIG_TC_PROVIDES_POSIX_C_LIB_EXT) - zephyr_library_sources_ifdef(CONFIG_POSIX_C_LIB_EXT - fnmatch.c - getentropy.c - getopt/getopt.c - getopt/getopt_common.c - ) + zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK_SELECTION clock_selection.c) endif() if (NOT CONFIG_TC_PROVIDES_POSIX_DEVICE_IO) @@ -124,7 +107,6 @@ endif() if (NOT CONFIG_TC_PROVIDES_POSIX_TIMERS) zephyr_library_sources_ifdef(CONFIG_POSIX_TIMERS clock.c - clock_common.c timer.c timespec_to_timeout.c ) @@ -166,7 +148,6 @@ zephyr_library_sources_ifdef(CONFIG_XOPEN_STREAMS stropts.c) if (NOT CONFIG_TC_PROVIDES_XSI_SINGLE_PROCESS) zephyr_library_sources_ifdef(CONFIG_XSI_SINGLE_PROCESS - clock_common.c env_common.c xsi_single_process.c ) @@ -176,13 +157,6 @@ if (NOT CONFIG_TC_PROVIDES_XSI_SYSTEM_LOGGING) zephyr_library_sources_ifdef(CONFIG_XSI_SYSTEM_LOGGING syslog.c) endif() -zephyr_library_sources_ifdef(CONFIG_GETOPT_LONG - getopt/getopt_long.c -) -zephyr_include_directories_ifdef(CONFIG_POSIX_C_LIB_EXT - getopt/ -) - zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index 6c2b129170e3..3f072a293f6b 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -4,14 +4,9 @@ # # SPDX-License-Identifier: Apache-2.0 -menu "POSIX Options" - -rsource "Kconfig.profile" - +# zephyr-keep-sorted-start rsource "Kconfig.aio" rsource "Kconfig.barrier" -rsource "Kconfig.c_lang_r" -rsource "Kconfig.c_lib_ext" rsource "Kconfig.device_io" rsource "Kconfig.fd_mgmt" rsource "Kconfig.file_system_r" @@ -29,19 +24,16 @@ rsource "Kconfig.signal" rsource "Kconfig.spinlock" rsource "Kconfig.sync_io" rsource "Kconfig.timer" +# zephyr-keep-sorted-stop menu "X/Open system interfaces" +# zephyr-keep-sorted-start rsource "Kconfig.xsi_realtime" rsource "Kconfig.xsi_single_process" rsource "Kconfig.xsi_streams" rsource "Kconfig.xsi_system_logging" rsource "Kconfig.xsi_threads_ext" +# zephyr-keep-sorted-stop endmenu # "X/Open system interfaces" - -rsource "Kconfig.compat" - -rsource "Kconfig.toolchain" - -endmenu # "POSIX Options" diff --git a/lib/posix/options/clock.c b/lib/posix/options/clock.c index 1f4533467312..239dadb69266 100644 --- a/lib/posix/options/clock.c +++ b/lib/posix/options/clock.c @@ -8,18 +8,23 @@ #include #include -#include +#include #include +#include #include - -extern int z_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp); -extern int z_clock_gettime(clockid_t clock_id, struct timespec *ts); -extern int z_clock_settime(clockid_t clock_id, const struct timespec *tp); +#include int clock_gettime(clockid_t clock_id, struct timespec *ts) { - return z_clock_gettime(clock_id, ts); + int ret; + + ret = sys_clock_gettime((int)clock_id, ts); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } int clock_getres(clockid_t clock_id, struct timespec *res) @@ -54,7 +59,15 @@ int clock_getres(clockid_t clock_id, struct timespec *res) */ int clock_settime(clockid_t clock_id, const struct timespec *tp) { - return z_clock_settime(clock_id, tp); + int ret; + + ret = sys_clock_settime((int)clock_id, tp); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } /* @@ -88,7 +101,20 @@ int usleep(useconds_t useconds) int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { - return z_clock_nanosleep(CLOCK_MONOTONIC, 0, rqtp, rmtp); + int ret; + + if (rqtp == NULL) { + errno = EFAULT; + return -1; + } + + ret = sys_clock_nanosleep(SYS_CLOCK_REALTIME, 0, rqtp, rmtp); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } int clock_getcpuclockid(pid_t pid, clockid_t *clock_id) diff --git a/lib/posix/options/clock_common.c b/lib/posix/options/clock_common.c deleted file mode 100644 index c8271cf185dd..000000000000 --- a/lib/posix/options/clock_common.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * Copyright (c) 2018 Friedt Professional Engineering Services, Inc - * Copyright (c) 2025 Tenstorrent AI ULC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "posix_clock.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * `k_uptime_get` returns a timestamp based on an always increasing - * value from the system start. To support the `CLOCK_REALTIME` - * clock, this `rt_clock_base` records the time that the system was - * started. This can either be set via 'clock_settime', or could be - * set from a real time clock, if such hardware is present. - */ -static struct timespec rt_clock_base; -static SYS_SEM_DEFINE(rt_clock_base_lock, 1, 1); - -int z_impl___posix_clock_get_base(clockid_t clock_id, struct timespec *base) -{ - switch (clock_id) { - case CLOCK_MONOTONIC: - base->tv_sec = 0; - base->tv_nsec = 0; - break; - - case CLOCK_REALTIME: - SYS_SEM_LOCK(&rt_clock_base_lock) { - *base = rt_clock_base; - } - break; - - default: - errno = EINVAL; - return -1; - } - - return 0; -} - -#ifdef CONFIG_USERSPACE -int z_vrfy___posix_clock_get_base(clockid_t clock_id, struct timespec *ts) -{ - K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); - return z_impl___posix_clock_get_base(clock_id, ts); -} -#include -#endif - -int z_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - struct timespec base = {.tv_sec = 0, .tv_nsec = 0}; - - switch (clock_id) { - case CLOCK_MONOTONIC: - break; - - case CLOCK_REALTIME: - (void)__posix_clock_get_base(clock_id, &base); - break; - - default: - errno = EINVAL; - return -1; - } - - uint64_t ticks = k_uptime_ticks(); - uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC; - uint64_t nremainder = ticks - elapsed_secs * CONFIG_SYS_CLOCK_TICKS_PER_SEC; - - ts->tv_sec = (time_t)elapsed_secs; - /* For ns 32 bit conversion can be used since its smaller than 1sec. */ - ts->tv_nsec = (int32_t)k_ticks_to_ns_floor32(nremainder); - - if (unlikely(!timespec_normalize(ts)) || unlikely(!timespec_add(ts, &base))) { - errno = EOVERFLOW; - return -1; - } - - return 0; -} - -int z_clock_settime(clockid_t clock_id, const struct timespec *tp) -{ - struct timespec base; - - if (clock_id != CLOCK_REALTIME) { - errno = EINVAL; - return -1; - } - - if (!timespec_is_valid(tp)) { - errno = EINVAL; - return -1; - } - - uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks()); - int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec - elapsed_nsecs; - - base.tv_sec = delta / NSEC_PER_SEC; - base.tv_nsec = delta % NSEC_PER_SEC; - - if (unlikely(!timespec_normalize(&base))) { - errno = EOVERFLOW; - return -1; - } - - SYS_SEM_LOCK(&rt_clock_base_lock) { - rt_clock_base = base; - } - - return 0; -} - -int z_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp) -{ - uint64_t ns; - uint64_t us; - uint64_t uptime_ns; - const bool update_rmtp = rmtp != NULL; - - if (!((clock_id == CLOCK_REALTIME) || (clock_id == CLOCK_MONOTONIC))) { - errno = EINVAL; - return -1; - } - - if (rqtp == NULL) { - errno = EFAULT; - return -1; - } - - if ((rqtp->tv_sec < 0) || !timespec_is_valid(rqtp)) { - errno = EINVAL; - return -1; - } - - if ((flags & TIMER_ABSTIME) == 0 && unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { - ns = rqtp->tv_nsec + NSEC_PER_SEC + - (uint64_t)k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC; - } else { - ns = (uint64_t)rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; - } - - uptime_ns = k_ticks_to_ns_ceil64(sys_clock_tick_get()); - - if (flags & TIMER_ABSTIME && clock_id == CLOCK_REALTIME) { - SYS_SEM_LOCK(&rt_clock_base_lock) { - ns -= rt_clock_base.tv_sec * NSEC_PER_SEC + rt_clock_base.tv_nsec; - } - } - - if ((flags & TIMER_ABSTIME) == 0) { - ns += uptime_ns; - } - - if (ns <= uptime_ns) { - goto do_rmtp_update; - } - - us = DIV_ROUND_UP(ns, NSEC_PER_USEC); - do { - us = k_sleep(K_TIMEOUT_ABS_US(us)) * 1000; - } while (us != 0); - -do_rmtp_update: - if (update_rmtp) { - rmtp->tv_sec = 0; - rmtp->tv_nsec = 0; - } - - return 0; -} - -#ifdef CONFIG_ZTEST -#include -static void reset_clock_base(void) -{ - SYS_SEM_LOCK(&rt_clock_base_lock) { - rt_clock_base = (struct timespec){0}; - } -} - -static void clock_base_reset_rule_after(const struct ztest_unit_test *test, void *data) -{ - ARG_UNUSED(test); - ARG_UNUSED(data); - - reset_clock_base(); -} - -ZTEST_RULE(clock_base_reset_rule, NULL, clock_base_reset_rule_after); -#endif /* CONFIG_ZTEST */ diff --git a/lib/posix/options/clock_selection.c b/lib/posix/options/clock_selection.c index 6bddc3212080..c67d48ff0253 100644 --- a/lib/posix/options/clock_selection.c +++ b/lib/posix/options/clock_selection.c @@ -13,15 +13,26 @@ #include #include +#include #include -extern int z_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp); - -extern int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp) +int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp) { - return z_clock_nanosleep(clock_id, flags, rqtp, rmtp); + int ret; + + if (rqtp == NULL) { + errno = EFAULT; + return -1; + } + + ret = sys_clock_nanosleep((int)clock_id, flags, rqtp, rmtp); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; } int pthread_condattr_getclock(const pthread_condattr_t *ZRESTRICT att, diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index 86b4e2e7eb22..c4c03a572a45 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -61,12 +61,8 @@ static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct ti uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstime); -__syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); - /** INTERNAL_HIDDEN @endcond */ -#include - #ifdef __cplusplus } #endif diff --git a/lib/posix/options/xsi_single_process.c b/lib/posix/options/xsi_single_process.c index cc5e82cb99a7..006577fedbee 100644 --- a/lib/posix/options/xsi_single_process.c +++ b/lib/posix/options/xsi_single_process.c @@ -12,14 +12,15 @@ #include #include +#include #include #include +#include #include LOG_MODULE_REGISTER(xsi_single_process, CONFIG_XSI_SINGLE_PROCESS_LOG_LEVEL); extern int z_setenv(const char *name, const char *val, int overwrite); -extern int z_clock_gettime(clockid_t clockid, struct timespec *tp); long gethostid(void) { @@ -46,10 +47,11 @@ int gettimeofday(struct timeval *tv, void *tz) */ ARG_UNUSED(tz); - res = z_clock_gettime(CLOCK_REALTIME, &ts); + res = sys_clock_gettime(SYS_CLOCK_REALTIME, &ts); if (res < 0) { - LOG_DBG("%s() failed: %d", "clock_gettime", res); - return res; + LOG_DBG("%s() failed: %d", "sys_clock_gettime", res); + errno = -res; + return -1; } tv->tv_sec = ts.tv_sec; diff --git a/samples/net/cloud/aws_iot_mqtt/prj.conf b/samples/net/cloud/aws_iot_mqtt/prj.conf index ef5f6574ef75..825bd8514b95 100644 --- a/samples/net/cloud/aws_iot_mqtt/prj.conf +++ b/samples/net/cloud/aws_iot_mqtt/prj.conf @@ -39,7 +39,6 @@ CONFIG_NET_DHCPV4=y # SNTP CONFIG_SNTP=y -CONFIG_POSIX_TIMERS=y CONFIG_NET_CONFIG_CLOCK_SNTP_INIT=y CONFIG_NET_CONFIG_SNTP_INIT_SERVER="0.pool.ntp.org" diff --git a/samples/net/lwm2m_client/overlay-data-cache.conf b/samples/net/lwm2m_client/overlay-data-cache.conf index 523b23519add..f8356b12d95a 100644 --- a/samples/net/lwm2m_client/overlay-data-cache.conf +++ b/samples/net/lwm2m_client/overlay-data-cache.conf @@ -1,5 +1,4 @@ CONFIG_ZCBOR=y CONFIG_ZCBOR_CANONICAL=y CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT=y -CONFIG_XSI_SINGLE_PROCESS=y CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT=y diff --git a/subsys/net/lib/config/Kconfig b/subsys/net/lib/config/Kconfig index d0a98d207ed6..82b534888d43 100644 --- a/subsys/net/lib/config/Kconfig +++ b/subsys/net/lib/config/Kconfig @@ -206,7 +206,7 @@ endif # NET_DHCPV6 config NET_CONFIG_CLOCK_SNTP_INIT bool "Initialize system clock using SNTP on application startup" - depends on SNTP && POSIX_TIMERS + depends on SNTP help Perform an SNTP request over networking to get and absolute wall clock time, and initialize system time from it, so diff --git a/subsys/net/lib/config/init_clock_sntp.c b/subsys/net/lib/config/init_clock_sntp.c index dd63564f9c02..7f0b9d7979ff 100644 --- a/subsys/net/lib/config/init_clock_sntp.c +++ b/subsys/net/lib/config/init_clock_sntp.c @@ -12,7 +12,6 @@ LOG_MODULE_DECLARE(net_config, CONFIG_NET_CONFIG_LOG_LEVEL); #include #include #include -#include #ifdef CONFIG_NET_CONFIG_SNTP_INIT_RESYNC static void sntp_resync_handler(struct k_work *work); @@ -60,7 +59,7 @@ int net_init_clock_via_sntp(void) tspec.tv_sec = ts.seconds; tspec.tv_nsec = ((uint64_t)ts.fraction * (1000 * 1000 * 1000)) >> 32; - res = clock_settime(CLOCK_REALTIME, &tspec); + res = sys_clock_settime(SYS_CLOCK_REALTIME, &tspec); end: #ifdef CONFIG_NET_CONFIG_SNTP_INIT_RESYNC diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 9872e2acd915..8bd0cdef300f 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -227,7 +227,7 @@ config LWM2M_RD_CLIENT_MAX_RETRIES config LWM2M_RESOURCE_DATA_CACHE_SUPPORT bool "Resource Time series data cache support" depends on (LWM2M_RW_SENML_JSON_SUPPORT || LWM2M_RW_SENML_CBOR_SUPPORT) - depends on (XSI_SINGLE_PROCESS && RING_BUFFER) + depends on RING_BUFFER help Enable time series data storage. Requires time() to provide current Unix timestamp. diff --git a/tests/lib/c_lib/thrd/src/thrd.c b/tests/lib/c_lib/thrd/src/thrd.c index 70dca94b4a9a..6a9f0b5de171 100644 --- a/tests/lib/c_lib/thrd/src/thrd.c +++ b/tests/lib/c_lib/thrd/src/thrd.c @@ -10,6 +10,7 @@ #include #include +#include #include static thrd_t thr; @@ -23,17 +24,21 @@ ZTEST(libc_thrd, test_thrd_sleep) struct timespec remaining; const uint16_t delay_ms[] = {0, 100, 200, 400}; - zassert_not_equal(0, thrd_sleep(NULL, NULL)); - zassert_ok(thrd_sleep(&duration, NULL)); - zassert_ok(thrd_sleep(&duration, &duration)); + if (false) { + /* duration may not be NULL */ + zassert_not_equal(thrd_success, thrd_sleep(NULL, NULL)); + } + + zassert_equal(thrd_success, thrd_sleep(&duration, NULL)); + zassert_equal(thrd_success, thrd_sleep(&duration, &duration)); for (int i = 0; i < ARRAY_SIZE(delay_ms); ++i) { - duration = (struct timespec){.tv_nsec = delay_ms[i] * NSEC_PER_MSEC}; + timespec_from_timeout(K_MSEC(delay_ms[i]), &duration); remaining = (struct timespec){.tv_sec = 4242, .tv_nsec = 4242}; printk("sleeping %d ms\n", delay_ms[i]); start = k_uptime_get(); - zassert_ok(thrd_sleep(&duration, &remaining)); + zassert_equal(thrd_success, thrd_sleep(&duration, &remaining)); end = k_uptime_get(); zassert_equal(remaining.tv_sec, 0); zassert_equal(remaining.tv_nsec, 0); diff --git a/tests/lib/time/CMakeLists.txt b/tests/lib/c_lib/time/CMakeLists.txt similarity index 100% rename from tests/lib/time/CMakeLists.txt rename to tests/lib/c_lib/time/CMakeLists.txt diff --git a/tests/lib/c_lib/time/prj.conf b/tests/lib/c_lib/time/prj.conf new file mode 100644 index 000000000000..97b1a4e7da24 --- /dev/null +++ b/tests/lib/c_lib/time/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_PICOLIBC=y diff --git a/tests/lib/time/src/main.c b/tests/lib/c_lib/time/src/main.c similarity index 83% rename from tests/lib/time/src/main.c rename to tests/lib/c_lib/time/src/main.c index 227ed25131f5..e7346738a16f 100644 --- a/tests/lib/time/src/main.c +++ b/tests/lib/c_lib/time/src/main.c @@ -37,7 +37,7 @@ ZTEST(libc_time, test_time_passing) time_current = time(NULL); zassert_equal(time_current, time_initial + i, "Current time (%d) does not match expected time (%d)", - (int) time_current, (int) (time_initial + i)); + (int)time_current, (int)(time_initial + i)); } } @@ -49,14 +49,12 @@ ZTEST(libc_time, test_time_param) time_result = time(&time_param); - zassert_equal(time_result, time_param, - "time() result does not match param value"); + zassert_equal(time_result, time_param, "time() result does not match param value"); for (i = 0; i < 10; i++) { k_sleep(K_SECONDS(1)); - zassert_equal(time_result, time_param, - "time() result does not match param value"); + zassert_equal(time_result, time_param, "time() result does not match param value"); } } diff --git a/tests/lib/time/testcase.yaml b/tests/lib/c_lib/time/testcase.yaml similarity index 100% rename from tests/lib/time/testcase.yaml rename to tests/lib/c_lib/time/testcase.yaml diff --git a/tests/lib/time/prj.conf b/tests/lib/time/prj.conf deleted file mode 100644 index dd87f5a1338c..000000000000 --- a/tests/lib/time/prj.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_POSIX_TIMERS=y -CONFIG_XSI_SINGLE_PROCESS=y -CONFIG_PICOLIBC=y diff --git a/tests/posix/c_lib_ext/src/getsubopt.c b/tests/posix/c_lib_ext/src/getsubopt.c new file mode 100644 index 000000000000..06043431a9e7 --- /dev/null +++ b/tests/posix/c_lib_ext/src/getsubopt.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +extern int getsubopt(char **optionp, char *const *keylistp, char **valuep); + +ZTEST(posix_c_lib_ext, test_getsubopt) +{ + char *value; + char *option; + char buf[32]; + + enum opte { + RO_OPTION, + RW_OPTION, + READ_SIZE_OPTION, + WRITE_SIZE_OPTION, + EMBEDDED_EQ_OPTION, + }; + + static const char *const key_list[] = { + [RO_OPTION] = "ro", + [RW_OPTION] = "rw", + [READ_SIZE_OPTION] = "rsize", + [WRITE_SIZE_OPTION] = "wsize", + [EMBEDDED_EQ_OPTION] = "equal", + NULL, + }; + + static const char *const empty_key_list[] = { + NULL, + }; + + /* degenerate cases */ + zexpect_equal(-1, getsubopt(NULL, NULL, NULL)); + zexpect_equal(-1, getsubopt(NULL, NULL, &value)); + zexpect_equal(-1, getsubopt(NULL, (char **)key_list, NULL)); + zexpect_equal(-1, getsubopt(NULL, (char **)key_list, &value)); + zexpect_equal(-1, getsubopt(&option, NULL, NULL)); + zexpect_equal(-1, getsubopt(&option, NULL, &value)); + + /* iterate over valuep being NULL and valid */ + for (size_t j = 0; j < 2; ++j) { + char **valuep = (j == 0) ? NULL : &value; + + /* empty options string */ + memset(buf, 0, sizeof(buf)); + option = buf; + value = (char *)0x4242; + zexpect_equal(-1, getsubopt(&option, (char **)key_list, valuep)); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + /* empty key list */ + strcpy(buf, "ro,rsize=512,equal=1=2,rw"); + option = buf; + value = (char *)0x4242; + zexpect_equal(-1, getsubopt(&option, (char **)empty_key_list, valuep)); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + strcpy(buf, "ro,rsize=512,equal=1=2,rw"); + option = buf; + value = (char *)0x4242; + zexpect_equal(RO_OPTION, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen("ro,")]); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + value = (char *)0x4242; + zexpect_equal(READ_SIZE_OPTION, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen("ro,rsize=512,")]); + if (valuep != NULL) { + zexpect_str_equal(value, "512"); + } + + value = (char *)0x4242; + zexpect_equal(EMBEDDED_EQ_OPTION, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen("ro,rsize=512,equal=1=2,")]); + if (valuep != NULL) { + zexpect_str_equal(value, "1=2"); + } + + value = (char *)0x4242; + zexpect_equal(RW_OPTION, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen("ro,rsize=512,equal=1=2,rw")]); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + value = (char *)0x4242; + zexpect_equal(getsubopt(&option, (char **)key_list, valuep), -1); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + strcpy(buf, "oops"); + option = buf; + value = (char *)0x4242; + zexpect_equal(getsubopt(&option, (char **)key_list, valuep), -1); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + /* some corner cases */ + strcpy(buf, ",rsize=,"); + option = buf; + value = (char *)0x4242; + zexpect_equal(-1, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen(",")]); + if (valuep != NULL) { + zexpect_equal(value, NULL); + } + + value = (char *)0x4242; + zexpect_equal(READ_SIZE_OPTION, getsubopt(&option, (char **)key_list, valuep)); + zexpect_equal(option, &buf[strlen(",rsize=,")]); + if (valuep != NULL) { + zexpect_str_equal(value, ""); + } + } +} diff --git a/tests/posix/single_process/prj.conf b/tests/posix/single_process/prj.conf index 7422432b9d0b..ceec42c12c04 100644 --- a/tests/posix/single_process/prj.conf +++ b/tests/posix/single_process/prj.conf @@ -1,4 +1,5 @@ CONFIG_ZTEST=y +CONFIG_POSIX_SYSTEM_INTERFACES=y CONFIG_POSIX_SINGLE_PROCESS=y # Let's explicitly choose PICOLIBC, so it is used if supported even if it would not have been the