I kept digging on and off during the last few weeks, and although I don't have all my answers yet, I thought I would post as it might interest some people (and I could also receive some help while I keep going down the rabbit hole).
I verified that using k_aligned_alloc
in the posix_memalign()
implementation works, returns addresses that are properly aligned but fails to deallocate.
Calling deallocate()
on my UnsafeMutablePointer
calls free()
(I suppose) and this does not know anything about the memory allocated by k_aligned_alloc()
and so does nothing.
Doing a loop of .allocate(capacity:)
and deallocate()
eventually ends up with an error (as there is no more memory to allocate).
Sample with CONFIG_HEAP_MEM_POOL_SIZE=256
in prj.conf, eventually allocations fail
for i in 1..<100 {
var ptr: UnsafeMutablePointer<UInt32> = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)
ptr.deallocate()
}
As free
is already implemented, I cannot re-implement it to call k_free
instead.
I looked into the implementation of deallocate
in UnsafePointer.swift (swift/stdlib/public/core/UnsafePointer.swift at c874e6f84cf7c5fdb3665b33febb54b352676e50 · swiftlang/swift · GitHub) but this calls Builtin.deallocRaw()
and this goes beyond my current understanding of the inner workings of Swift.
I tried directly calling k_free()
from my Swift code and that works but:
- I'm not sure if there could be potential side effects, I also tried calling both
deallocate()
and k_free()
and that works
- it's definitely not elegant and does make the code less readable for a Swift developer
Following works fine
for i in 1..<100 {
var ptr: UnsafeMutablePointer<UInt32> = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)
ptr.deallocate()
k_free(ptr)
}
The other path I took is to use malloc(). This works fine and memory is freed as required, but the requested alignement is not respected, as shown in the below example. I'm not sure how bad this is, never caused issues in the little projects I've worked on.
posix_memalign()
implementation
int
posix_memalign(void **memptr, size_t alignment, size_t size)
{
printk(">>posix_memalign, asking for %d with align %d\n", size, alignment);
printk("Size of size_t %d\n", sizeof (size_t));
void *p = malloc(size);
if (p) {
printk("malloc returned %p, aligned %s\n", p, ((uint32_t)p % alignment) == 0 ? "yes":"no");
printk("aligned on size_t ? %s\n", ((uint32_t)p % sizeof (size_t)) == 0 ? "yes":"no");
*memptr = p;
return 0;
}
printk("Error, code %d\n", errno);
return errno;
}
My swift code
struct MediumStruct {
var a = 42
var b = true
var c = "Hello"
var d = 43
var e = 44
var f = 45
}
var iPtr: UnsafeMutablePointer<UInt16> = UnsafeMutablePointer<UInt16>.allocate(capacity: 1)
var pMedium = UnsafeMutablePointer<MediumStruct>.allocate(capacity: 1)
var a: [Bool] = Array(repeating: true, count: 1)
var iPtr2: UnsafeMutablePointer<UInt16> = UnsafeMutablePointer<UInt16>.allocate(capacity: 1)
results in
>>posix_memalign, asking for 2 with align 16
Size of size_t 4
malloc returned 0x20002088, aligned no
aligned on size_t ? yes
>>posix_memalign, asking for 32 with align 16
Size of size_t 4
malloc returned 0x20002090, aligned yes
aligned on size_t ? yes
>>posix_memalign, asking for 17 with align 4
Size of size_t 4
malloc returned 0x200020b8, aligned yes
aligned on size_t ? yes
>>posix_memalign, asking for 2 with align 16
Size of size_t 4
malloc returned 0x200020d8, aligned no
aligned on size_t ? yes
Regarding my observation that, with the original implementation in the example repo, there was some recursion, I found that, in EmbeddedRuntime.swift, there is the implementation of alignedAlloc() swift/stdlib/public/core/EmbeddedRuntime.swift at c874e6f84cf7c5fdb3665b33febb54b352676e50 · swiftlang/swift · GitHub and it calls posix_memalign()
.
But stubs.c is calling aligned_alloc()
(different casing). Are those the same thing ?
@kubamracek , as you did the commit with that implementation, would you mind shedding some light on this for me ? That would be tremendously helpful.
And one more question for now, although an UnsafeMutablePointer.allocate()
do indeed call posix_memalign()
, creating an instance of a class does not. I still think the instance ends up on the heap and not the stack but I don't understand the mechanism behind, still experimenting with that one.
Apologies for the super long post. I'll soon post a GitHub repo with my different test projects and when I finally understand the details of this, I'll create a blog post about it.