Adding newlib locks & BASEPRI value prior to starting scheduler

Hello,

I just want to clarify if I understood the FreeRTOS API behaviour correctly with regards to BASEPRI register value because I stumbled over an issue with my device initialization (Cortex-M3) while porting a bare-metal application to FreeRTOS. I’m using heap_3.c and configUSE_NEWLIB_REENTRANT = 1.

I added the newlib lock mechanism based on this implementation.

Question #1: since the locks are initialized before main() is called and the locks are calling pvPortMalloc(), the BASEPRI register will have the shifted configMAX_SYSCALL_INTERRUPT_PRIORITY value when entering main(), is this correct? Somewhere I’ve read that the BASEPRI register value is raised, but not reset to zero when API calls are not made from within a task or prior to starting the scheduler.

Question #2: if the assumption above is correct, it shouldn’t be a problem to reset the BASEPRI register to zero manually when entering main(), is this also correct? I had to do it this way because for the migration I’m pulling in small pieces of the original application and do some testing before starting the scheduler. I stumbled because I configured & enabled a timer interrupt, but it never hit the breakpoint inside the ISR. That was the point where I realised that “something” modified the BASEPRI register value.

Question #3: the locking mechanism mentioned above is using dynamic memory, there’s also a static implementation. Should I prefer one over the other?

Thank you.

Regards

A1 - most API calls will leave interrupt masked by BASPRI if they are called before the scheduler is started. BASPRI is then cleared automatically before the first task runs. See number 4 in this FAQ page: https://www.freertos.org/FAQHelp.html. However, I don’t think it is necessary to use heap_3 if you use newlib with reentrancy and locking enabled.

A2 - it’s ok to reset basepri manually provided no interrupt are going to use the FreeRTOS API before the scheduler starts.

A3 - static or dynamic memory depends on the application and the authors preference. https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html

Hello Richard,

thank you for your response. For A1 and the used heap, it means that with the locks added and the newlib being reentrant, I can use any heap implementation provided by FreeRTOS? It would not conflict with newlib using its own malloc()/free()?

Regards

Richard means that you don’t really need the heap_3 implementation with its additional wrappers around malloc/free because you already provided the locking.
You could simply

#define pvPortMalloc malloc
#define vPortFree    free

in your FreeRTOSConfig.h.
I’m curious why you’re using this rather sophisticated ‘retarget locking’ meachism.
For malloc/free the implementation of __malloc_lock/free hooks is sufficient and much simpler.

1 Like

Hello Hartmut,

Well, it’s simply because I’ve only little knowledge about the internals of newlib, etc. I’m still a beginner and I only know THAT I’ve to take care about locks, etc when using specific library functions from multiple tasks. But for the HOW I’m still lacking experience.

So, if understand correctly, if I redefine pvPortMalloc/vPortFree and remove heap_3.c from the project, It should also work. I’ll try it.

Regards

Exactly :+1:
And you could simplify your code by just adding the rather simple __malloc_lock/free hook functions like this

void __malloc_lock(struct _reent *r)
{
   vTaskSuspendAll();
}

void __malloc_unlock(struct _reent *r)
{
   xTaskResumeAll();
}

I’d not propose to use critical sections for locking malloc/free because those functions might be time consuming causing rather long periods where interrupts are disabled.
This in turn might cause problems. At least it might make responsiveness worse.

2 Likes

Hello Hartmut,

okay, I’ll switch it to vTaskSuspendAll()/xTaskResumeAll(), thank you.

I’m curious, for taskENTER_CRITICAL()/taskEXIT_CRITICAL(), there are also counterparts for calling them from interrupts. While I would have a bad feeling about using malloc() from an interrupt, this would now be possible, right? For taskENTER_CRITICAL()/taskEXIT_CRITICAL(), I’d have to check first if the function is called from within an ISR and then call the appropriate function?

Regards

Yes. And I’d also have a bad feeling about using malloc/free in ISRs. At least when using standard heap implementations like the one in newlib, because those functions might take varying, longer times to execute. Internally the memory blocks are usually managed by lists…
Somewhat special heap implementations like lock free fixed block allocators don’t have this drawbacks but others. It depends…
Often dedicated buffering resp. memory management mechanisms are used for ISR/post-processing task signaling keeping things simple and ISRs short.

1 Like

Okay. Many thanks for clarifying and giving hints for optimization :slight_smile:

Since the initial questions have been answered by Richard, I’ll mark his post as the solution.

Regards