-
Notifications
You must be signed in to change notification settings - Fork 948
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
Add condition variables to pico_sync (fixes #1093) #1101
base: develop
Are you sure you want to change the base?
Conversation
I'm just a contributor so please take this with a "pinch of salt" and I suggest waiting for someone with authority before acting on any of this. First of all, if this is to be called a condition variable module, I think it would be reasonable for an SDK user to expect it to also include a cond_broadcast() or similarly named function that signals all waiting threads. If an RTOS is in use, there could be >1 waiting threads. I appreciate that implementing cond_broadcast() is a challenge in the context of the SDK, in part because there is nothing resembling a thread control block that could be used to efficiently implement a linked list of threads waiting for a particular condition variable. I have two suggestions. My first suggestion is a (hopefully) upcoming thread local variable module for the SDK, which essentially provides a thread control block by another name. My second suggestion is to add a broadcast_count variable to cond_t, which atomically increments whenever cond_broadcast() is called. I've never implemented condition variables this way and I wonder if it's flawed but I think it might give waiting threads enough information to all wake up on broadcast:
Finally, I think there are some issues with condition variables as implemented. There are three cases where cond_wait() blocks by calling lock_internal_spin_unlock_with_wait():
I use the term "blocked" here, and in the operating system sense, because that is exactly what will happen when an RTOS is in use: the calling thread will transition to a blocked state. In order to transition the thread out of the blocked state, another thread must call lock_internal_spin_unlock_with_notify(). Of the three, case 1 is covered by the call to lock_internal_spin_unlock_with_notify() in cond_signal() and I believe this case is fully covered. I think there are issues with cases 2 and 3 though. In case 2, I there's no notification when cond->waiter becomes LOCK_INVALID_OWNER_ID so a thread waiting to become the current waiter might never wake up. Case 3 is partially covered by the call to lock_internal_spin_unlock_with_notify() in mutex_exit(). However, code in cond_wait() also releases the mutex by bypassing the public mutex API and setting mtx->owner = LOCK_INVALID_OWNER_ID. So, like case 2, a thread waiting for the mutex to be released might never wake up. |
Thank you.
|
Perhaps it's slightly less efficient but I think cond_wait() is clearer refactored like this. I haven't attempted to fix any of the issues I mentioned above.
|
58fa5fb
to
26d7860
Compare
@alastairpatrick Thank you for your feedback. I eventually implemented broadcast as well as timed waits. |
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Thanks for the update; I haven't really had a chance to look at this in detail; I do note however that the latest commit uses "_sev()" in some path which is not valid under a RTOS (it is what |
@kilograham Thank you for this feedback. The |
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
23c4cb5
to
653b354
Compare
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Also slightly modify SMP code to handle the specific case of the Pico. Code relies on condition variables implementation proposed in this upstream PR: raspberrypi/pico-sdk#1101 Signed-off-by: Paul Guyot <pguyot@kallisys.net>
653b354
to
f593b3a
Compare
@kilograham this was rebased on top of SDK 2.0 and tested on RP2040, RP2350 ARM and RP2350 RISCV. |
This PR provides condition variables as companion to mutexes.
It is implemented without any assumption on the number of cores.
Like mutexes, condition variables are protected by a spinlock. Because the spinlock could be the same as the one used by the associated mutex, the two cases are implemented to avoid a deadlock trying to acquire the two spinlocks.
When waiting on a condition variable, a core tries to be the waiter (=owner) and when it is, it waits to be signaled.
When signaling a condition variable, the caller verifies that there is a waiter, and if there is, sets a boolean to signal it.
This busy-loop implementation seems to be immune from spurious wakeup.