nRF: memalign issue

Hello,

I've been extending the nRF blink example (1. thanks a lot to all those who put up the examples together, 2. I'll publish blog posts and code repos when I've got some more interesting stuff) and I'm now facing some weird issue with the memalign implementation.

My simple swift code is

print("a")
var iPtr: UnsafeMutablePointer<UInt16> = UnsafeMutablePointer<UInt16>.allocate(capacity: 1)
print("b")

and this prints a to the console, then is stuck.

I did add a couple of print statements to the memalign implementation from the repo:

int
posix_memalign(void **memptr, size_t alignment, size_t size)
{
  printk(">>posix_memalign\n");
  void *p = aligned_alloc(alignment, size);
  printk("Returned from aligned_alloc\n");
  if (p) {
    *memptr = p;
    return 0;
  }

  return errno;
}

and that's what I see in the console

a
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign
>>posix_memalign

and the code halts there.

This would suggest some kind of recursive call from aligned_alloc to posix_memalloc, but looking at the Zephyr source code, I could not see how that would happen.

If I use malloc() instead of aligned_alloc(), code works properly and I can use the UnsafeMutablePointer normally.
However, I suppose not respecting the alignment could lead to some issues down the road.

I've seen that Zephyr should have a k_aligned_alloc but this results in an undefined reference when linking (that I have not yet taken the time to investigate further).

Has anyone faced anything similar ? Does anybody have an explanation or ideas on what/how I could further debug the issue ?

This is much lower level that the code I'm usually working with, so bear with me if I don't understand some of the mechanisms at play here.

Thanks,
Eric

Maybe log the actual requested alignment? Or take a leap of faith and special case an alignment of 1 (and 0!) and see if that fixes it?

Thanks for your feedback.

If I log the alignment, the initial value is 16.

I then forced the alignement to 1 or 0 when calling aligned_alloc in the posix_memalign implementation (that's what I understood from your suggestion).

And the output now looks like

a
>>posix_memalign
alignment 16
>>posix_memalign
alignment 1
>>posix_memalign
alignment 1
...

or

a
>>posix_memalign
alignment 16
>>posix_memalign
alignment 0
>>posix_memalign
...

Which I interpret as a confirmation of the recursive call.

Well what I actually meant was check the incoming alignment and for alignment of 0 or 1 you are already aligned so you are good to go. I had thought the aligned_alloc might call posix_memalign with something like 0 or 1...

Lets see as an implementation detail macOS and iOS et al have a malloc that aligns everything to at least 16 bytes. So maybe that is relevant here. On a non-Apple platform maybe just use regular malloc add mod 16 and when free gets called lop off the low bits...except there isn't a different free is there? Aw, rats.

I did some further digging with using k_aligned_alloc() instead of aligned_alloc().

This was initially giving me a "undefined reference to `k_aligned_alloc'" error message in a linking stage.

Looking into Zephyr source code, I found that this function is defined in kernel/mempool.c under a conditional
#if (K_HEAP_MEM_POOL_SIZE > 0)

Searching for that constant, I found some information in the Migration guide to Zephyr v3.6.0 — Zephyr Project Documentation page, indicating that this constant was indeed now driving the system heap availability.

I did not, however, find anyway to make this work, defining that constant in Stubs.c has no effect.

As the release notes indicated that the old option was still available, I tried that, adding CONFIG_HEAP_MEM_POOL_SIZE=2048 to my prj.conf file.

With that in place, I can now use
void *p = k_aligned_alloc(alignment, size);
in the posix_memalign() implementation in Stubs.c

I now need to address the deallocation, calling .deallocate() on my UnsafeMutablePointer should eventually call k_free()