Skip to content

Commit d21cd79

Browse files
committed
pkg/tlsf: Fix the way system functions are overriden.
The correct way to overrride the malloc family of functions in newlib-nano is to provide the *_r (reentrant) variants. Newlib implements the "normal" functions on top of these (see the newlib source code). Also, internally it calls the *_r functions when allocating buffers. If only the "normal" non-reentrant functions are provided this will mean that some of the code will still use the vanilla newlib allocator. Furthermore, if one uses the whole heap as a pool for TLSF then the system may in the best case crash as there is no enough memory for its internall allocations or in the worst case function eratically (this depends on how the heap reserved, there is an upcomming series of commits in that direction). This commit splits the handling between newlib and native. It also prepares the ground for future work on the pool initialization. Right now I could only test this in ARM and native and I cannot ensure it will work on other platforms. Replacing the system's memory allocator is not something that can be taken lightly and will inevitably require diving into the depths of the libc. Therefore I would say that using TLSF as a system wide allocator is ATM supported officially only on those plaftorms. Testing: Aside from reading the newlib sources, you can see the issue in a live system using the debugger. Compile any example (with or without tlsf-malloc), grab a debugger and place a breakpoint in sbrk and _sbrk_r. Doing a backtrace will reveal it gets called by _malloc_r.
1 parent ad4d883 commit d21cd79

9 files changed

Lines changed: 299 additions & 90 deletions

File tree

pkg/tlsf/Makefile.dep

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ifneq (,$(filter tlsf-malloc,$(USEMODULE)))
2+
ifneq (,$(filter newlib,$(USEMODULE)))
3+
USEMODULE += tlsf-malloc_newlib
4+
else
5+
USEMODULE += tlsf-malloc_native
6+
endif
7+
endif

pkg/tlsf/Makefile.include

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ ifneq (,$(filter tlsf-malloc,$(USEMODULE)))
44
INCLUDES += -I$(RIOTPKG)/tlsf/contrib/include
55
DIRS += $(RIOTPKG)/tlsf/contrib
66
endif
7+
8+
PSEUDOMODULES += tlsf-malloc_newlib
9+
PSEUDOMODULES += tlsf-malloc_native

pkg/tlsf/contrib/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
MODULE := tlsf-malloc
1+
MODULE = tlsf-malloc
2+
SUBMODULES = 1
3+
SRC = tlsf-malloc.c
24

35
include $(RIOTBASE)/Makefile.base

pkg/tlsf/contrib/Makefile.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
UNDEF += $(BINDIR)/tlsf-malloc/tlsf-malloc.o

pkg/tlsf/contrib/include/tlsf-malloc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#define TLSF_MALLOC_H
3838

3939
#include <stddef.h>
40+
4041
#include "tlsf.h"
4142

4243
#ifdef __cplusplus

pkg/tlsf/contrib/native.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright (C) 2019 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @ingroup pkg_tlsf_malloc
10+
* @ingroup pkg
11+
* @ingroup sys
12+
* @{
13+
* @file
14+
*
15+
* @brief Definitions to use tlsf as malloc on native.
16+
* @author Juan I Carrano
17+
*
18+
* This assumes glibc is bein used.
19+
* see: https://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html
20+
*
21+
*/
22+
23+
#include <string.h>
24+
#include <errno.h>
25+
26+
#include "irq.h"
27+
#include "tlsf.h"
28+
#include "tlsf-malloc.h"
29+
#include "tlsf-malloc-internal.h"
30+
31+
/* TODO: Add defines for other compilers */
32+
#if defined(__GNUC__) && !defined(__clang__) /* Clang supports __GNUC__ but
33+
* not the alloc_size()
34+
* attribute */
35+
36+
#define ATTR_MALLOC __attribute__((malloc, alloc_size(1)))
37+
#define ATTR_CALLOC __attribute__((malloc, alloc_size(1,2)))
38+
#define ATTR_MALIGN __attribute__((alloc_align(1), alloc_size(2), malloc))
39+
#define ATTR_REALLOC __attribute__((alloc_size(2)))
40+
41+
#else /* No GNU C -> no alias attribute */
42+
43+
#define ATTR_MALLOCR
44+
#define ATTR_CALLOCR
45+
#define ATTR_MALIGNR
46+
#define ATTR_REALLOCR
47+
48+
#endif /* __GNUC__ */
49+
50+
extern tlsf_t tlsf_malloc_gheap;
51+
52+
/**
53+
* Allocate a block of size "bytes"
54+
*/
55+
ATTR_MALLOC void *malloc(size_t bytes)
56+
{
57+
unsigned old_state = irq_disable();
58+
void *result = tlsf_malloc(tlsf_malloc_gheap, bytes);
59+
60+
if (result == NULL) {
61+
errno = ENOMEM;
62+
}
63+
64+
irq_restore(old_state);
65+
return result;
66+
}
67+
68+
/**
69+
* Allocate and clear a block of size "bytes*count"
70+
*/
71+
ATTR_CALLOC void *calloc(size_t count, size_t bytes)
72+
{
73+
void *result = malloc(count * bytes);
74+
75+
if (result != NULL) {
76+
memset(result, 0, count * bytes);
77+
}
78+
return result;
79+
}
80+
81+
/**
82+
* Allocate an aligned memory block.
83+
*/
84+
ATTR_MALIGN void *memalign(size_t align, size_t bytes)
85+
{
86+
unsigned old_state = irq_disable();
87+
void *result = tlsf_memalign(tlsf_malloc_gheap, align, bytes);
88+
89+
if (result == NULL) {
90+
errno = ENOMEM;
91+
}
92+
93+
irq_restore(old_state);
94+
return result;
95+
}
96+
97+
/**
98+
* Deallocate and reallocate with a different size.
99+
*/
100+
ATTR_REALLOC void *realloc(void *ptr, size_t size)
101+
{
102+
unsigned old_state = irq_disable();
103+
void *result = tlsf_realloc(tlsf_malloc_gheap, ptr, size);
104+
105+
if (result == NULL) {
106+
errno = ENOMEM;
107+
}
108+
109+
irq_restore(old_state);
110+
return result;
111+
}
112+
113+
114+
/**
115+
* Deallocate a block of data.
116+
*/
117+
void free(void *ptr)
118+
{
119+
unsigned old_state = irq_disable();
120+
121+
tlsf_free(tlsf_malloc_gheap, ptr);
122+
irq_restore(old_state);
123+
}

pkg/tlsf/contrib/newlib.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (C) 2019 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @ingroup pkg_tlsf_malloc
10+
* @ingroup pkg
11+
* @ingroup sys
12+
* @{
13+
* @file
14+
*
15+
* @brief Reentrant definitions to replace newlib's malloc with TLSF.
16+
* @author Juan I Carrano
17+
*
18+
* Newlib-nano implements malloc/free/etc in terms of the reentrant definitions
19+
* in _malloc_r/_free_r/etc so the latter are the one that have to be
20+
* overwritten.
21+
*
22+
*/
23+
24+
#include <string.h>
25+
#include <reent.h>
26+
#include <errno.h>
27+
28+
#include "irq.h"
29+
#include "tlsf.h"
30+
#include "tlsf-malloc.h"
31+
#include "tlsf-malloc-internal.h"
32+
33+
34+
/* TODO: Add defines for other compilers */
35+
#if defined(__GNUC__) && !defined(__clang__) /* Clang supports __GNUC__ but
36+
* not the alloc_size()
37+
* attribute */
38+
39+
#define ATTR_MALLOCR __attribute__((malloc, alloc_size(2)))
40+
#define ATTR_CALLOCR __attribute__((malloc, alloc_size(2,3)))
41+
#define ATTR_MALIGNR __attribute__((alloc_align(2), alloc_size(3), malloc))
42+
#define ATTR_REALLOCR __attribute__((alloc_size(3)))
43+
44+
#else /* No GNU C -> no alias attribute */
45+
46+
#define ATTR_MALLOCR
47+
#define ATTR_CALLOCR
48+
#define ATTR_MALIGNR
49+
#define ATTR_REALLOCR
50+
51+
#endif /* __GNUC__ */
52+
53+
/**
54+
* Allocate a block of size "bytes"
55+
*/
56+
ATTR_MALLOCR void *_malloc_r(struct _reent *reent_ptr, size_t bytes)
57+
{
58+
unsigned old_state = irq_disable();
59+
void *result = tlsf_malloc(tlsf_malloc_gheap, bytes);
60+
61+
if (result == NULL) {
62+
reent_ptr->_errno = ENOMEM;
63+
}
64+
65+
irq_restore(old_state);
66+
return result;
67+
}
68+
69+
/**
70+
* Allocate and clear a block of size "bytes*count"
71+
*/
72+
ATTR_CALLOCR void *_calloc_r(struct _reent *reent_ptr, size_t count, size_t bytes)
73+
{
74+
void *result = _malloc_r(reent_ptr, count * bytes);
75+
76+
if (result != NULL) {
77+
memset(result, 0, count * bytes);
78+
}
79+
return result;
80+
}
81+
82+
/**
83+
* Allocate an aligned memory block.
84+
*/
85+
ATTR_MALIGNR void *_memalign_r(struct _reent *reent_ptr, size_t align, size_t bytes)
86+
{
87+
unsigned old_state = irq_disable();
88+
void *result = tlsf_memalign(tlsf_malloc_gheap, align, bytes);
89+
90+
if (result == NULL) {
91+
reent_ptr->_errno = ENOMEM;
92+
}
93+
94+
irq_restore(old_state);
95+
return result;
96+
}
97+
98+
/**
99+
* Deallocate and reallocate with a different size.
100+
*/
101+
ATTR_REALLOCR void *_realloc_r(struct _reent *reent_ptr, void *ptr, size_t size)
102+
{
103+
unsigned old_state = irq_disable();
104+
void *result = tlsf_realloc(tlsf_malloc_gheap, ptr, size);
105+
106+
if (result == NULL) {
107+
reent_ptr->_errno = ENOMEM;
108+
}
109+
110+
irq_restore(old_state);
111+
return result;
112+
}
113+
114+
/**
115+
* Deallocate a block of data.
116+
*/
117+
void _free_r(struct _reent *reent_ptr, void *ptr)
118+
{
119+
unsigned old_state = irq_disable();
120+
(void)reent_ptr;
121+
122+
tlsf_free(tlsf_malloc_gheap, ptr);
123+
irq_restore(old_state);
124+
}
125+
126+
/**
127+
* @}
128+
*/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (C) 2014-2018 Freie Universität Berlin
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @ingroup pkg_tlsf_malloc
10+
* @{
11+
* @file
12+
* @internal
13+
*
14+
* @brief TLSF/malloc internal definitions
15+
* @author Juan I Carrano
16+
*
17+
*/
18+
19+
#include "tlsf.h"
20+
21+
#ifndef TLSF_MALLOC_INTERNAL_H
22+
#define TLSF_MALLOC_INTERNAL_H
23+
24+
extern tlsf_t tlsf_malloc_gheap;
25+
26+
#endif /* TLSF_MALLOC_INTERNAL_H */

0 commit comments

Comments
 (0)