I’m playing around with an ESP32-C6 Development board and looking at was playing around with wrapping the FreeRTOS Task API with something more Swift-y. Here is my basic Main.swift:
@_cdecl("app_main")
func main() {
print("Hello from Swift on ESP32-C6!")
_ = try? Task {
print("In my task")
}
print("Created task, exiting")
}
And here is an included Task.swift
class Task {
typealias TaskFunction = @convention(c) (UnsafeMutableRawPointer?) -> Void
let innerTask: () -> Void
init(_ innerTask: @escaping () -> Void) throws {
self.innerTask = innerTask
let taskPointer = Unmanaged.passRetained(self).toOpaque()
let taskFunction: TaskFunction = {(_ ptr: UnsafeMutableRawPointer?) in
guard let ptr else { return }
let unmanaged = Unmanaged<Task>.fromOpaque(ptr)
let task = unmanaged.takeUnretainedValue()
print("executing task")
task.innerTask()
print("executed task, releasing")
unmanaged.release()
print("released, executing vTaskDelete")
vTaskDelete(nil)
print("executed vTaskDelete, exiting closure")
}
if pdPASS != xTaskCreate(taskFunction, "inner_task", 4096, taskPointer, uxTaskPriorityGet(nil) - 1 , nil) {
print("Failed to create task")
Unmanaged<Task>.fromOpaque(taskPointer).release()
}
print("exiting init")
}
deinit {
print("Task.deinit")
}
}
When I build, flash, and monitor the output, I see this at the end:
I (250) main_task: Calling app_main()
Hello from Swift on ESP32-C6!
exiting init
Created task, exiting
I (260) main_task: Returned from app_main()
executing task
In my task
executed task, releasing
released, executing vTaskDelete
I was expecting to see the Task instance deallocate on the unmanaged.release() line, but it never happens.
I think I’m correctly managing the memory as expected, so I’m wondering if this is expected behavior or if I’ve done something wrong.