Discussion:
[avr-libc-dev] C11 Atomics and GCC libatomic
Jacob Moroni
2016-06-24 14:21:23 UTC
Permalink
Hello,



After the C11 spec was finalized, GCC added a bunch of new built-in
“__atomic_X” functions to replace the older “__sync_” functions. These
atomic functions are generally used by <stdatomic.h> headers, as they were
designed to adhere to the C11 memory model, but there’s nothing preventing
their use in "regular" code. These built-ins are rather convenient, as they
allow for atomic manipulations of regular data types, which is useful when
dealing with data which is shared between threads (or the main program and
an ISR in the case of an MCU). With these functions, it would no longer be
necessary to declare shared global variables as “volatile”, and it would no
longer be necessary to explicitly disable and re-enable interrupts when
dealing with types larger than the native word size.



Currently, these “__atomic_X” functions (as well as the older “__sync_”
counterparts) are not supported on the AVR.



When the atomic operations aren’t natively implemented by GCC on a specific
platform (either due to hardware limitations or because GCC just hasn’t
implemented them yet), GCC automatically converts calls to the built-in
“__atomic_X” functions into regular function calls which are to be resolved
by an external library. This library is called “libatomic” and is supposed
to implement the required routines in a way which is specific to the target
platform (perhaps using locks or disabling interrupts). The issue is that
no such library exists for the AVR, so any use of the “__atomic_X”
functions ultimately results in undefined references at link time.



The reason I’m posting here is because I’ve created a libatomic library for
the AVR. In reality, it’s just a single C file which implements the
required “__atomic_X” functions by means of saving/disabling interrupts,
performing the operation, then restoring interrupts.



With this library, I was also able to include a portable version of the
<stdatomic.h> header which allows for the successful use of C11 atomic
types!



I would like to get this merged into avr-libc, as it seems to be the most
sensible place for it (I think). However, I’m not familiar with the
process, coding requirements, etc…



I am willing to release it under whatever license is required, which I
assume would be BSD. This would be good also because the portable
<stdatomic.h> header file that I used is already BSD licensed.

By implementing the libatomic library and (optionally) including a
<stdatomic.h> header, we would support a fully portable way of dealing with
atomic types, which I think would be a good thing.



Do you think this is the right place for such an implementation? If not,
could you direct me?

I'm not familiar with the general development process here, so forgive me
if I'm out of line.



Jake
Markus Hitter
2016-06-24 16:02:34 UTC
Permalink
With this library, I was also able to include a portable version of the <stdatomic.h> header which allows for the successful use of C11 atomic types!
I would like to get this merged into avr-libc
What's wrong with the atomic macros already existing?

http://www.nongnu.org/avr-libc/user-manual/atomic_8h.html

A function call is rather heavyweight for something as simple as locking
interrupts.

As the above macros require C99, Teacup Firmware created a similar macro
set working on C89, too:

https://github.com/Traumflug/Teacup_Firmware/blob/master/memory_barrier.h


Markus
--
- - - - - - - - - - - - - - - - - - -
Dipl. Ing. (FH) Markus Hitter
http://www.jump-ing.de/
Martin McKee
2016-06-24 19:43:39 UTC
Permalink
I don't comment often, but...

There are, for C++ work, a number of advantages to supporting the
standardized atomic types. And, we *are* talking here about C++ support
rather than C support, which is rather more lacking in avr-lib-c. Besides
making code more portable, the standard atomics library works in a well
quantified manner and is, thus, safer for someone that moves between
different platforms. Plus, the C++ standard atomic functionality has a
much wider range of granularity than the current avr-libc atomic header.
It is possible to protect blocks of code, but, moreover, atomic types allow
for *type-safe* atomic access to single values with only minimal periods of
interrupts being disabled. Granted, this is entirely possible with a block
critical section, but the code is much more complicated than the direct
value access of the "atomic type."

Finally, the C++ atomics are typically, and this is what Jacob is
describing above, I believe, implemented with a combination of compiler
intrensics and template metaprogramming. The result is that there is no
function call. The code is inlined, just like a macro. As such, there is
no additional cost

I for one would welcome this as an addition to the current library.

Martin Jay McKee
Post by Markus Hitter
Post by Jacob Moroni
With this library, I was also able to include a portable version of the
<stdatomic.h> header which allows for the successful use of C11 atomic
types!
I would like to get this merged into avr-libc
What's wrong with the atomic macros already existing?
http://www.nongnu.org/avr-libc/user-manual/atomic_8h.html
A function call is rather heavyweight for something as simple as locking
interrupts.
As the above macros require C99, Teacup Firmware created a similar macro
https://github.com/Traumflug/Teacup_Firmware/blob/master/memory_barrier.h
Markus
--
- - - - - - - - - - - - - - - - - - -
Dipl. Ing. (FH) Markus Hitter
http://www.jump-ing.de/
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Jacob Moroni
2016-06-24 20:59:38 UTC
Permalink
To Markus:



I agree that a function call is a fair amount of overhead, especially in
the case of single byte operations.



The intent wasn’t to eliminate or discourage the use of the existing atomic
macros, but rather to provide support for compiling code which uses the
portable C11 atomics (or the somewhat portable GCC __atomic_X functions
directly). Routines which require absolute speed and efficiency would still
be best suited using the existing macros, but I think providing support for
the standard/GCC atomics could be useful. There are some routines such as
“__atomic_compare_exchange” [1] which are pretty convenient since you can
use the result as an expression. To accomplish the same task using the
existing macros would require you to end up implementing a function anyway
in many cases. Another (slight) advantage of using a function call is that
it prevents operations on register-stored variables from “leaking” into the
atomic block and causing interrupts to be disabled for a longer time than
expected [2].



Also, on a somewhat related note, I think there may be a bug in the
<avr/atomic.h> header, specifically, in the “__iRestore” function which is
called to restore the interrupt state after the atomic block is finished.
There’s currently a memory barrier after SREG is restored, but I think the
barrier should be before in order to ensure that any pending stores are
completed _before_ restoring the interrupt state. If the barrier is after,
I’m not sure if there’s anything preventing operations on non-volatile
variables from being reordered with respect to the restoring of SREG.



It’s likely that this problem has never been encountered in the field
because the common practice is to declare all shared globals as “volatile”,
which therefore prevents accesses to them from being reordered with respect
to access of SREG, but it seems like a possible issue to me.



If you agree, I can submit a bug report or even make the fix myself once I
figure out the process of sending in a patch. This is actually my first
time participating in any type of collaborative open source project!



[1] https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html



[2]
http://www.atmel.com/webdoc/AVRLibcReferenceManual/optimization_1optim_code_reorder.html





To Martin:



In this case, I was talking specifically about the C11 atomics that are
defined in <stdatomic.h> rather than the C++11 atomics which I believe are
defined in <atomic>. There is also another header in C++ called
<cstdatomic> which is apparently the C++ version of the C11 atomic header.
That being said, the proposed library implements the backend support
required for all of these headers, so they could likely all be implemented
(or grabbed from any other license compliant source) if need be, and I
would be glad to do it if you think it would be useful.



I still have some more testing to do involving the library, but I will post
it on my Github within the next day or so. If the higher powers agree to
accept this contribution, they can either grab it from my Github or I can
send it in. I will just need some guidance as to how to officially submit a
patch/contribution. While I’m not new at programming, I am new to the whole
“contributing to open source software” thing!



- Jake
Post by Martin McKee
I don't comment often, but...
There are, for C++ work, a number of advantages to supporting the
standardized atomic types. And, we *are* talking here about C++ support
rather than C support, which is rather more lacking in avr-lib-c. Besides
making code more portable, the standard atomics library works in a well
quantified manner and is, thus, safer for someone that moves between
different platforms. Plus, the C++ standard atomic functionality has a
much wider range of granularity than the current avr-libc atomic header.
It is possible to protect blocks of code, but, moreover, atomic types allow
for *type-safe* atomic access to single values with only minimal periods of
interrupts being disabled. Granted, this is entirely possible with a block
critical section, but the code is much more complicated than the direct
value access of the "atomic type."
Finally, the C++ atomics are typically, and this is what Jacob is
describing above, I believe, implemented with a combination of compiler
intrensics and template metaprogramming. The result is that there is no
function call. The code is inlined, just like a macro. As such, there is
no additional cost
I for one would welcome this as an addition to the current library.
Martin Jay McKee
Post by Markus Hitter
Post by Jacob Moroni
With this library, I was also able to include a portable version of the
<stdatomic.h> header which allows for the successful use of C11 atomic
types!
I would like to get this merged into avr-libc
What's wrong with the atomic macros already existing?
http://www.nongnu.org/avr-libc/user-manual/atomic_8h.html
A function call is rather heavyweight for something as simple as locking
interrupts.
As the above macros require C99, Teacup Firmware created a similar macro
https://github.com/Traumflug/Teacup_Firmware/blob/master/memory_barrier.h
Post by Markus Hitter
Markus
--
- - - - - - - - - - - - - - - - - - -
Dipl. Ing. (FH) Markus Hitter
http://www.jump-ing.de/
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Martin McKee
2016-06-25 03:43:25 UTC
Permalink
Yes, I realize that we're not talking about <atomic>, but, rather the
backend. But, really, my point is that it becomes fairly easy to go all
the way ( if desired ) once the backend is in place.

Martin Ja McKee
Post by Jacob Moroni
I agree that a function call is a fair amount of overhead, especially in
the case of single byte operations.
The intent wasn’t to eliminate or discourage the use of the existing
atomic macros, but rather to provide support for compiling code which uses
the portable C11 atomics (or the somewhat portable GCC __atomic_X functions
directly). Routines which require absolute speed and efficiency would still
be best suited using the existing macros, but I think providing support for
the standard/GCC atomics could be useful. There are some routines such as
“__atomic_compare_exchange” [1] which are pretty convenient since you can
use the result as an expression. To accomplish the same task using the
existing macros would require you to end up implementing a function anyway
in many cases. Another (slight) advantage of using a function call is that
it prevents operations on register-stored variables from “leaking” into the
atomic block and causing interrupts to be disabled for a longer time than
expected [2].
Also, on a somewhat related note, I think there may be a bug in the
<avr/atomic.h> header, specifically, in the “__iRestore” function which is
called to restore the interrupt state after the atomic block is finished.
There’s currently a memory barrier after SREG is restored, but I think the
barrier should be before in order to ensure that any pending stores are
completed _before_ restoring the interrupt state. If the barrier is after,
I’m not sure if there’s anything preventing operations on non-volatile
variables from being reordered with respect to the restoring of SREG.
It’s likely that this problem has never been encountered in the field
because the common practice is to declare all shared globals as “volatile”,
which therefore prevents accesses to them from being reordered with respect
to access of SREG, but it seems like a possible issue to me.
If you agree, I can submit a bug report or even make the fix myself once I
figure out the process of sending in a patch. This is actually my first
time participating in any type of collaborative open source project!
[1] https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
[2]
http://www.atmel.com/webdoc/AVRLibcReferenceManual/optimization_1optim_code_reorder.html
In this case, I was talking specifically about the C11 atomics that are
defined in <stdatomic.h> rather than the C++11 atomics which I believe are
defined in <atomic>. There is also another header in C++ called
<cstdatomic> which is apparently the C++ version of the C11 atomic header.
That being said, the proposed library implements the backend support
required for all of these headers, so they could likely all be implemented
(or grabbed from any other license compliant source) if need be, and I
would be glad to do it if you think it would be useful.
I still have some more testing to do involving the library, but I will
post it on my Github within the next day or so. If the higher powers agree
to accept this contribution, they can either grab it from my Github or I
can send it in. I will just need some guidance as to how to officially
submit a patch/contribution. While I’m not new at programming, I am new to
the whole “contributing to open source software” thing!
- Jake
Post by Martin McKee
I don't comment often, but...
There are, for C++ work, a number of advantages to supporting the
standardized atomic types. And, we *are* talking here about C++ support
rather than C support, which is rather more lacking in avr-lib-c. Besides
making code more portable, the standard atomics library works in a well
quantified manner and is, thus, safer for someone that moves between
different platforms. Plus, the C++ standard atomic functionality has a
much wider range of granularity than the current avr-libc atomic header.
It is possible to protect blocks of code, but, moreover, atomic types allow
for *type-safe* atomic access to single values with only minimal periods of
interrupts being disabled. Granted, this is entirely possible with a block
critical section, but the code is much more complicated than the direct
value access of the "atomic type."
Finally, the C++ atomics are typically, and this is what Jacob is
describing above, I believe, implemented with a combination of compiler
intrensics and template metaprogramming. The result is that there is no
function call. The code is inlined, just like a macro. As such, there is
no additional cost
I for one would welcome this as an addition to the current library.
Martin Jay McKee
Post by Markus Hitter
Post by Jacob Moroni
With this library, I was also able to include a portable version of the
<stdatomic.h> header which allows for the successful use of C11 atomic
types!
I would like to get this merged into avr-libc
What's wrong with the atomic macros already existing?
http://www.nongnu.org/avr-libc/user-manual/atomic_8h.html
A function call is rather heavyweight for something as simple as locking
interrupts.
As the above macros require C99, Teacup Firmware created a similar macro
https://github.com/Traumflug/Teacup_Firmware/blob/master/memory_barrier.h
Post by Markus Hitter
Markus
--
- - - - - - - - - - - - - - - - - - -
Dipl. Ing. (FH) Markus Hitter
http://www.jump-ing.de/
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
David Brown
2016-06-26 18:24:00 UTC
Permalink
Post by Jacob Moroni
Also, on a somewhat related note, I think there may be a bug in the
<avr/atomic.h> header, specifically, in the “__iRestore” function which is
called to restore the interrupt state after the atomic block is finished.
There’s currently a memory barrier after SREG is restored, but I think the
barrier should be before in order to ensure that any pending stores are
completed _before_ restoring the interrupt state. If the barrier is after,
I’m not sure if there’s anything preventing operations on non-volatile
variables from being reordered with respect to the restoring of SREG.
It has been a while since I looked at such things in detail, and I don't
have the appropriate references conveniently available at the moment.
But if I remember correctly, the change to the interrupt status is
delayed in hardware for an instruction, so that it is safe to re-enable
interrupts (restore the SREG) and then have the memory barrier.
Post by Jacob Moroni
It’s likely that this problem has never been encountered in the field
because the common practice is to declare all shared globals as “volatile”,
which therefore prevents accesses to them from being reordered with respect
to access of SREG, but it seems like a possible issue to me.
If you agree, I can submit a bug report or even make the fix myself once I
figure out the process of sending in a patch. This is actually my first
time participating in any type of collaborative open source project!
Georg-Johann Lay
2016-06-25 20:35:22 UTC
Permalink
Post by Jacob Moroni
Hello,
After the C11 spec was finalized, GCC added a bunch of new built-in
“__atomic_X” functions to replace the older “__sync_” functions. These
atomic functions are generally used by <stdatomic.h> headers, as they were
designed to adhere to the C11 memory model, but there’s nothing preventing
their use in "regular" code. These built-ins are rather convenient, as they
allow for atomic manipulations of regular data types, which is useful when
dealing with data which is shared between threads (or the main program and
an ISR in the case of an MCU). With these functions, it would no longer be
necessary to declare shared global variables as “volatile”, and it would no
longer be necessary to explicitly disable and re-enable interrupts when
dealing with types larger than the native word size.
Currently, these “__atomic_X” functions (as well as the older “__sync_”
counterparts) are not supported on the AVR.
When the atomic operations aren’t natively implemented by GCC on a specific
platform (either due to hardware limitations or because GCC just hasn’t
implemented them yet), GCC automatically converts calls to the built-in
“__atomic_X” functions into regular function calls which are to be resolved
by an external library. This library is called “libatomic” and is supposed
to implement the required routines in a way which is specific to the target
platform (perhaps using locks or disabling interrupts). The issue is that
no such library exists for the AVR, so any use of the “__atomic_X”
functions ultimately results in undefined references at link time.
The reason I’m posting here is because I’ve created a libatomic library for
the AVR. In reality, it’s just a single C file which implements the
required “__atomic_X” functions by means of saving/disabling interrupts,
performing the operation, then restoring interrupts.
With this library, I was also able to include a portable version of the
<stdatomic.h> header which allows for the successful use of C11 atomic
types!
I would like to get this merged into avr-libc, as it seems to be the most
sensible place for it (I think). However, I’m not familiar with the
process, coding requirements, etc…
huh? libatomic is part of GCC, see

http://gcc.gnu.org/viewcvs/gcc/trunk/libatomic/

So the patches should go to GCC's gcc-patches mailing list.

libatomic is currently not built for avr simply because there are no
target specific bits in libatomic/config/avr.
Post by Jacob Moroni
I am willing to release it under whatever license is required, which I
assume would be BSD. This would be good also because the portable
<stdatomic.h> header file that I used is already BSD licensed.
By implementing the libatomic library and (optionally) including a
<stdatomic.h> header, we would support a fully portable way of dealing with
atomic types, which I think would be a good thing.
Do you think this is the right place for such an implementation? If not,
could you direct me?
I'm not familiar with the general development process here, so forgive me
if I'm out of line.
Jake
As libatomic will need close cooperation with the compiler, I'd
recommend to add it to GCC.


Johann
Joerg Wunsch
2016-06-25 21:13:03 UTC
Permalink
Post by Georg-Johann Lay
As libatomic will need close cooperation with the compiler, I'd
recommend to add it to GCC.
That would be my recommendation, too. If it's a compile feature,
it would better be there. Perhaps it's then even possible to find
a more efficient implementation (no function call overhead).
--
cheers, Joerg .-.-. --... ...-- -.. . DL8DTL

http://www.sax.de/~joerg/
Never trust an operating system you don't have sources for. ;-)
Jacob Moroni
2016-06-25 21:54:35 UTC
Permalink
Got it. I'll add the support to GCC's libatomic then send it in. Thanks.
Post by Joerg Wunsch
Post by Georg-Johann Lay
As libatomic will need close cooperation with the compiler, I'd
recommend to add it to GCC.
That would be my recommendation, too. If it's a compile feature,
it would better be there. Perhaps it's then even possible to find
a more efficient implementation (no function call overhead).
--
cheers, Joerg .-.-. --... ...-- -.. . DL8DTL
http://www.sax.de/~joerg/
Never trust an operating system you don't have sources for. ;-)
_______________________________________________
AVR-libc-dev mailing list
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Georg-Johann Lay
2016-06-26 15:15:05 UTC
Permalink
Post by Jacob Moroni
Got it. I'll add the support to GCC's libatomic then send it in. Thanks.
Here is some introduction on contributing to GCC:

http://gcc.gnu.org/contribute.html

As it is hard to follow discussions in top-posting style, that style is
usually voided :-)

https://en.wikipedia.org/wiki/Posting_style#Top-posting
Post by Jacob Moroni
Post by Joerg Wunsch
Post by Georg-Johann Lay
As libatomic will need close cooperation with the compiler, I'd
recommend to add it to GCC.
That would be my recommendation, too. If it's a compile feature,
it would better be there. Perhaps it's then even possible to find
a more efficient implementation (no function call overhead).
cheers, Joerg .-.-. --... ...-- -.. . DL8DTL
There are quite some standard insns for atomics known to gcc, cf.
"atomic_" insns in

http://gcc.gnu.org/onlinedocs/gccint/Standard-Names.html

This can avoid overhead of function calls. But I still don't see the
great advantage of using stdatomic over the "classical" util/atomic.h
from avr-libc. For C++ we don't have portability because there is no
libstdc++ generated for avr, not even libsupc++...

Johann
David Brown
2016-06-26 18:32:20 UTC
Permalink
Post by Georg-Johann Lay
There are quite some standard insns for atomics known to gcc, cf.
"atomic_" insns in
http://gcc.gnu.org/onlinedocs/gccint/Standard-Names.html
This can avoid overhead of function calls. But I still don't see the
great advantage of using stdatomic over the "classical" util/atomic.h
from avr-libc. For C++ we don't have portability because there is no
libstdc++ generated for avr, not even libsupc++...
Johann
The "classical" atomic locks in util/atomic.h are for constructing
critical sections - sections of code that can only be accessed by one
context of execution at a time. The stdatomic C11 and C++ atomics are
for atomic data - variables that are accessed atomically regardless of
contexts. These are two different ways of looking at atomic accesses
and correct interrupt or multi-threaded programming. While either can
be used to implement the other, they do not replace each other - the
best choice depends on the type of code and the type of problem to be
solved at the time.

Additionally, it is always good to implement standard solutions - it
makes it a lot easier to write code that can be portable between
different architectures. So implementing the C11 and C++11 atomics
helps make avr-gcc a better tool.

avr-gcc supports a fair amount of C++, even though there are many parts
missing (last I looked, which was a good while ago, support for
exceptions was missing). People use C++ on the avr, and it makes a lot
of sense to support as many features of the latest C++ standards as can
conveniently be done. Of course there are many things in C++ that would
be disproportionately hard to support on the AVR, and are unlikely to be
much used - but if C++11 atomics can be supported "for free" by Jacob's
functions added to libatomic to support C11 atomics, then that is a
great thing.

mvh.,

David

Loading...