Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions cmake/verify-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@
# FORMAT=json: Print the output as a json formatted string, useful for Python

# This is the minimum required Zephyr-SDK version which supports CMake package
if("${ARCH}" STREQUAL "arm64")
set(TOOLCHAIN_ZEPHYR_MINIMUM_REQUIRED_VERSION 0.12.4)
else()
set(TOOLCHAIN_ZEPHYR_MINIMUM_REQUIRED_VERSION 0.12)
endif()
set(TOOLCHAIN_ZEPHYR_MINIMUM_REQUIRED_VERSION 0.13)

# Set internal variables if set in environment.
if(NOT DEFINED ZEPHYR_TOOLCHAIN_VARIANT)
Expand Down
145 changes: 140 additions & 5 deletions lib/libc/newlib/libc-hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <arch/cpu.h>
#include <errno.h>
#include <stdio.h>
#include <malloc.h>
#include <sys/__assert.h>
#include <sys/stat.h>
#include <linker/linker-defs.h>
Expand Down Expand Up @@ -298,17 +299,151 @@ void *_sbrk(intptr_t count)
}
__weak FUNC_ALIAS(_sbrk, sbrk, void *);

static LIBC_DATA SYS_MUTEX_DEFINE(heap_mutex);
#ifdef CONFIG_MULTITHREADING
/*
* Newlib Retargetable Locking Interface Implementation
*
* When multithreading is enabled, the newlib retargetable locking interface is
* defined below to override the default void implementation and provide the
* Zephyr-side locks.
*
* NOTE: `k_mutex` and `k_sem` are used instead of `sys_mutex` and `sys_sem`
* because the latter do not support dynamic allocation for now.
*/

/* Static locks */
K_MUTEX_DEFINE(__lock___sinit_recursive_mutex);
K_MUTEX_DEFINE(__lock___sfp_recursive_mutex);
K_MUTEX_DEFINE(__lock___atexit_recursive_mutex);
K_MUTEX_DEFINE(__lock___malloc_recursive_mutex);
K_MUTEX_DEFINE(__lock___env_recursive_mutex);
K_SEM_DEFINE(__lock___at_quick_exit_mutex, 1, 1);
K_SEM_DEFINE(__lock___tz_mutex, 1, 1);
K_SEM_DEFINE(__lock___dd_hash_mutex, 1, 1);
K_SEM_DEFINE(__lock___arc4random_mutex, 1, 1);

#ifdef CONFIG_USERSPACE
/* Grant public access to all static locks after boot */
static int newlib_locks_prepare(const struct device *unused)
{
ARG_UNUSED(unused);

/* Initialise recursive locks */
k_object_access_all_grant(&__lock___sinit_recursive_mutex);
k_object_access_all_grant(&__lock___sfp_recursive_mutex);
k_object_access_all_grant(&__lock___atexit_recursive_mutex);
k_object_access_all_grant(&__lock___malloc_recursive_mutex);
k_object_access_all_grant(&__lock___env_recursive_mutex);

/* Initialise non-recursive locks */
k_object_access_all_grant(&__lock___at_quick_exit_mutex);
k_object_access_all_grant(&__lock___tz_mutex);
k_object_access_all_grant(&__lock___dd_hash_mutex);
k_object_access_all_grant(&__lock___arc4random_mutex);

return 0;
}

SYS_INIT(newlib_locks_prepare, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif /* CONFIG_USERSPACE */

/* Create a new dynamic non-recursive lock */
void __retarget_lock_init(_LOCK_T *lock)
{
__ASSERT_NO_MSG(lock != NULL);

/* Allocate semaphore object */
#ifndef CONFIG_USERSPACE
*lock = malloc(sizeof(struct k_sem));
#else
*lock = k_object_alloc(K_OBJ_SEM);
#endif /* !CONFIG_USERSPACE */
__ASSERT(*lock != NULL, "non-recursive lock allocation failed");

k_sem_init((struct k_sem *)*lock, 1, 1);
}

/* Create a new dynamic recursive lock */
void __retarget_lock_init_recursive(_LOCK_T *lock)
{
__ASSERT_NO_MSG(lock != NULL);

/* Allocate mutex object */
#ifndef CONFIG_USERSPACE
*lock = malloc(sizeof(struct k_mutex));
#else
*lock = k_object_alloc(K_OBJ_MUTEX);
#endif /* !CONFIG_USERSPACE */
__ASSERT(*lock != NULL, "recursive lock allocation failed");

k_mutex_init((struct k_mutex *)*lock);
}

/* Close dynamic non-recursive lock */
void __retarget_lock_close(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
#ifndef CONFIG_USERSPACE
free(lock);
#else
k_object_release(lock);
#endif /* !CONFIG_USERSPACE */
}

/* Close dynamic recursive lock */
void __retarget_lock_close_recursive(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
#ifndef CONFIG_USERSPACE
free(lock);
#else
k_object_release(lock);
#endif /* !CONFIG_USERSPACE */
}

/* Acquiure non-recursive lock */
void __retarget_lock_acquire(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
k_sem_take((struct k_sem *)lock, K_FOREVER);
}

/* Acquiure recursive lock */
void __retarget_lock_acquire_recursive(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
k_mutex_lock((struct k_mutex *)lock, K_FOREVER);
}

/* Try acquiring non-recursive lock */
int __retarget_lock_try_acquire(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
return !k_sem_take((struct k_sem *)lock, K_NO_WAIT);
}

/* Try acquiring recursive lock */
int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
{
__ASSERT_NO_MSG(lock != NULL);
return !k_mutex_lock((struct k_mutex *)lock, K_NO_WAIT);
}

void __malloc_lock(struct _reent *reent)
/* Release non-recursive lock */
void __retarget_lock_release(_LOCK_T lock)
{
sys_mutex_lock(&heap_mutex, K_FOREVER);
__ASSERT_NO_MSG(lock != NULL);
k_sem_give((struct k_sem *)lock);
}

void __malloc_unlock(struct _reent *reent)
/* Release recursive lock */
void __retarget_lock_release_recursive(_LOCK_T lock)
{
sys_mutex_unlock(&heap_mutex);
__ASSERT_NO_MSG(lock != NULL);
k_mutex_unlock((struct k_mutex *)lock);
}
#endif /* CONFIG_MULTITHREADING */

__weak int *__errno(void)
{
Expand Down
13 changes: 11 additions & 2 deletions tests/lib/newlib/thread_safety/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,14 @@ cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(newlib_thread_safety)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app PRIVATE src/main.c)

target_sources_ifdef(
CONFIG_NEWLIB_THREAD_SAFETY_TEST_LOCKS
app PRIVATE src/locks.c
)

target_sources_ifdef(
CONFIG_NEWLIB_THREAD_SAFETY_TEST_STRESS
app PRIVATE src/stress.c
)
11 changes: 11 additions & 0 deletions tests/lib/newlib/thread_safety/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2021 Stephanos Ioannidis <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config NEWLIB_THREAD_SAFETY_TEST_LOCKS
bool "Test: Locks"
default y

config NEWLIB_THREAD_SAFETY_TEST_STRESS
bool "Test: Stress"

source "Kconfig"
1 change: 1 addition & 0 deletions tests/lib/newlib/thread_safety/prj.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
CONFIG_ZTEST=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_NANO=n
CONFIG_TIMESLICE_SIZE=1
8 changes: 8 additions & 0 deletions tests/lib/newlib/thread_safety/prj_userspace.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CONFIG_ZTEST=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_NANO=n
CONFIG_TIMESLICE_SIZE=1

CONFIG_TEST_USERSPACE=y
CONFIG_MAX_THREAD_BYTES=10
CONFIG_HEAP_MEM_POOL_SIZE=2048
Loading