-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
No LDREX/STREX-based implementations of __cxa_guard_acquire/release/abort in ARM code? #1393
Comments
I might reopen this, but I will think a little more about it first. |
Reopening, after a little more thinking. So my questions above stand. |
Hi @amosnier, I guess the most important aspect is that CMSIS is still pure C code and does not contain any C++ related content so far. Now, we need to set the scene to sort your request. Am I right that you are looking for using CMSIS-RTOS2 in an C++ environment? E.g., by using a concrete implementation of this RTOS-API like the reference implementation RTX5? Cheers, |
Hi @JonatanAntoni, Thanks for taking the time to answer. In my use case, an RTOS is available, although it does not implement the CMSIS-RTOS2 interface. Assuming that an RTOS is used, if static object creation is only performed once the RTOS has started, a Additionally, in a typical C++ embedded application using an RTOS, in the general case, it is likely that most objects, but not necessarily all of them, will be constructed before the RTOS is started, at a time when OS-mutexes are not available for locking. But that is obviously not what the ARM C++ ABI refers to, when it says:
and
If I understand this correctly, and LLVM's general implementation of It seems to me that we have two quite different solutions, one which relies on the RTOS and one which is completely independent of any RTOS, and which, according to ARM themselves, could be based on ARM SWP and LDREX/STREX, instructions which I guess are available on all ARM cores. Both have benefits and drawbacks:
To link back to my original questions, it seems to me that a common implementation based on ARM SWP and LDREX/STREX could be provided by ARM. For the sake of completion, I guess I should add that because of the Static Initialization Order Fiasco, and because declaring static objects in functions does not really solve the whole issue, static object creation of non-POD types should be frowned upon, so in an ideal application, one could choose to generate a compilation error if Best regards, Alain Mosnier |
Hi Alain, To be honest, I don't see how your request could be addressed in terms of CMSIS. Using RTOS-based solution requires at least some knowledge about the RTOS API. I cannot imagine how a solution that is totally independent from the used RTOS could work. If I got your requirement correctly, it is about thread-safeness when function-local static objects are initialized. Calling a function with a function-local static object before the RTOS scheduler has been launched should always be safe. But calling it from different thread contexts concurrently could cause issues. Lets say thread A calls such a function first and the static object initialization is started. Now, the initialization is interrupted and the scheduler switches to thread B. Thread B calls the same function. Now, the static object cannot be used as it is not fully initialized, yet. But thread B must not start to initialize the object itself (again). Instead thread B would need to wait for thread A to complete object initialization before executing the function. The only way to achive this is by using some RTOS synchronization mechanism (semaphore, mutex, event). I don't understand how busy waiting would work in this case. Hence, I don't see how one might use LDREX/STREX or SWP instructions in this scenario. Cheers, |
Hi @amosnier, A default implementation of these guards is part of LLVM, you can find the implementation here: https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_guard.cpp Having this discussed with some Compiler experts I still don't see how an RTOS-independent solution could work. The LLVM implementation contains a variant using a global mutex plus global conditional variable. I think a similar implementation could be done for a specific RTOS used. Cheers, |
Hi @JonatanAntoni, You wrote:
But ARM also specifies (C++ ABI for the ARM architecture):
and:
So my question is: in what scenarios does ARM mean that static object initialization guard variables should be "the target of ARM SWP or LDREX and STREX instructions", and why would CMSIS not include a reference implementation of those principles? As a side note, the ARM® Synchronization Primitives article includes several OS-independent thread synchronization primitives, a mutex among others, based on LDREX/STREX. I do not think any of them should be used directly to guard static object initialization, and they are probably sub-optimal for general purposes if an OS is available, but the article still shows that OS-independent thread synchronization based on LDREX/STREX is achievable. Best regards, Alain Mosnier |
Hi @amosnier, The C++ ABI might be missleading, here. But I am not an expert in this area and as I already stated CMSIS is C software. This is why CMSIS does not contain C++ implementations, yet. RTX5 for instance makes use of LDREX/STREX instructions to achieve atomicity of its synchronization primitives. But these implementations are clearly RTX5 specific and not OS-independent. Sorry, if this is not the answer you were looking for. Cheers, |
Hi @JonatanAntoni, You wrote
Since we are talking about a major interface specification, we would have to report such an issue to the group who maintains it, right? What is the procedure for that? For the record, I in fact do not think that the ABI documentation is misleading. My feeling is that the group who wrote it knows exactly what they are talking about, and even have a solution in mind. Maybe they could just tell us?
The functions are declared Best regards, Alain Mosnier |
Hi @amosnier, you could try to address this in the Arm Community. Cheers, |
Hi @JonatanAntoni, You wrote
Since you think you have found some misleading guidance in a major ARM specification, I trust you will report that as an issue with the group responsible for maintaining it. Since I expect that they in fact have a precise idea of how an implementation of the
Sure I can submit this question to them too. Best regards, Alain Mosnier |
Hi @JonatanAntoni, |
If anyone reads this and is interested, they might also be interested by a related ARM community discussion. |
From C++ ABI for the ARM architecture, ARM IHI 0041D:
extern "C" int __cxa_guard_acquire(int *guard_object);
extern "C" void __cxa_guard_release(int *guard_object);
extern "C" void __cxa_guard_abort(int *guard_object);
Is my interpretation correct that only one bit of the
obj_guard
variable is accessed at all by the code that provides it (the code that invokes the__cxa_guard_xxx
functions), and that because the rest is unused, theobj_guard
variable itself could be used for the semaphore implementation?If that is the case, and I certainly hope so, since an alternative implementation would have to "manually" allocate semaphore memory on the side of every static variable, which would be quite cumbersome (or would have to use some kind of recursive mutex that would handle the case when the OS is not started, but not everyone has that kind of luxury), how come the following search on the CMSIS_5 repository gives no result in source code?
$ git grep __cxa_guard_acquire
I mean, if there is a possibly trivial implementation based on the ABI documentation (of the three functions), why would ARM themselves not provide it? Or is it provided in some other repository? I made such an implementation myself, but seeing naive non-thread-safe implementations all over the Internet (which systematically break C++ static object creation semantics!) really makes me wonder whether we are not missing a great opportunity of improving many embedded C++ applications with a small effort.
What am I missing?
The text was updated successfully, but these errors were encountered: