1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys/malloc_thread_safe: split out of cpu/atmega_common

Split out Gunar Schorcht's clever approach to provide thread safe malloc for
AVR into a system module and make AVR depend on this. This allows other
platforms to also use this.
This commit is contained in:
Marian Buschsieweke 2020-12-10 09:39:44 +01:00
parent c9d63c9f4f
commit 902aa29b62
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
10 changed files with 112 additions and 44 deletions

View File

@ -7,6 +7,11 @@ USEMODULE += atmega_common
# peripheral drivers are linked into the final binary
USEMODULE += atmega_common_periph
# The AVR-libc provides no thread safe malloc implementation and has no hooks
# to inject. Use malloc_thread_safe to link calls to malloc to safe wrappers
# instead.
USEMODULE += malloc_thread_safe
# the atmel port uses stdio_uart by default
ifeq (,$(filter stdio_% slipdev_stdio,$(USEMODULE)))
USEMODULE += stdio_uart

View File

@ -177,45 +177,4 @@ ssize_t write(int fd, const void *src, size_t count)
#endif
}
/*
* Following functions are wrappers around the according avr-libc system
* functions to avoid their preemption by disabling the interrupts for the
* time of their execution.
*/
extern void *__real_malloc(size_t size);
extern void __real_free(void *ptr);
extern void *__real_calloc(size_t nmemb, size_t size);
extern void *__real_realloc(void *ptr, size_t size);
void *__wrap_malloc(size_t size)
{
unsigned state = irq_disable();
void *ptr = __real_malloc(size);
irq_restore(state);
return ptr;
}
void __wrap_free(void *ptr)
{
unsigned state = irq_disable();
__real_free(ptr);
irq_restore(state);
}
void *__wrap_calloc(size_t nmemb, size_t size)
{
unsigned state = irq_disable();
void *ptr = __real_calloc(nmemb, size);
irq_restore(state);
return ptr;
}
void *__wrap_realloc(void *ptr, size_t size)
{
unsigned state = irq_disable();
void *new = __real_realloc(ptr, size);
irq_restore(state);
return new;
}
/** @} */

View File

@ -23,9 +23,6 @@ LDSCRIPT_COMPAT = $(if $(shell $(TARGET_ARCH)-ld --verbose | grep __TEXT_REGION_
-T$(RIOTCPU)/$(CPU)/ldscripts_compat/avr_2.26.ld)
LINKFLAGS += $(LDSCRIPT_COMPAT)
# use the wrapper functions for following avr-libc functions
LINKFLAGS += -Wl,-wrap=malloc -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=free
ifeq ($(LTO),1)
# avr-gcc <4.8.3 has a bug when using LTO which causes a warning to be printed always:
# '_vector_25' appears to be a misspelled signal handler [enabled by default]

View File

@ -17,6 +17,7 @@ rsource "entropy_source/Kconfig"
rsource "event/Kconfig"
rsource "fmt/Kconfig"
rsource "isrpipe/Kconfig"
rsource "malloc_thread_safe/Kconfig"
rsource "net/Kconfig"
rsource "Kconfig.newlib"
rsource "Kconfig.stdio"

View File

@ -21,6 +21,10 @@ ifneq (,$(filter gnrc_pktbuf,$(USEMODULE)))
include $(RIOTBASE)/sys/net/gnrc/pktbuf/Makefile.include
endif
ifneq (,$(filter malloc_thread_safe,$(USEMODULE)))
include $(RIOTBASE)/sys/malloc_thread_safe/Makefile.include
endif
ifneq (,$(filter posix_headers,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include
endif

View File

@ -0,0 +1,18 @@
# Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_MALLOC_THREAD_SAFE
bool
depends on TEST_KCONFIG
help
This module provides wrappers for malloc(), calloc(), realloc(), and
free() which guarantee mutually exclusive access to heap data
structures. This linker is also instructed to redirect all calls to
the corresponding wrappers. As a result, all allocations become thread
safe without touching the application code or the c library. This module
is intended to be pulled in automatically if needed. Hence, applications
never should manually use it.

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,2 @@
# use the wrapper functions for malloc and friends to provide thread-safety
LINKFLAGS += -Wl,-wrap=malloc -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=free

View File

@ -0,0 +1,26 @@
/**
@defgroup sys_malloc_ts Thread-safe wrappers for malloc and friends
@ingroup sys
@brief This module provides wrappers for malloc, calloc, realloc and free
that provide mutually exclusive access to those functions.
@warning This module is automatically selected, if needed. Never add it
manually.
# Background
Without support of the OS (or resorting to disabling IRQs), the standard C
library is unable to guarantee that at most one thread at a time accesses the
heap management data structures. Some C libraries provide hooks for locking
(e.g. picolibc and newlib do so optionally), others (e.g. AVR libc) don't.
By providing wrapper functions for `malloc()` and friends and instructing the
linker to link to those instead of their actual implementations, we can provide
thread safe access to the heap regardless of C libraries support.
# Usage
This module is intended to be use by platforms not providing the required
locking with other means automatically. Hence, application developers and users
should never select this module by hand.
*/

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @brief Implements various POSIX syscalls
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#include "irq.h"
extern void *__real_malloc(size_t size);
extern void __real_free(void *ptr);
extern void *__real_calloc(size_t nmemb, size_t size);
extern void *__real_realloc(void *ptr, size_t size);
void *__wrap_malloc(size_t size)
{
unsigned state = irq_disable();
void *ptr = __real_malloc(size);
irq_restore(state);
return ptr;
}
void __wrap_free(void *ptr)
{
unsigned state = irq_disable();
__real_free(ptr);
irq_restore(state);
}
void *__wrap_calloc(size_t nmemb, size_t size)
{
unsigned state = irq_disable();
void *ptr = __real_calloc(nmemb, size);
irq_restore(state);
return ptr;
}
void *__wrap_realloc(void *ptr, size_t size)
{
unsigned state = irq_disable();
void *new = __real_realloc(ptr, size);
irq_restore(state);
return new;
}
/** @} */