-
Notifications
You must be signed in to change notification settings - Fork 2k
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
sys/tsrb is not thread safe #9882
Comments
This issue was raised while reviewing #9869 . |
Reality, as usual, is a little more differentiated.
Our sweet little MCU's rely heavily on memory-mapped hardware registers. In order for them to work properly, accesses to volatile, word-aligned and word-sized data must use single-instruction load/stores. So much code depends on this that what the C standard doesn't matter here. That said, it would be nicer (and necessary for AVR) to wrap the reads and writes in explicit per-architecture inline assembly. Linux's "io.h" has @jcarrano As you seem interested in this topic, I'll assign to you. |
@jcarrano ping I've changed the issue title to more reflect the current state. Feel free to add architectures if you can show the compilers don't emit the correct load/stores. |
@gschorcht maybe you know how the ESP compilers behave here? |
I't not about showing (the absence of) certain behavior, but of conforming to the published specifications, be it the C standard or the compiler's manual. Showing that something works in a particular instance is not a proof. This is how stuff "gets broken" when one tries to use new compilers or new versions of the same compiler. It is because people do things that are not OK but "worked every time I tried it". See for example the instances of function-pointer casts. In a more general way, it is also how stuff gets broken on more advanced CPUs that can reorder memory accesses.
Why? How do 8-bit MCU's work with 32 or 16-bit registers in peripherals then? Here's how: each byte is written in a predefined order, such that the last write, to the high or low bytes, triggers whatever action in the peripheral. The whole sequence still consists of 2 or 4 stores, but is usually not a problem because there is one thread accessing the peripheral. Many of these issues were brought forward by @josephnoir in #4700. I will continue with this after the Summit but, since I'm not using this module myself, understand that it is not a priority for me. |
Conforming to the standard is not our goal. Correctly working code is. Standards are not more than a tool. See this old, but related paper or this blog entry about compilers that don't necessarily conform to standards, anyways. Showing that some code is standard-conformant is not a proof that the result is working either. How about we stop waving standards or opinions and try to find actual issues, and fix them? ("standard doesn't guarantee correctness", to me, has at most very low priority as an issue if the generated assembly does what it is supposed to do and we can reasonably expect that not to change anytime in the near future.) |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
still an issue |
There is no guarantee, that I doubt that compiler developers will have any seconds thoughts about breaking RIOT, if they feel their interpretation of the C standard is correct and ours is not. Thus, we should make sure to perform atomic accesses where needed, rather than using Btw: Has anyone checked if just making |
Lines 22 to 25 in 78f8cef
Here is another issue: The actual order of the stores (incrementing |
Description
The "Thread-safe ringbuffer" is not actually thread safe.
Thread safety in this module depends upon reads and writes to
unsigned int
being atomic. C99 makes no guarantees with respect to atomicity (and they are probably NOT atomic in 8-bit platforms).To fix this, access to these variables should be wrapped in a
save interrupt mask/restore interrupt mask
block. Alternatively, for architectures that support it, anasm
statement can be used to ensure a single-cycle uninterruptible operation.Steps to reproduce the issue
The text was updated successfully, but these errors were encountered: