From 87729baabee1f477bdc15555c99559374a98f9d5 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 13 Jun 2024 18:43:28 +0800 Subject: [PATCH 1/3] posix: implement file locking functions Implement file locking functions and added testcase. Signed-off-by: Yong Cong Sin --- .../portability/posix/option_groups/index.rst | 12 +- lib/libc/Kconfig | 1 + lib/libc/minimal/include/stdio.h | 6 + lib/os/fdtable.c | 29 +++++ lib/posix/options/CMakeLists.txt | 1 + lib/posix/options/Kconfig | 1 + lib/posix/options/Kconfig.file_locking | 38 ++++++ lib/posix/options/Kconfig.pthread | 1 + lib/posix/options/file_locking.c | 37 ++++++ tests/posix/common/src/file_locking.c | 116 ++++++++++++++++++ 10 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 lib/posix/options/Kconfig.file_locking create mode 100644 lib/posix/options/file_locking.c create mode 100644 tests/posix/common/src/file_locking.c diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index e67523ae3d7c5..47127adb042d8 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -564,9 +564,9 @@ This table lists service support status in Zephyr for `POSIX_FD_MGMT`: :header: API, Supported :widths: 50,10 - flockfile(), - ftrylockfile(), - funlockfile(), + flockfile(), yes + ftrylockfile(), yes + funlockfile(), yes getc_unlocked(), getchar_unlocked(), putc_unlocked(), @@ -901,9 +901,9 @@ _POSIX_THREAD_SAFE_FUNCTIONS asctime_r(), ctime_r(), - flockfile(), - ftrylockfile(), - funlockfile(), + flockfile(), yes + ftrylockfile(), yes + funlockfile(), yes getc_unlocked(), getchar_unlocked(), getgrgid_r(), diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 6607f62c521f0..8794c8a898bc8 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -75,6 +75,7 @@ config MINIMAL_LIBC imply COMMON_LIBC_MALLOC imply COMMON_LIBC_CALLOC imply COMMON_LIBC_REALLOCARRAY + select POSIX_FILE_LOCKING if POSIX_THREAD_SAFE_FUNCTIONS help Build with minimal C library. diff --git a/lib/libc/minimal/include/stdio.h b/lib/libc/minimal/include/stdio.h index db3c89790c42a..995bf255ece8f 100644 --- a/lib/libc/minimal/include/stdio.h +++ b/lib/libc/minimal/include/stdio.h @@ -63,6 +63,12 @@ size_t fwrite(const void *ZRESTRICT ptr, size_t size, size_t nitems, #define putc(c, stream) fputc(c, stream) #define putchar(c) putc(c, stdout) +#if defined(CONFIG_POSIX_FILE_LOCKING) || defined(__DOXYGEN__) +void flockfile(FILE *file); +int ftrylockfile(FILE *file); +void funlockfile(FILE *file); +#endif /* CONFIG_POSIX_FILE_LOCKING || __DOXYGEN__ */ + #ifdef __cplusplus } #endif diff --git a/lib/os/fdtable.c b/lib/os/fdtable.c index 534e212aa6465..b4536370ddafe 100644 --- a/lib/os/fdtable.c +++ b/lib/os/fdtable.c @@ -392,6 +392,35 @@ int zvfs_fsync(int fd) return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC); } +#if defined(CONFIG_POSIX_FILE_LOCKING) +void zvfs_flockfile(int fd) +{ + if (_check_fd(fd) < 0) { + return; + } + + (void)k_mutex_lock(&fdtable[fd].lock, K_FOREVER); +} + +int zvfs_ftrylockfile(int fd) +{ + if (_check_fd(fd) < 0) { + return -1; + } + + return k_mutex_lock(&fdtable[fd].lock, K_NO_WAIT); +} + +void zvfs_funlockfile(int fd) +{ + if (_check_fd(fd) < 0) { + return; + } + + (void)k_mutex_unlock(&fdtable[fd].lock); +} +#endif /* CONFIG_POSIX_FILE_LOCKING */ + static inline off_t zvfs_lseek_wrap(int fd, int cmd, ...) { off_t res; diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index f7da027223d4d..6fddb9ed8ec7d 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -55,6 +55,7 @@ zephyr_library_sources_ifdef(CONFIG_POSIX_MEMLOCK mlockall.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MEMLOCK_RANGE mlock.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MEMORY_PROTECTION mprotect.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MAPPED_FILES mmap.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_FILE_LOCKING file_locking.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MESSAGE_PASSING mqueue.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MULTI_PROCESS sleep.c diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index bdf0ed4901f05..07b76410a03c6 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -13,6 +13,7 @@ rsource "Kconfig.barrier" rsource "Kconfig.c_lib_ext" rsource "Kconfig.device_io" rsource "Kconfig.fd_mgmt" +rsource "Kconfig.file_locking" rsource "Kconfig.fs" rsource "Kconfig.mem" rsource "Kconfig.mqueue" diff --git a/lib/posix/options/Kconfig.file_locking b/lib/posix/options/Kconfig.file_locking new file mode 100644 index 0000000000000..7a731a592ce6b --- /dev/null +++ b/lib/posix/options/Kconfig.file_locking @@ -0,0 +1,38 @@ +# Copyright (c) 2024 Meta Platforms +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_FILE_LOCKING + bool "POSIX file locking [EXPERIMENTAL]" + select EXPERIMENTAL + select FDTABLE + help + Select 'y' here and Zephyr will provide implementations for the POSIX_FILE_LOCKING Option + Group. + This includes support for flockfile(), ftrylockfile(), funlockfile(), getc_unlocked(), + getchar_unlocked(), putc_unlocked() and putchar_unlocked(). + + For more information, please see + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html + +if POSIX_FILE_LOCKING + +# These options are intended to be used for compatibility with external POSIX +# implementations such as those in Newlib or Picolibc. + +config POSIX_FD_MGMT_ALIAS_FLOCKFILE + bool + help + Select 'y' here and Zephyr will provide an alias for flockfile() as _flockfile(). + +config POSIX_FD_MGMT_ALIAS_FTRYLOCKFILE + bool + help + Select 'y' here and Zephyr will provide an alias for ftrylockfile() as _ftrylockfile(). + +config POSIX_FD_MGMT_ALIAS_FUNLOCKFILE + bool + help + Select 'y' here and Zephyr will provide an alias for funlockfile() as _funlockfile(). + +endif # POSIX_FILE_LOCKING diff --git a/lib/posix/options/Kconfig.pthread b/lib/posix/options/Kconfig.pthread index ec38286ff49a3..c779d2f2c8ac9 100644 --- a/lib/posix/options/Kconfig.pthread +++ b/lib/posix/options/Kconfig.pthread @@ -156,6 +156,7 @@ config POSIX_THREAD_PRIO_PROTECT config POSIX_THREAD_SAFE_FUNCTIONS bool "POSIX thread-safe functions" + select POSIX_FILE_LOCKING help Select 'y' here to enable POSIX thread-safe functions including asctime_r(), ctime_r(), flockfile(), ftrylockfile(), funlockfile(), getc_unlocked(), getchar_unlocked(), diff --git a/lib/posix/options/file_locking.c b/lib/posix/options/file_locking.c new file mode 100644 index 0000000000000..755d1194828b5 --- /dev/null +++ b/lib/posix/options/file_locking.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +void zvfs_flockfile(int fd); +int zvfs_ftrylockfile(int fd); +void zvfs_funlockfile(int fd); + +void flockfile(FILE *file) +{ + zvfs_flockfile(POINTER_TO_INT(file)); +} +#ifdef CONFIG_POSIX_FD_MGMT_ALIAS_FLOCKFILE +FUNC_ALIAS(flockfile, _flockfile, void); +#endif /* CONFIG_POSIX_FD_MGMT_ALIAS_FLOCKFILE */ + +int ftrylockfile(FILE *file) +{ + return zvfs_ftrylockfile(POINTER_TO_INT(file)); +} +#ifdef CONFIG_POSIX_FD_MGMT_ALIAS_FTRYLOCKFILE +FUNC_ALIAS(ftrylockfile, _ftrylockfile, int); +#endif /* CONFIG_POSIX_FD_MGMT_ALIAS_FTRYLOCKFILE */ + +void funlockfile(FILE *file) +{ + zvfs_funlockfile(POINTER_TO_INT(file)); +} +#ifdef CONFIG_POSIX_FD_MGMT_ALIAS_FUNLOCKFILE +FUNC_ALIAS(funlockfile, _funlockfile, void); +#endif /* CONFIG_POSIX_FD_MGMT_ALIAS_FUNLOCKFILE */ diff --git a/tests/posix/common/src/file_locking.c b/tests/posix/common/src/file_locking.c new file mode 100644 index 0000000000000..ade9ecf908471 --- /dev/null +++ b/tests/posix/common/src/file_locking.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024, Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#ifndef CONFIG_PICOLIBC + +K_THREAD_STACK_DEFINE(test_stack, 1024); + +#define LOCK_SHOULD_PASS (void *)true +#define LOCK_SHOULD_FAIL (void *)false +#define UNLOCK_FILE (void *)true +#define NO_UNLOCK_FILE (void *)false + +void ftrylockfile_thread(void *p1, void *p2, void *p3) +{ + int ret; + FILE *file = p1; + bool success = (bool)p2; + bool unlock = (bool)p3; + + if (success) { + ret = ftrylockfile(file); + zassert_ok(ret, "Expected ftrylockfile to succeed but it failed: %d", ret); + if (unlock) { + funlockfile(file); + } + } else { + zassert_not_ok(ftrylockfile(file), + "Expected ftrylockfile to failed but it succeeded"); + } +} + +void flockfile_thread(void *p1, void *p2, void *p3) +{ + FILE *file = p1; + bool success = (bool)p2; + bool unlock = (bool)p3; + + flockfile(file); + + if (!success) { + /* Shouldn't be here if it supposed to fail */ + ztest_test_fail(); + } + + if (unlock) { + funlockfile(file); + } +} + +ZTEST(file_locking, test_file_locking) +{ + FILE *file = INT_TO_POINTER(z_alloc_fd(NULL, NULL)); + int priority = k_thread_priority_get(k_current_get()); + struct k_thread test_thread; + + /* Lock 5 times with flockfile */ + for (int i = 0; i < 5; i++) { + flockfile(file); + } + + /* Lock 5 times with ftrylockfile */ + for (int i = 0; i < 5; i++) { + zassert_ok(ftrylockfile(file)); + } + + /* Spawn a thread that uses ftrylockfile(), it should fail immediately */ + k_thread_create(&test_thread, test_stack, K_THREAD_STACK_SIZEOF(test_stack), + ftrylockfile_thread, file, LOCK_SHOULD_FAIL, NO_UNLOCK_FILE, priority, 0, + K_NO_WAIT); + /* The thread should terminate immediately */ + zassert_ok(k_thread_join(&test_thread, K_MSEC(100))); + + /* Try agian with flockfile(), it should block forever */ + k_thread_create(&test_thread, test_stack, K_THREAD_STACK_SIZEOF(test_stack), + flockfile_thread, file, LOCK_SHOULD_FAIL, NO_UNLOCK_FILE, priority, 0, + K_NO_WAIT); + /* We expect the flockfile() call to block forever, so this will timeout */ + zassert_equal(k_thread_join(&test_thread, K_MSEC(500)), -EAGAIN); + /* Abort the test thread */ + k_thread_abort(&test_thread); + + /* Unlock the file completely in this thread */ + for (int i = 0; i < 10; i++) { + funlockfile(file); + } + + /* Spawn the thread again, which should be able to lock the file now with ftrylockfile() */ + k_thread_create(&test_thread, test_stack, K_THREAD_STACK_SIZEOF(test_stack), + ftrylockfile_thread, file, LOCK_SHOULD_PASS, UNLOCK_FILE, priority, 0, + K_NO_WAIT); + zassert_ok(k_thread_join(&test_thread, K_MSEC(100))); + + z_free_fd(POINTER_TO_INT(file)); +} + +#else +/** + * PicoLIBC doesn't support these functions in its header + * Skip the tests for now. + */ +ZTEST(file_locking, test_file_locking) +{ + ztest_test_skip(); +} +#endif /* CONFIG_PICOLIBC */ + +ZTEST_SUITE(file_locking, NULL, NULL, NULL, NULL, NULL); From 778629e24775ffa415c5122db5c16af939b9a71b Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 14 Jun 2024 19:55:55 +0800 Subject: [PATCH 2/3] libc: minimal: implement putc_unlocked & putchar_unlocked Add a simple implementation for putc_unlocked() & putchar_unlocked(). Signed-off-by: Yong Cong Sin --- .../portability/posix/option_groups/index.rst | 4 +- lib/libc/Kconfig | 2 + lib/libc/common/CMakeLists.txt | 2 + lib/libc/common/Kconfig | 2 + lib/libc/common/source/CMakeLists.txt | 4 ++ lib/libc/common/source/Kconfig | 4 ++ lib/libc/common/source/stdio/CMakeLists.txt | 5 +++ lib/libc/common/source/stdio/Kconfig | 19 ++++++++ lib/libc/common/source/stdio/getc_unlocked.c | 24 +++++++++++ lib/libc/common/source/stdio/putc_unlocked.c | 19 ++++++++ lib/libc/minimal/include/stdio.h | 5 +++ lib/posix/options/file_locking.c | 1 + tests/posix/common/src/file_locking.c | 43 +++++++++++++++++++ 13 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 lib/libc/common/source/CMakeLists.txt create mode 100644 lib/libc/common/source/Kconfig create mode 100644 lib/libc/common/source/stdio/CMakeLists.txt create mode 100644 lib/libc/common/source/stdio/Kconfig create mode 100644 lib/libc/common/source/stdio/getc_unlocked.c create mode 100644 lib/libc/common/source/stdio/putc_unlocked.c diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 47127adb042d8..8c5d846b01d9b 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -569,8 +569,8 @@ This table lists service support status in Zephyr for `POSIX_FD_MGMT`: funlockfile(), yes getc_unlocked(), getchar_unlocked(), - putc_unlocked(), - putchar_unlocked(), + putc_unlocked(), yes + putchar_unlocked(), yes .. _posix_option_group_memory_protection: diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 8794c8a898bc8..94d7bc14e7cd7 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -76,6 +76,8 @@ config MINIMAL_LIBC imply COMMON_LIBC_CALLOC imply COMMON_LIBC_REALLOCARRAY select POSIX_FILE_LOCKING if POSIX_THREAD_SAFE_FUNCTIONS + select COMMON_LIBC_PUTC_UNLOCKED if POSIX_THREAD_SAFE_FUNCTIONS + select COMMON_LIBC_GETC_UNLOCKED if POSIX_THREAD_SAFE_FUNCTIONS help Build with minimal C library. diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 64fe33d1c4ad3..1a822a96d6c27 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -17,5 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD source/thrd/tss.c ) +add_subdirectory(source) + # Prevent compiler from optimizing calloc into an infinite recursive call zephyr_library_compile_options($) diff --git a/lib/libc/common/Kconfig b/lib/libc/common/Kconfig index ea0d6869435c4..2538769994190 100644 --- a/lib/libc/common/Kconfig +++ b/lib/libc/common/Kconfig @@ -82,3 +82,5 @@ config COMMON_LIBC_THRD default y help Common implementation of C11 API. + +rsource "source/Kconfig" diff --git a/lib/libc/common/source/CMakeLists.txt b/lib/libc/common/source/CMakeLists.txt new file mode 100644 index 0000000000000..d80868a73ee2e --- /dev/null +++ b/lib/libc/common/source/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_COMMON_LIBC_STDIO stdio) diff --git a/lib/libc/common/source/Kconfig b/lib/libc/common/source/Kconfig new file mode 100644 index 0000000000000..4bc4ea4d18518 --- /dev/null +++ b/lib/libc/common/source/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +rsource "stdio/Kconfig" diff --git a/lib/libc/common/source/stdio/CMakeLists.txt b/lib/libc/common/source/stdio/CMakeLists.txt new file mode 100644 index 0000000000000..922c590e81a58 --- /dev/null +++ b/lib/libc/common/source/stdio/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_GETC_UNLOCKED getc_unlocked.c) +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_PUTC_UNLOCKED putc_unlocked.c) diff --git a/lib/libc/common/source/stdio/Kconfig b/lib/libc/common/source/stdio/Kconfig new file mode 100644 index 0000000000000..fe21143e91225 --- /dev/null +++ b/lib/libc/common/source/stdio/Kconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +config COMMON_LIBC_STDIO + bool + help + common function implementation in stdio.h + +config COMMON_LIBC_GETC_UNLOCKED + bool + select COMMON_LIBC_STDIO + help + common implementation of getc_unlocked() & getchar_unlocked(). + +config COMMON_LIBC_PUTC_UNLOCKED + bool + select COMMON_LIBC_STDIO + help + common implementation of putc_unlocked() & putchar_unlocked(). diff --git a/lib/libc/common/source/stdio/getc_unlocked.c b/lib/libc/common/source/stdio/getc_unlocked.c new file mode 100644 index 0000000000000..94d97e70102ed --- /dev/null +++ b/lib/libc/common/source/stdio/getc_unlocked.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int getc_unlocked(FILE *stream) +{ + ARG_UNUSED(stream); + + errno = ENOSYS; + + return EOF; +} + +int getchar_unlocked(void) +{ + return getc_unlocked(stdin); +} diff --git a/lib/libc/common/source/stdio/putc_unlocked.c b/lib/libc/common/source/stdio/putc_unlocked.c new file mode 100644 index 0000000000000..5bd6ecf6cd446 --- /dev/null +++ b/lib/libc/common/source/stdio/putc_unlocked.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +int putc_unlocked(int c, FILE *stream) +{ + return zephyr_fputc(c, stream); +} + +int putchar_unlocked(int c) +{ + return putc_unlocked(c, stdout); +} diff --git a/lib/libc/minimal/include/stdio.h b/lib/libc/minimal/include/stdio.h index 995bf255ece8f..e179b7c9a71e6 100644 --- a/lib/libc/minimal/include/stdio.h +++ b/lib/libc/minimal/include/stdio.h @@ -63,6 +63,11 @@ size_t fwrite(const void *ZRESTRICT ptr, size_t size, size_t nitems, #define putc(c, stream) fputc(c, stream) #define putchar(c) putc(c, stdout) +#if defined(CONFIG_COMMON_LIBC_PUTC_UNLOCKED) || defined(__DOXYGEN__) +int putc_unlocked(int c, FILE *stream); +int putchar_unlocked(int c); +#endif /* CONFIG_COMMON_LIBC_PUTC_UNLOCKED || __DOXYGEN__ */ + #if defined(CONFIG_POSIX_FILE_LOCKING) || defined(__DOXYGEN__) void flockfile(FILE *file); int ftrylockfile(FILE *file); diff --git a/lib/posix/options/file_locking.c b/lib/posix/options/file_locking.c index 755d1194828b5..9493f2c7330a9 100644 --- a/lib/posix/options/file_locking.c +++ b/lib/posix/options/file_locking.c @@ -6,6 +6,7 @@ #include +#include #include void zvfs_flockfile(int fd); diff --git a/tests/posix/common/src/file_locking.c b/tests/posix/common/src/file_locking.c index ade9ecf908471..2c6d06f99685f 100644 --- a/tests/posix/common/src/file_locking.c +++ b/tests/posix/common/src/file_locking.c @@ -102,6 +102,49 @@ ZTEST(file_locking, test_file_locking) z_free_fd(POINTER_TO_INT(file)); } +void put_thread(void *p1, void *p2, void *p3) +{ + FILE *file = p1; + + /* Lock held in main thread */ + zassert_not_ok(ftrylockfile(file)); + + /* Wait for the lock */ + flockfile(file); + zassert_equal(putc_unlocked('S', file), 'S'); + zassert_equal(putchar('T'), 'T'); + funlockfile(file); +} + +ZTEST(file_locking, test_stdio) +{ + FILE *file = INT_TO_POINTER(z_alloc_fd(NULL, NULL)); + struct k_thread test_thread; + int priority = k_thread_priority_get(k_current_get()); + + /* Lock the file before creating the test thread */ + flockfile(file); + + k_thread_create(&test_thread, test_stack, K_THREAD_STACK_SIZEOF(test_stack), + put_thread, file, INT_TO_POINTER(true), NULL, priority, 0, + K_NO_WAIT); + + /* Allow the test thread to run */ + k_msleep(100); + /* The test thread should be waiting for the lock */ + zassert_equal(k_thread_join(&test_thread, K_MSEC(10)), -EAGAIN); + + /* Main thread has the lock, either version should work */ + zassert_equal(putc('T', file), 'T'); + zassert_equal(putchar_unlocked('E'), 'E'); + + /* We are done with the file here, unlock it so that test thread can run */ + funlockfile(file); + zassert_equal(k_thread_join(&test_thread, K_MSEC(100)), 0); + + z_free_fd(POINTER_TO_INT(file)); +} + #else /** * PicoLIBC doesn't support these functions in its header From a206ee6a916238a344580ef87daf88866a715a55 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 18 Jun 2024 16:04:04 +0800 Subject: [PATCH 3/3] libc: minimal: stubs getc_unlocked & getchar_unlocked Add stub implementation and test for `getc_unlocked()` & `getchar_unlocked()`. Signed-off-by: Yong Cong Sin --- .../portability/posix/option_groups/index.rst | 8 ++++---- lib/libc/minimal/include/stdio.h | 5 +++++ lib/posix/options/file_locking.c | 1 + tests/posix/common/src/file_locking.c | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 8c5d846b01d9b..6af6625d594e1 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -567,8 +567,8 @@ This table lists service support status in Zephyr for `POSIX_FD_MGMT`: flockfile(), yes ftrylockfile(), yes funlockfile(), yes - getc_unlocked(), - getchar_unlocked(), + getc_unlocked(), yes :ref:`†` + getchar_unlocked(), yes :ref:`†` putc_unlocked(), yes putchar_unlocked(), yes @@ -904,8 +904,8 @@ _POSIX_THREAD_SAFE_FUNCTIONS flockfile(), yes ftrylockfile(), yes funlockfile(), yes - getc_unlocked(), - getchar_unlocked(), + getc_unlocked(), yes :ref:`†` + getchar_unlocked(), yes :ref:`†` getgrgid_r(), getgrnam_r(), getpwnam_r(), diff --git a/lib/libc/minimal/include/stdio.h b/lib/libc/minimal/include/stdio.h index e179b7c9a71e6..75767738af9e2 100644 --- a/lib/libc/minimal/include/stdio.h +++ b/lib/libc/minimal/include/stdio.h @@ -68,6 +68,11 @@ int putc_unlocked(int c, FILE *stream); int putchar_unlocked(int c); #endif /* CONFIG_COMMON_LIBC_PUTC_UNLOCKED || __DOXYGEN__ */ +#if defined(CONFIG_COMMON_LIBC_GETC_UNLOCKED) || defined(__DOXYGEN__) +int getc_unlocked(FILE *stream); +int getchar_unlocked(void); +#endif /* CONFIG_COMMON_LIBC_GETC_UNLOCKED || __DOXYGEN__ */ + #if defined(CONFIG_POSIX_FILE_LOCKING) || defined(__DOXYGEN__) void flockfile(FILE *file); int ftrylockfile(FILE *file); diff --git a/lib/posix/options/file_locking.c b/lib/posix/options/file_locking.c index 9493f2c7330a9..27a0e0fff5cea 100644 --- a/lib/posix/options/file_locking.c +++ b/lib/posix/options/file_locking.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include diff --git a/tests/posix/common/src/file_locking.c b/tests/posix/common/src/file_locking.c index 2c6d06f99685f..c0b24025a9255 100644 --- a/tests/posix/common/src/file_locking.c +++ b/tests/posix/common/src/file_locking.c @@ -145,6 +145,24 @@ ZTEST(file_locking, test_stdio) z_free_fd(POINTER_TO_INT(file)); } +/** + * @brief Existence test for the stubs + */ +ZTEST(file_locking, test_stubs) +{ +#ifndef CONFIG_NEWLIB_LIBC + errno = 0; + zassert_equal(getchar_unlocked(), EOF); + zassert_equal(errno, ENOSYS); + + errno = 0; + zassert_equal(getc_unlocked(stdin), EOF); + zassert_equal(errno, ENOSYS); +#else + ztest_test_skip(); +#endif /* !CONFIG_NEWLIB_LIBC */ +} + #else /** * PicoLIBC doesn't support these functions in its header