Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libc: common: add support for iso c11 threads #60759

Merged
merged 11 commits into from
Nov 14, 2023
2 changes: 1 addition & 1 deletion include/zephyr/posix/sys/stat.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct stat {
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
#if defined(__linux) && defined(__x86_64__)
__uint64_t __glibc_reserved[3];
uint64_t __glibc_reserved[3];
dkalowsk marked this conversation as resolved.
Show resolved Hide resolved
#endif
#else
#if defined(__rtems__)
Expand Down
9 changes: 9 additions & 0 deletions lib/libc/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_system_include_directories(include)

zephyr_library()
zephyr_library_property(ALLOW_EMPTY TRUE)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD
source/thrd/cnd.c
source/thrd/mtx.c
source/thrd/once.c
source/thrd/thrd.c
source/thrd/tss.c
)

# Prevent compiler from optimizing calloc into an infinite recursive call
zephyr_library_compile_options($<TARGET_PROPERTY:compiler,no_builtin_malloc>)
10 changes: 10 additions & 0 deletions lib/libc/common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,13 @@ config COMMON_LIBC_STRNLEN
bool
help
common implementation of strnlen().

config COMMON_LIBC_THRD
bool "C11 <threads.h> API support"
depends on DYNAMIC_THREAD
# Note: the POSIX_API dependency is only necessary until common elements
# of C11 threads and POSIX API can be abstracted out to a common library.
depends on POSIX_API
cfriedt marked this conversation as resolved.
Show resolved Hide resolved
default y
help
Common implementation of C11 <threads.h> API.
32 changes: 32 additions & 0 deletions lib/libc/common/include/machine/_threads.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_
#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_

#ifdef __cplusplus
extern "C" {
#endif

#define ONCE_FLAG_INIT \
{ \
1, 0 \
}

typedef int cnd_t;
typedef int mtx_t;
typedef int thrd_t;
typedef int tss_t;
typedef struct {
int is_initialized;
int init_executed;
} once_flag;

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ */
83 changes: 83 additions & 0 deletions lib/libc/common/include/threads.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_
#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_

#include <time.h>

#include <machine/_threads.h>
#include <zephyr/toolchain.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef int (*thrd_start_t)(void *arg);

enum {
thrd_success,
#define thrd_success thrd_success
thrd_nomem,
#define thrd_nomem thrd_nomem
thrd_timedout,
#define thrd_timedout thrd_timedout
thrd_busy,
#define thrd_busy thrd_busy
thrd_error,
#define thrd_error thrd_error
};

int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
int thrd_equal(thrd_t lhs, thrd_t rhs);
thrd_t thrd_current(void);
int thrd_sleep(const struct timespec *duration, struct timespec *remaining);
void thrd_yield(void);
_Noreturn void thrd_exit(int res);
int thrd_detach(thrd_t thr);
int thrd_join(thrd_t thr, int *res);

enum {
mtx_plain,
#define mtx_plain mtx_plain
mtx_timed,
#define mtx_timed mtx_timed
mtx_recursive,
#define mtx_recursive mtx_recursive
};

int mtx_init(mtx_t *mutex, int type);
void mtx_destroy(mtx_t *mutex);
int mtx_lock(mtx_t *mutex);
int mtx_timedlock(mtx_t *ZRESTRICT mutex, const struct timespec *ZRESTRICT time_point);

Check warning on line 55 in lib/libc/common/include/threads.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

FUNCTION_ARGUMENTS

lib/libc/common/include/threads.h:55 function definition argument 'int' should also have an identifier name
int mtx_trylock(mtx_t *mutex);
int mtx_unlock(mtx_t *mutex);

int cnd_init(cnd_t *cond);
int cnd_wait(cnd_t *cond, mtx_t *mtx);
int cnd_timedwait(cnd_t *ZRESTRICT cond, mtx_t *ZRESTRICT mtx, const struct timespec *ZRESTRICT ts);
int cnd_signal(cnd_t *cond);
int cnd_broadcast(cnd_t *cond);
void cnd_destroy(cnd_t *cond);

#ifndef thread_local
#define thread_local _Thread_local
#endif

typedef void (*tss_dtor_t)(void *val);

int tss_create(tss_t *key, tss_dtor_t destructor);
void *tss_get(tss_t key);
int tss_set(tss_t key, void *val);
void tss_delete(tss_t key);

void call_once(once_flag *flag, void (*func)(void));

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ */
71 changes: 71 additions & 0 deletions lib/libc/common/source/thrd/cnd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <threads.h>

#include <zephyr/posix/pthread.h>

int cnd_broadcast(cnd_t *cond)
{
switch (pthread_cond_broadcast(cond)) {
case 0:
return thrd_success;
default:
return thrd_error;
}
}

void cnd_destroy(cnd_t *cond)
{
(void)pthread_cond_destroy(cond);
}

int cnd_init(cnd_t *cond)
{
switch (pthread_cond_init(cond, NULL)) {
case 0:
return thrd_success;
case ENOMEM:
return thrd_nomem;
default:
return thrd_error;
}
}

int cnd_signal(cnd_t *cond)
{
switch (pthread_cond_signal(cond)) {
case 0:
return thrd_success;
case ENOMEM:
return thrd_nomem;
default:
return thrd_error;
}
}

int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts)
{
switch (pthread_cond_timedwait(cond, mtx, ts)) {
case 0:
return thrd_success;
case ETIMEDOUT:
return thrd_timedout;
default:
return thrd_error;
}
}

int cnd_wait(cnd_t *cond, mtx_t *mtx)
{
switch (pthread_cond_wait(cond, mtx)) {
case 0:
return thrd_success;
default:
return thrd_error;
}
}
99 changes: 99 additions & 0 deletions lib/libc/common/source/thrd/mtx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <threads.h>

#include <zephyr/kernel.h>
#include <zephyr/posix/pthread.h>

int mtx_init(mtx_t *mutex, int type)
{
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_t *attrp = NULL;

switch (type) {
case mtx_plain:
case mtx_timed:
break;
case mtx_plain | mtx_recursive:
case mtx_timed | mtx_recursive:
attrp = &attr;
ret = pthread_mutexattr_init(attrp);
__ASSERT_NO_MSG(ret == 0);

ret = pthread_mutexattr_settype(attrp, PTHREAD_MUTEX_RECURSIVE);
__ASSERT_NO_MSG(ret == 0);
break;
default:
return thrd_error;
}

switch (pthread_mutex_init(mutex, attrp)) {
cfriedt marked this conversation as resolved.
Show resolved Hide resolved
case 0:
ret = thrd_success;
break;
default:
ret = thrd_error;
break;
}

if (attrp != NULL) {
(void)pthread_mutexattr_destroy(attrp);
}

return ret;
}

void mtx_destroy(mtx_t *mutex)
{
(void)pthread_mutex_destroy(mutex);
}

int mtx_lock(mtx_t *mutex)
{
switch (pthread_mutex_lock(mutex)) {
case 0:
return thrd_success;
default:
return thrd_error;
}
}

int mtx_timedlock(mtx_t *restrict mutex, const struct timespec *restrict time_point)
{
switch (pthread_mutex_timedlock(mutex, time_point)) {
case 0:
return thrd_success;
case ETIMEDOUT:
return thrd_timedout;
default:
return thrd_error;
}
}

int mtx_trylock(mtx_t *mutex)
{
switch (pthread_mutex_trylock(mutex)) {
case 0:
return thrd_success;
case EBUSY:
return thrd_busy;
default:
return thrd_error;
}
}

int mtx_unlock(mtx_t *mutex)
{
switch (pthread_mutex_unlock(mutex)) {
case 0:
return thrd_success;
default:
return thrd_error;
}
}
16 changes: 16 additions & 0 deletions lib/libc/common/source/thrd/once.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <threads.h>

#include <zephyr/kernel.h>
#include <zephyr/posix/pthread.h>

void call_once(once_flag *flag, void (*func)(void))
{
(void)pthread_once((pthread_once_t *)flag, func);
}
Loading
Loading