Skip to content
This repository was archived by the owner on Jan 15, 2021. It is now read-only.
Merged
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
97 changes: 80 additions & 17 deletions source/ualloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,44 @@ extern int printf(const char *, ...);

extern void * volatile mbed_sbrk_ptr;

// Set debug level to 0 until non-allocating printf is available
const UAllocDebug_t ualloc_debug_level = UALLOC_DEBUG_NONE;//(DEBUG?UALLOC_DEBUG_MAX:UALLOC_DEBUG_NONE);
/*****************************************************************************************
UALLOC_DEBUG_LOG is effectively reserved for tracing memory allocations
Tracing must be enabled via "yotta config":
{
"debug": {
"options": {
"memory-trace": true
}
}
}
[TODO]: ualloc_debug_level probably needs better control with "yotta config"
*****************************************************************************************/
#ifdef YOTTA_CFG_DEBUG_OPTIONS_MEMORY_TRACE
const UAllocDebug_t ualloc_debug_level = UALLOC_DEBUG_LOG;
#else
const UAllocDebug_t ualloc_debug_level = UALLOC_DEBUG_NONE;
#endif

// Debug characters
const char ua_chars[] = "NFEWIL";

/*****************************************************************************************
The purpose of "prevent_tracing" below is twofold:

1. prevent infinite loops (mbed_ualloc_internal -> ualloc_debug -> printf ->
mbed_ualloc_internal -> ualloc_debug -> printf...)
2. prevent a possible scenario when an interrupt occurs while ualloc_debug
is printing debug information and the interrupt also calls 'mbed_ualloc' or
another memory operation that would result in ualloc_debug being called,
which would in turn result in garbled output. By using "prevent_tracing",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be possible to have a re-entrant logging format (surround messages by matching brackets?), which would make this OK. This seems like a suitable solution for now though, especially as we don't malloc from interrupt handlers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think this is already re-entrant, since it always starts with a known prefix that isn't repeated im the rest of the message. I can't remove prevent_tracing yet tohugh, because of printf.

the output is kept consistent, but the memory operation invoked in the
interrupt handler is not logged.

1 above can be prevented by using a logging function that doesn't allocate memory.
2 above can be prevented by queueing log messages instead of logging them immediately.
*****************************************************************************************/
static volatile int prevent_tracing = 0;

#define ualloc_debug(ADBG_LEVEL, fmt, ...) do { \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be inside separate trace library, because for example it might be that sometimes user wan't to change endpoint where to print these debug messages (=traces), or change trace format easily without touching ualloc -library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please file this as an issue against this repo.

if (ADBG_LEVEL <= ualloc_debug_level && ADBG_LEVEL < UALLOC_DEBUG_MAX) { \
printf("UAL:%c " fmt, ua_chars[ADBG_LEVEL], __VA_ARGS__); \
Expand All @@ -52,10 +84,9 @@ const char ua_chars[] = "NFEWIL";
#define caller_addr() (NULL)
#endif

void * mbed_ualloc(size_t bytes, UAllocTraits_t traits)
static void * mbed_ualloc_internal(size_t bytes, UAllocTraits_t traits, void *caller)
{
void * ptr = NULL;
void * caller = (void*) caller_addr();
if (UALLOC_TEST_TRAITS(traits.flags, UALLOC_TRAITS_NEVER_FREE)) {
ptr = mbed_krbs(bytes);
// krbs uses the same semantics as sbrk, so translate a -1 to NULL.
Expand All @@ -76,47 +107,79 @@ void * mbed_ualloc(size_t bytes, UAllocTraits_t traits)

if(ptr == NULL) {
ualloc_debug(UALLOC_DEBUG_WARNING, "ua c:%p fail\n", caller);
} else {
ualloc_debug(UALLOC_DEBUG_LOG, "ua c:%p m:%p\n", caller, ptr);
}

return ptr;
}
void * mbed_urealloc(void * ptr, size_t bytes, UAllocTraits_t traits)

void *mbed_ualloc(size_t bytes, UAllocTraits_t traits)
{
void *caller = (void*)caller_addr();
void *p = mbed_ualloc_internal(bytes, traits, caller);
if (!prevent_tracing) {
prevent_tracing = 1;
ualloc_debug(UALLOC_DEBUG_LOG, "ua c:%p s:%u m:%p\n", caller, (unsigned)bytes, p);
prevent_tracing = 0;
}
return p;
}

static void * mbed_urealloc_internal(void * ptr, size_t bytes, UAllocTraits_t traits, void *caller)
{
void * caller = (void*) caller_addr();
void *newptr = NULL;
if (ptr == NULL) {
return mbed_ualloc(bytes, traits);
}
if(traits.flags & ~UALLOC_TRAITS_BITMASK) {
// Traits not supported in urealloc yet
ualloc_debug(UALLOC_DEBUG_WARNING, "ua c:%p fail\n", caller);
ualloc_debug(UALLOC_DEBUG_ERROR, "ur c:%p fail\n", caller);
return NULL;
}
uintptr_t ptr_tmp = (uintptr_t) ptr;
if ((ptr_tmp < (uintptr_t) mbed_sbrk_ptr) &&
(ptr_tmp >= (uintptr_t)&__mbed_sbrk_start)) {
newptr = dlrealloc(ptr, bytes);
} else {
ualloc_debug(UALLOC_DEBUG_LOG, "uf c:%p m:%p non-heap realloc\n", caller, ptr);
ualloc_debug(UALLOC_DEBUG_ERROR, "ur c:%p m:%p non-heap realloc\n", caller, ptr);
}

if(newptr == NULL) {
ualloc_debug(UALLOC_DEBUG_WARNING, "ur c:%p m0:%p fail\n", caller, ptr);
} else {
ualloc_debug(UALLOC_DEBUG_LOG, "ur c:%p m0:%p m1:%p\n", caller, ptr, newptr);
ualloc_debug(UALLOC_DEBUG_WARNING, "ur c:%p p:%p fail\n", caller, ptr);
}
return newptr;
}
void mbed_ufree(void * ptr)

void * mbed_urealloc(void * ptr, size_t bytes, UAllocTraits_t traits)
{
void *caller = (void*)caller_addr();
void *p = mbed_urealloc_internal(ptr, bytes, traits, caller);
if (!prevent_tracing) {
prevent_tracing = 1;
ualloc_debug(UALLOC_DEBUG_LOG, "ur c:%p s:%u p:%p m:%p\n", caller, (unsigned)bytes, ptr, p);
prevent_tracing = 0;
}
return p;
}

static void mbed_ufree_internal(void * ptr, void *caller)
{
void * caller = (void*) caller_addr();
ualloc_debug(UALLOC_DEBUG_LOG, "uf c:%p m:%p\n", caller, ptr);
uintptr_t ptr_tmp = (uintptr_t) ptr;
if ((ptr_tmp < (uintptr_t) mbed_sbrk_ptr) &&
(ptr_tmp >= (uintptr_t)&__mbed_sbrk_start)) {
dlfree(ptr);
} else {
ualloc_debug(UALLOC_DEBUG_LOG, "uf c:%p m:%p non-heap free\n", caller, ptr);
ualloc_debug(UALLOC_DEBUG_WARNING, "uf c:%p m:%p non-heap free\n", caller, ptr);
}
}

void mbed_ufree(void *ptr)
{
void *caller = (void*)caller_addr();
mbed_ufree_internal(ptr, caller);
if (!prevent_tracing) {
prevent_tracing = 1;
ualloc_debug(UALLOC_DEBUG_LOG, "uf c:%p m:%p\n", caller, ptr);
prevent_tracing = 0;
}
}