Atomic API proposal

I’ve done a lot of research, looked over Bob’s excellent analysis, and
looked at some practical examples of lockless programming (scary stuff,
don’t do it!), and I think I’ve come up with an API that more closely
matches the use cases.

I’d love to get feedback on this proposal…

(All these functions are full memory barriers)

/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;

/* Set an atomic variable to a value, returning the previous value */
int SDL_AtomicSet(SDL_atomic_t *a, int value);

/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);

/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);

/* Increment an atomic variable used as a reference count */
void SDL_AtomicIncRef(SDL_atomic_t *a);

/* Decrement an atomic variable used as a reference count,
returning SDL_TRUE if the variable has reached zero after decrementing
*/
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a);

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

/* Set a pointer to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);–
-Sam Lantinga, Founder and President, Galaxy Gameworks LLC

Looks interesting, but I’ve gotta agree with the guy (I forget who) who asked
for a compile flag to leave this out. There’s a surprising amount of general,
non-multimedia-related stuff in SDL that’s basically an exact duplicate of
functionality I already have available in the Delphi standard libraries, and
this is one example.________________________________
From: slouken@libsdl.org (slouken)
To: SDL
Sent: Fri, January 14, 2011 3:10:02 PM
Subject: [SDL] Atomic API proposal

I’ve done a lot of research, looked over Bob’s excellent analysis, and looked at
some practical examples of lockless programming (scary stuff, don’t do it!), and
I think I’ve come up with an API that more closely matches the use cases.

I’d love to get feedback on this proposal…

(All these functions are full memory barriers)

/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;

/* Set an atomic variable to a value, returning the previous value */
int SDL_AtomicSet(SDL_atomic_t *a, int value);

/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);

/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);

/* Increment an atomic variable used as a reference count */
void SDL_AtomicIncRef(SDL_atomic_t *a);

/* Decrement an atomic variable used as a reference count,
returning SDL_TRUE if the variable has reached zero after decrementing
*/
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a);

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

/* Set a pointer to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);


-Sam Lantinga, Founder and President, Galaxy Gameworks LLC

Hello,On 2011?01?15? 00:18, Mason Wheeler wrote:

Looks interesting, but I’ve gotta agree with the guy (I forget who) who
asked for a compile flag to leave this out. There’s a surprising amount
of general, non-multimedia-related stuff in SDL that’s basically an
exact duplicate of functionality I already have available in the Delphi
standard libraries, and this is one example.

If it’s optional it defeats the entire purpose of having it. If you
compile without it does the app not run? Or does it get race conditions?
Either way I do not think it’s acceptable, and personally I would be
interested in it to stay away from gcc extensions. If it duplicates
stuff in the port to another language or the likes that port can just
omit it, but for C it is a good thing.

Edgar

-------------- next part --------------
A non-text attachment was scrubbed…
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20110115/ed920240/attachment.pgp

If it’s optional it defeats the entire purpose of having it. If you
compile without it does the app not run? Or does it get race conditions?
Either way I do not think it’s acceptable, and personally I would be
interested in it to stay away from gcc extensions. If it duplicates
stuff in the port to another language or the likes that port can just
omit it, but for C it is a good thing.

I’ll second this. SDL in it’s nature provides duplicate functionality. If
I use SDL on a single platform with no intentions of porting it to
another… then… there’s already something else that provides the graphics
/ sound / etc primitives, so theoretically there would be no point in using
SDL. As the immediate rebuff to first argument against this thought – “but
I already know SDL and want to use it, even if I won’t port my application
to another platform” :).

It should be available at all times. I also imagine that the atomic
operations will cost very lil compiled space or RAM, so it’s got minimal
impact if it’s not used. There are things that SDL provides that posix
systems already provides, etc… that doesn’t mean you can cut’em out. This
seems like a good addition to the mutex support SDL already provides.

Lastly, it’s also something that I do feel should be apart of SDL, and not
separate such as “sdl_atomic” (ie: sdl_image/sdl_net/etc).

I don’t fully recall all of Bob’s tremendously awesome work last year (or
was it even earlier ??) but… I think Sam’s got the bases covered with the
API list above. I think keeping things Simple (of SDL) is good.

I only have a semantical question - much of the rest of the current SDL API
is more along the lines of:

SDL_VerbObject

Here, you’re changing to:

SDL_ObjectVerb

This would be an annoying inconsistency (and will leave my personal
preference for grammar/nomenclature out of the discussion).

-Will

API list above. I think keeping things Simple (of SDL) is good.

Second that.

I only have a semantical question - much of the rest of the current SDL API
is more along the lines of:

SDL_VerbObject

Here, you’re changing to:

SDL_ObjectVerb

This would be an annoying inconsistency (and will leave my personal
preference for grammar/nomenclature out of the discussion).

Atomic is a modifier, not an object. So for example

void SDL_AtomicIncRef(SDL_atomic_t *a);

is SDL_AtomicVerbObject

JeffOn Friday 14 January 2011 17:00, Will Langford wrote:

Atomic is a modifier, not an object. So for example

void SDL_AtomicIncRef(SDL_atomic_t *a);

is SDL_AtomicVerbObject

I’ve been primarily working with 1.2, but looking at the current 1.3 wiki –
I will note the addition of SDL_Haptic* … and… actually… looking at
many of the changes to SDL 1.3 API … there’s SDL_Render* (ie:
RenderFillRect instead of just FillRect, etc)…

Soooo… I think… I’ll withdraw my complaint about nomenclature /
grammar. SDL_Atomic* matches the rest of 1.3.

My bad, I’ll go into my corner and shut up now :slight_smile:

-Will

PS: YAY! I’ve always wanted the API to be more like this hehe

I’d love to get feedback on this proposal…

In general, I think this looks like a great atomic operation API. The
only two things I can think of off hand are (in order of importance):

/* Set a pointer to a new value if it is currently an old value,
?? returning SDL_TRUE if the value was set.

?? If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);

  1. What method are you intending to use to avoid ABA? I assume from
    the signature that you intend to use the low bits of the pointer as a
    mod counter? That would at least give some protection against ABA,
    w/o the overhead and inconvenience of having an explicit mod counter.

  2. It might be nice to have a double wide CAS, as well. But that would
    just be gravy, I guess.

Regardless, having a basic atomic ops API is a great step in the right
direction!On Fri, Jan 14, 2011 at 17:10, Sam Lantinga wrote:


Do what you can, where you are, with what you have. - T. Roosevelt

I second this idea, while generally you’d want to have the atomic
features available across all platforms, there are special cases in
which you want (and need) to tune SDL library as much as you can. The
first example that comes into mind is on mobile platforms (namely
iphone and android) in which you need to be able to select which
features you want compiled in.
VittorioOn Sat, Jan 15, 2011 at 12:18 AM, Mason Wheeler wrote:

Looks interesting, but I’ve gotta agree with the guy (I forget who) who
asked for a compile flag to leave this out.? There’s a surprising amount of
general, non-multimedia-related stuff in SDL that’s basically an exact
duplicate of functionality I already have available in the Delphi standard
libraries, and this is one example.


From: Sam Lantinga
To: SDL
Sent: Fri, January 14, 2011 3:10:02 PM
Subject: [SDL] Atomic API proposal

I’ve done a lot of research, looked over Bob’s excellent analysis, and
looked at some practical examples of lockless programming (scary stuff,
don’t do it!), and I think I’ve come up with an API that more closely
matches the use cases.

I’d love to get feedback on this proposal…

(All these functions are full memory barriers)

/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;

/* Set an atomic variable to a value, returning the previous value */
int SDL_AtomicSet(SDL_atomic_t *a, int value);

/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);

/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);

/* Increment an atomic variable used as a reference count */
void SDL_AtomicIncRef(SDL_atomic_t *a);

/* Decrement an atomic variable used as a reference count,
?? returning SDL_TRUE if the variable has reached zero after decrementing
?*/
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a);

/* Set an atomic variable to a new value if it is currently an old value,
?? returning SDL_TRUE if the value was set.

?? If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

/* Set a pointer to a new value if it is currently an old value,
?? returning SDL_TRUE if the value was set.

?? If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);


? ? -Sam Lantinga, Founder and President, Galaxy Gameworks LLC


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Hi Sam-

typedef struct { int value; } SDL_atomic_t;

This is too small to store a pointer on 64-bit platforms where int is 32 bits
wide.

An atomic swap (without the compare) would be nice to have too.

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

It may be useful to have this return the old value stored in the atomic. One
could check if the swap has occurred by comparing the return value to oldval.
However, in the case the swap fails, one can then inspect the value to which
it’s been changed.

I assume these functions would all have the appropriate barrier magic in them?

Other than those little points, looks great!

AlistairOn 14 Jan 2011, at 23:10, Sam Lantinga wrote:

Hi Sam-

typedef struct { int value; } SDL_atomic_t;

This is too small to store a pointer on 64-bit platforms where int is 32 bits
wide.

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

Perhaps an SDL_atomic_ptr_t, like:

typedef int SDL_mod_count_t;
typedef struct { void *p; SDL_mod_count_t mods } SDL_atomic_ptr_t;

could be done. That’d allow for a large enough mod count to make the
atomic ptr safe from ABA issues, but still allow the size of the
counter to be tuned for specific needs.

An atomic swap (without the compare) would be nice to have too.

While I agree that it’d be nice to have, I’m not aware of any way to
do a lock free swap without the compare. Can you point to a paper or
something that describes a way to do that?

/* Set an atomic variable to a new value if it is currently an old value,
? ?returning SDL_TRUE if the value was set.

? ?If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

It may be useful to have this return the old value stored in the atomic. One
could check if the swap has occurred by comparing the return value to oldval.
However, in the case the swap fails, one can then inspect the value to which
it’s been changed.

Personally, I prefer the bool return, and not keeping the old value
in the struct. The bool return is convenient in many coding styles,
and if anyone wants to tie the oldval to the atomic, they could wrap
their own struct.

Just my opinion, but I think it’d be best for this API to be a set of
primitives, not an all singing, all dancing concurrency library. With
the right set of primitives, the construction of an add on library
(SDL_Concurrency or some such?) would be possible, but the base API
would still be svelte and sexy … er, I mean small, efficient and
portable.On Sat, Jan 15, 2011 at 09:08, Alistair Lynn wrote:

On 14 Jan 2011, at 23:10, Sam Lantinga wrote:

I assume these functions would all have the appropriate barrier magic in them?

Other than those little points, looks great!

Alistair


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


Do what you can, where you are, with what you have. - T. Roosevelt

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

Er… pointers are 32 bit integers, as they are actually just memory
addresses.On Sat, Jan 15, 2011 at 12:43 PM, Greg Jandl <greg.jandl at gmail.com> wrote:
On Sat, Jan 15, 2011 at 09:08, Alistair Lynn wrote:

Quoth Alex Barry <alex.barry at gmail.com>, on 2011-01-15 12:47:23 -0500:

Er… pointers are 32 bit integers, as they are actually just memory
addresses.

No they’re not. Please don’t do this. void * is not guaranteed to be
at most the size of int. Consider GNU/Linux AMD64, for instance.
It’s not even guaranteed to be at most the size of long, if I recall
the types on AMD64 Windows correctly, though that’s a rarer case.

—> Drake Wilson

Fair enoughOn Sat, Jan 15, 2011 at 12:53 PM, Drake Wilson wrote:

Quoth Alex Barry <@Alex_Barry>, on 2011-01-15 12:47:23 -0500:

Er… pointers are 32 bit integers, as they are actually just memory
addresses.

No they’re not. Please don’t do this. void * is not guaranteed to be
at most the size of int. Consider GNU/Linux AMD64, for instance.
It’s not even guaranteed to be at most the size of long, if I recall
the types on AMD64 Windows correctly, though that’s a rarer case.

—> Drake Wilson


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


Hi Greg-

On 15 Jan 2011, at 17:43, Greg Jandl wrote:

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

It’s useful to be able to atomically munge pointers. :slight_smile: It’s also perfectly
valid to store them in integer types, as long as they’re sufficiently sized -
and, luckily, those thoughtful C standards committee chaps gave us intptr_t in
?7.18.1.4 of C99.

An atomic swap (without the compare) would be nice to have too.

While I agree that it’d be nice to have, I’m not aware of any way to
do a lock free swap without the compare. Can you point to a paper or
something that describes a way to do that?

Under x86 this would be an ‘xchg’ instruction; otherwise, it’s trivial to emulate
with code along the following lines:

int SDL_AtomicSwap(SDL_atomic_t *a, int newval)
{
int oldval;
do {
oldval = SDL_AtomicGet(a);
} while (SDL_AtomicCAS(a, oldval, newval));
return oldval;
}

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

It may be useful to have this return the old value stored in the atomic. One
could check if the swap has occurred by comparing the return value to oldval.
However, in the case the swap fails, one can then inspect the value to which
it’s been changed.

Personally, I prefer the bool return, and not keeping the old value
in the struct. The bool return is convenient in many coding styles,
and if anyone wants to tie the oldval to the atomic, they could wrap
their own struct.

Sorry, poor wording there: by “return the old value stored in the atomic” I do not
mean to suggest changing the ‘SDL_atomic_t’ structure - I mean changing
SDL_AtomicCAS to return the value that was previously stored in the atomic before
(possibly) being overwritten by the compare-and-swap. This also brings it in line
with the basic API offered by the GCC/clang ‘sync’ builtins extension, which has
__sync_val_compare_and_swap as the basic API and __sync_bool_compare_and_swap which
is lowered to the aforementioned test on the result of __sync_val_compare_and_swap
(i.e. comparing the return value against ‘oldval’).

Just my opinion, but I think it’d be best for this API to be a set of
primitives, not an all singing, all dancing concurrency library. With
the right set of primitives, the construction of an add on library
(SDL_Concurrency or some such?) would be possible, but the base API
would still be svelte and sexy … er, I mean small, efficient and
portable.

Yup.

Alistair

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

Er… pointers are 32 bit integers, as they are actually just memory
addresses.

You’re contradicting yourself here.

Pointers are memory addresses, though they’re not just memory
addresses, but, rather, typed memory addresses. Unless they’re a
void *, the compiler knows what the memory they’re pointing to is
being used for - that’s how pointer arithmetic works.

Memory addresses are most certainly not 32 bit integers. They may,
depending upon the platform, be 16 bits, 32 bits, 64 bits, 36 bits, 16
bits, plus an 8 or 16 bit segment specifier, or any of a host of other
things.

Expecting sizeof(foo *) to be the same as sizeof(int) is simply wrong.On Sat, Jan 15, 2011 at 11:47, Alex Barry <alex.barry at gmail.com> wrote:

On Sat, Jan 15, 2011 at 12:43 PM, Greg Jandl <@Greg_Jandl> wrote:

On Sat, Jan 15, 2011 at 09:08, Alistair Lynn wrote:


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


Do what you can, where you are, with what you have. - T. Roosevelt


Hi Greg-

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

It’s useful to be able to atomically munge pointers. :slight_smile: It’s also perfectly
valid to store them in integer types, as long as they’re sufficiently sized -
and, luckily, those thoughtful C standards committee chaps gave us intptr_t in
?7.18.1.4 of C99.

Agree on atomic pointer munging, and intptr_t (and C99 generally!),
but I’ve been bitten too many times over the years by code that
expects to be able to conflate pointers and ints (or other integer
types like long).

It’s true that, if they’re sufficiently sized, it’s possible to
store pointers in integer types. However, it’s seldom, if ever
necessary, in my experience. And I’ve seen in come to bad end more
often that not.

An atomic swap (without the compare) would be nice to have too.

While I agree that it’d be nice to have, I’m not aware of any way to
do a lock free swap without the compare. Can you point to a paper or
something that describes a way to do that?

Under x86 this would be an ‘xchg’ instruction; otherwise, it’s trivial to emulate
with code along the following lines:

int SDL_AtomicSwap(SDL_atomic_t *a, int newval)
{
? ?int oldval;
? ?do {
? ? ? ?oldval = SDL_AtomicGet(a);
? ?} while (SDL_AtomicCAS(a, oldval, newval));
? ?return oldval;
}

Ah. I was conflating lock free with lock free and non-blocking. In
general, I’d personally prefer the base API to be non-blocking, as
well, since, as you point out, it’s trivially possible to implement
more complex operations using the base primitives.

However, as long as there’s some way for client code to query SDL to
know if things like AtomicSwap are non-blocking, I can see the value
of having them as primitives to take advantage of platform
capabilities.

It may be useful to have this return the old value stored in the atomic. One
could check if the swap has occurred by comparing the return value to oldval.
However, in the case the swap fails, one can then inspect the value to which
it’s been changed.

Personally, I prefer the bool return, and not keeping the old value
in the struct. The bool return is convenient in many coding styles,
and if anyone wants to tie the oldval to the atomic, they could wrap
their own struct.

Sorry, poor wording there: by “return the old value stored in the atomic” I do not
mean to suggest changing the ‘SDL_atomic_t’ structure - I mean changing
SDL_AtomicCAS to return the value that was previously stored in the atomic before
(possibly) being overwritten by the compare-and-swap. This also brings it in line
with the basic API offered by the GCC/clang ‘sync’ builtins extension, which has
__sync_val_compare_and_swap as the basic API and __sync_bool_compare_and_swap which
is lowered to the aforementioned test on the result of __sync_val_compare_and_swap
(i.e. comparing the return value against ‘oldval’).

Gotcha. I guess either way works for me, assuming there’s no strong
implementation reason to go one way or the other. I still somewhat
prefer the bool interface, I think, but not strongly enough to argue
about it. ;)On Sat, Jan 15, 2011 at 12:12, Alistair Lynn wrote:

On 15 Jan 2011, at 17:43, Greg Jandl wrote:


Do what you can, where you are, with what you have. - T. Roosevelt

Hi Greg-

Ah. I was conflating lock free with lock free and non-blocking. In
general, I’d personally prefer the base API to be non-blocking, as
well, since, as you point out, it’s trivially possible to implement
more complex operations using the base primitives.

However, as long as there’s some way for client code to query SDL to
know if things like AtomicSwap are non-blocking, I can see the value
of having them as primitives to take advantage of platform
capabilities.

It isn’t blocking. At worst, it’s a busy wait - however, it’s only a
busy wait if something continually overwrites the atomic between the
read and the CAS. This is extremely unlikely.

Alistair

Okay, I’ve made a few tweaks and the updated API is available in the latest
snapshot, in SDL_atomic.h:
http://www.libsdl.org/tmp/SDL-1.3.zip

Thanks everyone!On Fri, Jan 14, 2011 at 3:10 PM, Sam Lantinga <@slouken> wrote:

I’ve done a lot of research, looked over Bob’s excellent analysis, and
looked at some practical examples of lockless programming (scary stuff,
don’t do it!), and I think I’ve come up with an API that more closely
matches the use cases.

I’d love to get feedback on this proposal…

(All these functions are full memory barriers)

/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;

/* Set an atomic variable to a value, returning the previous value */
int SDL_AtomicSet(SDL_atomic_t *a, int value);

/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);

/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);

/* Increment an atomic variable used as a reference count */
void SDL_AtomicIncRef(SDL_atomic_t *a);

/* Decrement an atomic variable used as a reference count,
returning SDL_TRUE if the variable has reached zero after decrementing
*/
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a);

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

/* Set a pointer to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);


-Sam Lantinga, Founder and President, Galaxy Gameworks LLC


-Sam Lantinga, Founder and President, Galaxy Gameworks LLC

SDL Digest, Vol 49, Issue 55

Message: 5
Message-ID:
Content-Type: text/plain; charset=us-ascii

Hi Sam-

typedef struct { int value; } SDL_atomic_t;

This is too small to store a pointer on 64-bit platforms where int is 32 bits
wide.

An atomic swap (without the compare) would be nice to have too.
This is actually what I’m needing as well (I’m working on some
single-ownership semantics with a C++ wrapper for SDL’s threads), but
I decided that since CAS is more multi-purpose (and swap is
dead-simple to implement if you have atomic read and CAS), I should
ask for that instead. That having been said, the older variants of the
ARM platform only have an atomic swap operation, so…

/* Set an atomic variable to a new value if it is currently an old value,
returning SDL_TRUE if the value was set.

If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);

It may be useful to have this return the old value stored in the atomic. One
could check if the swap has occurred by comparing the return value to oldval.
However, in the case the swap fails, one can then inspect the value to which
it’s been changed.
I don’t know if any platforms that LACK Compare-and-swap have it, but
I do know that some platforms have a Compare-and-store. Thus, the
current proposal for CAS might allow for optimization on more
platforms.

Additionally, some platforms use transactional operations for atomics
that fail if the address involved has been accessed between paired
transactional read and transactional write operations. Therefor, these
platforms can fail even if the value in the memory location is the
same now as it was when the operation began, which could lead to
situations where you don’t have a clue whether the CAS failed or
succeeded because the return value will be identical in either case. I
believe that the current form of the function would better represent
such things.

I assume these functions would all have the appropriate barrier magic in them?
Sam has said as much, so yeah.> Date: Sat, 15 Jan 2011 15:08:56 +0000
From: Alistair Lynn
To: SDL Development List
Subject: Re: [SDL] Atomic API proposal
On 14 Jan 2011, at 23:10, Sam Lantinga wrote:

SDL Digest, Vol 49, Issue 57

Message: 2
Date: Sat, 15 Jan 2011 12:07:17 -0600
From: Greg Jandl <greg.jandl at gmail.com>
To: SDL Development List
Subject: Re: [SDL] TM emulation [was SDL Digest, Vol 49, Issue 53]
Message-ID:
<AANLkTimjn=zkAf9APWhEsw5iFGsMS2myPzTd2ZbbxQh7 at mail.gmail.com>
Content-Type: text/plain; charset=ISO-8859-1

On Sat, Jan 15, 2011 at 00:05, Jared Maddox <@Jared_Maddox> wrote:

Since this is the time to decide, does anyone want transactional
memory emulation (by which I mean an emulation of the stuff that
POWER/ARMv7+ use for atomics)? Since I asked about this stuff in the
first place, I’ll provide emulation if anyone actually wants it, but
it isn’t a personal priority so I won’t do it if noone expresses an
interest.

Greg, should I count your message as a request?

Not sure what you mean by TM emulation here.

Do you mean a full blown transactional memory implementation?

If so, then no - I would prefer that to be a library separate from SDL
proper. One of the things that attracted me to SDL was the way it’s
set up (mostly) as a relatively primitive API that can be layered upon
as needed.
Ok, though now I’m slightly confused as to what you were talking about
earlier? At any rate, what’s your opinion about…:

Message: 5
Date: Fri, 14 Jan 2011 15:10:02 -0800
From: Sam Lantinga
To: SDL
Subject: [SDL] Atomic API proposal
Message-ID:
? ? ? ?<AANLkTinHn9qMrPb3vy+kONwCx8gjC_LF+U2y6z4-RMyQ at mail.gmail.com>
Content-Type: text/plain; charset=“iso-8859-1”

I’ve done a lot of research, looked over Bob’s excellent
analysis, and looked at some practical examples of
lockless programming (scary stuff, don’t do it!), and I
think I’ve come up with an API that more closely matches
the use cases.

I’d love to get feedback on this proposal…
The one thing I’d definitely like added is some sort of identification
of the locks used by the ‘operations’ themselves, with a pattern
something like this:

?/* A typedef so that coding-standard related changes /
?/
?can be done in a single place. */
typedef int SDL_oplock_t;
#define SDL_OPLOCK_ERROR_OFFSET (SDL_oplock_t)0

?/* The return value identifies the lock that was used. /
?/
?If the return value - SDL_OPLOCK_ERROR_OFFSET /
?/
?is negative, then the address wasn’t locked. */
SDL_oplock_t SDL_OpLock( void address_to_lock );
?/
As above, but doesn’t do any locking. */
SDL_oplock_t SDL_IdentifyOpLock( void *address_to_associate_with_lock );
void SDL_OpUnlock( void *address_to_unlock );

The basic idea is that you can create your own ‘atomic operations’,
such as an ‘atomic’ tree-edit (you lock the individual element,
increment it’s reference count, unlock it and the root object, lock
the element’s data, and start to work…), that integrate well with
SDL but don’t break if the details SDL’s emulation change. I got the
idea from reading about the atomic functions in the DGD version of
LPC. This wouldn’t exactly be part of the actual atomics api, but
instead would be part of the API that’s used to implement atomics.
This? I suggested this specifically so that external atomics libraries
can be seamlessly integrated with SDL’s atomics. What’s your opinion
on the API?

Message: 5
Date: Sat, 15 Jan 2011 12:33:53 -0600
From: Greg Jandl <greg.jandl at gmail.com>
To: SDL Development List
Subject: Re: [SDL] Atomic API proposal
Message-ID:
<AANLkTi=fYNorb840F2O5Jt8ni6AQJXvERZZ50qO0FMy0 at mail.gmail.com>
Content-Type: text/plain; charset=ISO-8859-1

On Sat, Jan 15, 2011 at 12:12, Alistair Lynn wrote:


Hi Greg-

On 15 Jan 2011, at 17:43, Greg Jandl wrote:

If you’re storing a pointer in an int, you’re already lost, man. :slight_smile:

It’s useful to be able to atomically munge pointers. :slight_smile: It’s also perfectly
valid to store them in integer types, as long as they’re sufficiently sized -
and, luckily, those thoughtful C standards committee chaps gave us intptr_t in
?7.18.1.4 of C99.

Agree on atomic pointer munging, and intptr_t (and C99 generally!),
but I’ve been bitten too many times over the years by code that
expects to be able to conflate pointers and ints (or other integer
types like long).

It’s true that, if they’re sufficiently sized, it’s possible to
store pointers in integer types. However, it’s seldom, if ever
necessary, in my experience. And I’ve seen in come to bad end more
often that not.
I like to use it for type identification (assign a static variable to
a particular type, and pass it’s address around in a intptr_t as an
identifier, especially useful for dynamic stuff since you can allocate
an identifier for a dynamic type with malloc() ). Beyond that, yeah,
it would be nice if longjmp/setjmp used intptr_t instead of int, but I
don’t know of any other good use for it.

I honestly think that the only reason why it’s done anyways is because
BCPL didn’t recognize a distinction in the first place, and by the
time they realized that C definitely needed to there was too much code
out in the wild that depended on this sort of thing.

An atomic swap (without the compare) would be nice to have too.

While I agree that it’d be nice to have, I’m not aware of any way to
do a lock free swap without the compare. Can you point to a paper or
something that describes a way to do that?

Under x86 this would be an ‘xchg’ instruction; otherwise, it’s trivial to emulate
with code along the following lines:

int SDL_AtomicSwap(SDL_atomic_t *a, int newval)
{
? ?int oldval;
? ?do {
? ? ? ?oldval = SDL_AtomicGet(a);
? ?} while (SDL_AtomicCAS(a, oldval, newval));
? ?return oldval;
}

Ah. I was conflating lock free with lock free and non-blocking. In
general, I’d personally prefer the base API to be non-blocking, as
well, since, as you point out, it’s trivially possible to implement
more complex operations using the base primitives.

However, as long as there’s some way for client code to query SDL to
know if things like AtomicSwap are non-blocking, I can see the value
of having them as primitives to take advantage of platform
capabilities.
Perhaps have a SDL_function name here_NATIVE define, and define it
to either 0 or 1 depending on the platform?

It may be useful to have this return the old value stored in the atomic.
One
could check if the swap has occurred by comparing the return value to
oldval.
However, in the case the swap fails, one can then inspect the value to
which
it’s been changed.
I don’t know if any platforms that LACK Compare-and-swap have it, but
I do know that some platforms have a Compare-and-store. Thus, the
current proposal for CAS might allow for optimization on more
platforms.

Additionally, some platforms use transactional operations for atomics
that fail if the address involved has been accessed between paired
transactional read and transactional write operations. Therefor, these
platforms can fail even if the value in the memory location is the
same now as it was when the operation began, which could lead to
situations where you don’t have a clue whether the CAS failed or
succeeded because the return value will be identical in either case. I
believe that the current form of the function would better represent
such things.

Interesting, I didn’t think about that. I did change the API to return the
old value, but maybe a bool is better to better avoid the ABA problem? I
don’t know that we can portably guarantee ABA avoidance though.

Suggestions?On Sat, Jan 15, 2011 at 1:33 PM, Jared Maddox wrote:


-Sam Lantinga, Founder and President, Galaxy Gameworks LLC