FreeRTOS SMP: Unable to call cyw43_arch_init outside of FreeRTOS task (intentional?) #1540

Open
opened 2023-11-09 00:42:48 -06:00 by gemarcano · 5 comments
gemarcano commented 2023-11-09 00:42:48 -06:00 (Migrated from github.com)

I am using upstream FreeRTOS with the SMP work merged into main (and using PR #1530 to fix the renaming of a FreeRTOS config).

I've successfully managed to convert the NTP client example Pico W example from its original LwIP raw API form to one using NO_SYS=0 FreeRTOS SMP and the LwIP socket API. In the process, I discovered that if I tried calling cyw43_arch_init from main(), the pico would hard crash with no output whatsoever. It worked fine if called from a FreeRTOS task.

I rigged up a second pico as a debug probe, and found a hard_assert that was failing in async_context_freertos_execute_sync. Specifically:

hard_assert(xSemaphoreGetMutexHolder(self->lock_mutex) != xTaskGetCurrentTaskHandle());

When called from main() or outside of a FreeRTOS task, xTaskGetCurrentTaskHandle() returns 0, and in general I'm seeing xSemaphoreGetMutexHolder(self->lock_mutex) return 0 during initialization (as apparently no tasks have claimed the mutex). This clearly leads to the hard_assert to fire when calling async_context_freertos_execute_sync outside of a FreeRTOS task.

Is this intentional? I'm also not 100% sure what that hard_assert is checking. Is it to catch some sort of recursive calling/deadlock (although I don't see that mutex being claimed during init-- maybe it is in other execution paths?)?

I am using upstream FreeRTOS with the SMP work merged into main (and using PR #1530 to fix the renaming of a FreeRTOS config). I've successfully managed to convert the NTP client example Pico W example from its original LwIP raw API form to one using NO_SYS=0 FreeRTOS SMP and the LwIP socket API. In the process, I discovered that if I tried calling `cyw43_arch_init` from `main()`, the pico would hard crash with no output whatsoever. It worked fine if called from a FreeRTOS task. I rigged up a second pico as a debug probe, and found a `hard_assert` that was failing in [`async_context_freertos_execute_sync`](https://github.com/raspberrypi/pico-sdk/blob/6a7db34ff63345a7badec79ebea3aaef1712f374/src/rp2_common/pico_async_context/async_context_freertos.c#L196). Specifically: ``` hard_assert(xSemaphoreGetMutexHolder(self->lock_mutex) != xTaskGetCurrentTaskHandle()); ``` When called from `main()` or outside of a FreeRTOS task, `xTaskGetCurrentTaskHandle()` returns 0, and in general I'm seeing `xSemaphoreGetMutexHolder(self->lock_mutex)` return 0 during initialization (as apparently no tasks have claimed the mutex). This clearly leads to the hard_assert to fire when calling `async_context_freertos_execute_sync` outside of a FreeRTOS task. Is this intentional? I'm also not 100% sure what that `hard_assert` is checking. Is it to catch some sort of recursive calling/deadlock (although I don't see that mutex being claimed during init-- maybe it is in other execution paths?)?
gemarcano commented 2023-11-09 01:06:19 -06:00 (Migrated from github.com)

After some more experimentation, the implementation of async_context_freertos_* functions, which are called by cyw43_arch_init, assume that they are taking place within the context of an already running FreeRTOS. For example, async_context_freertos_execute_sync calls xQueueSemaphoreTake near its end, and that in turn calls vTaskPlaceOnEventList, which implicitly assumes the current thread is running within FreeRTOS.

Per the documentation on async_context_execute_sync I think I understand what the hard_assert is checking against-- it is very clear in the documentation that the context's lock should not be held by whoever is calling execute_sync, so it's just checking against that.

So it does look like this behavior is intentional-- it might be a good idea to document that when using the FreeRTOS async_context, cyw43* functions should be called within a FreeRTOS task.

edit: and possibly also async_context_freertos functions.

After some more experimentation, the implementation of `async_context_freertos_*` functions, which are called by `cyw43_arch_init`, assume that they are taking place within the context of an already running FreeRTOS. For example, `async_context_freertos_execute_sync` calls `xQueueSemaphoreTake` near its end, and that in turn calls `vTaskPlaceOnEventList`, which implicitly assumes the current thread is running within FreeRTOS. Per the documentation on `async_context_execute_sync` I think I understand what the `hard_assert` is checking against-- it is very clear in the documentation that the context's lock should not be held by whoever is calling `execute_sync`, so it's just checking against that. So it does look like this behavior is intentional-- it might be a good idea to document that when using the FreeRTOS async_context, `cyw43*` functions should be called within a FreeRTOS task. edit: and possibly also `async_context_freertos` functions.
peterharperuk commented 2023-11-09 05:48:01 -06:00 (Migrated from github.com)

Yes, you're probably right - it needs to be documented.

I've successfully managed to convert the NTP client example Pico W example from its original LwIP raw API form to one using NO_SYS=0 FreeRTOS SMP and the LwIP socket API.

I was thinking the other day that we really need more examples of this. Any chance of contributing this to pico-examples?

Yes, you're probably right - it needs to be documented. > I've successfully managed to convert the NTP client example Pico W example from its original LwIP raw API form to one using NO_SYS=0 FreeRTOS SMP and the LwIP socket API. I was thinking the other day that we really need more examples of this. Any chance of contributing this to pico-examples?
gemarcano commented 2023-11-16 02:19:25 -06:00 (Migrated from github.com)

Sure, I've submitted a draft example based on my code. My own personal code was all in C++, so it took a bit but I managed to get it back to C.

Sure, I've submitted a draft example based on my code. My own personal code was all in C++, so it took a bit but I managed to get it back to C.
peterharperuk commented 2024-11-12 07:58:43 -06:00 (Migrated from github.com)

Is there anything to do here? We added the ping example. Just a documentation issue perhaps?

Is there anything to do here? We added the ping example. Just a documentation issue perhaps?
gemarcano commented 2024-11-27 21:10:41 -06:00 (Migrated from github.com)

Yes, I think it's just documentation stating that when using the FreeRTOS async_context, cyw43* functions should be called within a FreeRTOS task. Or something to that effect.

Yes, I think it's just documentation stating that when using the FreeRTOS async_context, cyw43* functions should be called within a FreeRTOS task. Or something to that effect.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#1540
No description provided.