Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
gemarcano opened this issue Nov 9, 2023 · 3 comments

Comments

@gemarcano
Copy link

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?)?

@gemarcano
Copy link
Author

gemarcano commented Nov 9, 2023

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
Copy link
Contributor

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants