cancel
Showing results for 
Search instead for 
Did you mean: 

Issue with Byte pool for ThreadX

flaming_vines
Associate II

Hi,

I am having issues with threadX tx_byte_allocate throwing a hard fault exception. 

This only happens after some time of byte allocate and release. There are still plenty of available bytes according to the pool. But somehow in _tx_byte_pool_search it encounters some problem. 

I am not posting the entire source code here as that will be huge. Anyway, I am using STM32H753. I created a byte pool using DTCRAM (128K).

Linker snippet:

RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K

.ram_dtcmram :

{

*(.ram_dtcmram)

} >RAM

 

 

 

Code Snippet

#define RAM_DTCMRAM \

__attribute__((section(".ram_dtcmram")))

#define GENERIC_MEM_ALLOCATION (0x20000-0x1000)

 

static u8 m_genericMemBytePoolBuffer[GENERIC_MEM_ALLOCATION] RAM_DTCMRAM;

static TX_BYTE_POOL m_genericMemBytePool RAM_D3;

 

bool Hal_MemPool_Init(void)

{

if (tx_byte_pool_create(&m_genericMemBytePool, "Generic memory pool", m_genericMemBytePoolBuffer , GENERIC_MEM_ALLOCATION) != TX_SUCCESS){

return FALSE;

}

return TRUE;

}

 

This  is the screenshot of the pool when the hard fault happens. byte pool available is still more than 50k

flaming_vines_0-1698198224139.png

Below are the local variables during the fault. As you can see current pointer goes to 0x2492bc7e. That memory is not available for H753 and obviously will throw a hard fault error trying to access this memory.

Specifically on line below inside the do while(examine_blocks != ((UINT) 0)) loop

work_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (sizeof(UCHAR *)));

free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);

if ((*free_ptr) == TX_BYTE_BLOCK_FREE) //<-----------HARD FAULT

 

 

Now my question is why? Clearly, I have enough available bytes in the pool. You can also see below that the memory required is only 256 bytes. Even if the memory gets fragmented, I am pretty confident there is a block with 256 bytes free on it. Besides, ThreadX is supposed to merge those splits or fragments. Which is also stated in the pool above (tx_byte_pool_performance_merge_count)

flaming_vines_1-1698198356976.png

 

Version of ThreadX is 

flaming_vines_2-1698199284021.png

Not that it matters I think, I made the pool  m_genericMemBytePool the same RAM as the m_genericMemBytePoolBuffer to dtcmram. Same outcome.

 

Thanks,

Carlo

 

1 ACCEPTED SOLUTION

Accepted Solutions
ABasi.2
Senior

Hello!

i have found my error, and i want to write here in case anyone else have the same problem

i actually don't understand the correlation beetween the problem occured and this line of code (they are in different thread) but this solve the problem

 

i was thinking it was a good idea to do this in case i don't need the flags value:

tx_event_flags_get(&machineFlags, MACHINEPARAMSFLAG, TX_OR ,NULL, TX_WAIT_FOREVER);

 

but i don't know why using NULL instead a correct variable address make a problem.

i switched to:

tx_event_flags_get(&machineFlags, MACHINEPARAMSFLAG, TX_OR ,&flags, TX_WAIT_FOREVER);

 

and now the problem is solved..

it was my fault

 

View solution in original post

4 REPLIES 4
christop
ST Employee
ABasi.2
Senior

hello!

 

i have the exact same problem using a nucleo-g0b1re

 tx_byte_allocate trow me an hardfault

digging n the code the hardfault appear at this line in the UCHAR *_tx_byte_pool_search(TX_BYTE_POOL *pool_ptr, ULONG memory_size)

if ((*free_ptr) == TX_BYTE_BLOCK_FREE)  <---- hardfaukt here

 

the strange thing is that the same tx_byte_allocat function perfectly without another thread that i have recently added

 

i espect that if there is no room to allocate memory the tx_byte_allocate simply return different from TX_SUCCESS

(i'm using TX_WAIT_FOREVER so in fact i espect to wait)

 

but:

1) i sure have space in the byte pool

2) why an hardfault?

 

if i place the mouse on *free_ptr   the value is : 0x20000026 <_impure_data+18> 

 

did you find the problem?

i saw you close the ticket because you are porting a code from another OS but for me is totally a new code

 

best reguards

 

 

ABasi.2
Senior

Hello!

i have found my error, and i want to write here in case anyone else have the same problem

i actually don't understand the correlation beetween the problem occured and this line of code (they are in different thread) but this solve the problem

 

i was thinking it was a good idea to do this in case i don't need the flags value:

tx_event_flags_get(&machineFlags, MACHINEPARAMSFLAG, TX_OR ,NULL, TX_WAIT_FOREVER);

 

but i don't know why using NULL instead a correct variable address make a problem.

i switched to:

tx_event_flags_get(&machineFlags, MACHINEPARAMSFLAG, TX_OR ,&flags, TX_WAIT_FOREVER);

 

and now the problem is solved..

it was my fault

 

To follow up on this for anyone experiencing it, I have found a more valid explanation as to what is causing this bug as the "Accepted Solution" here doesn't really answer it, and did not solve it for me. It was likely just some voodoo magic timing change to the code operation that fixed it for their particular implementation.

My root cause was having 2 independent threads at different priorities trying to use the same tx_byte_pool_allocate calls on the same shared byte pool at the exact same time. This was because I had written a spoofed malloc/free function that went to these byte pools to claim and free memory.

Digging down into _tx_byte_pool_search shows that whichever thread is calling it is the current owner of the pool. So if you get a priority preemption while a lower thread is allocating memory, it can have the memory it is trying to claim ripped out from under it while it is in the process of claiming it. There is clearly something that is not re-entrant about those functions, which in a way makes sense as the memory is "shared" and hence can't really be re-entrant. But there must still be a bug somewhere in ThreadX where it can't properly gate off the acquired memory pointers from separate threads to ensure they are returned to the proper thread.

The solution that worked for me was to use a Mutex with priority inheritance enabled around the shared tx_byte_allocate calls. The priority inheritance being important because it lets the lower priority thread finish up the allocation request while the higher thread waits. This prevents the hug of death while letting the allocation finish without nulling out that pointer by a higher thread after the lower priority thread had already been assigned a pointer.