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?> SDL Digest, Vol 49, Issue 53
Message: 1
Date: Fri, 14 Jan 2011 12:25:21 -0800
From: Sam Lantinga
To: SDL Development List
Subject: Re: [SDL] SDL Atomic operations
Message-ID:
<AANLkTim6m3=K_ZsUmTtqU7DzKhyWtv=OaUC__MMkAW+X at mail.gmail.com>
Content-Type: text/plain; charset=“iso-8859-1”There’s some great information on the design and
considerations of the SDL Atomic API here:
http://www.thegrumpyprogrammer.com/blog/1I’m going to contact Bob and double check some things.
Cheers!
I knew I’d seen some rational on the design of SDL’s atomics code (I
thought it had been in the source itself, but I obviously didn’t find
it there when I looked again), but all I could remember was that:
- It read as if the entire thing had been designed to just use OS
functions, and - That when I went looking at the actual operations again, it ONLY
seemed useful for reference counting. So, useful for some useful
things, but because I do some different things, not actually directly
useful to me (also, I don’t quite trust the reference counting code
from it’s description). Your set look much more useful for my
purposes.
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.
/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;
Am I right in assuming that this (and the related functions) will come
in both Uint32 and Uint64 versions?
/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);
What about a pointer version? Should a volatile pointer already be
atomic for reads?
/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);
Will this fail to increment if the variable is already 0, or would a
lock be needed for that type of safety?
/* 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);
I realize that I’m the one that asked for it, but do we need both of
these? Can we safely use casts to convert pointer-to-pointers into
pointers-to-values on all of the intended platforms?
Message: 6
Date: Fri, 14 Jan 2011 15:18:02 -0800 (PST)
From: Mason Wheeler
To: SDL Development List
Subject: Re: [SDL] Atomic API proposal
Message-ID: <54494.85447.qm at web161205.mail.bf1.yahoo.com>
Content-Type: text/plain; charset=“us-ascii”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.
You might wind up using code that expects them, so if they make it
into SDL it would PROBABLY be a bad idea to outright remove them with
a compiler flag, but at least in the case of non-threading code you
shouldn’t need ACTUAL atomic behavior. Here’s some (very simple)
replacements (that need proper error reporting!) for non-threading
usage:
int SDL_AtomicSet(SDL_atomic_t *a, int value)
{
int ret = 0;
if( a )
{
ret = a->value;
a->value = value;
}
return( ret );
}
int SDL_AtomicGet(SDL_atomic_t *a)
{
if( a )
{
return( a->value );
}
return( 0 );
}
int SDL_AtomicAdd(SDL_atomic_t *a, int value)
{
int ret = 0;
if( a )
{
ret = a->value;
a->value += value;
}
return( ret );
}
void SDL_AtomicIncRef(SDL_atomic_t *a)
{
if( a )
{
++( a->value );
}
}
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a)
{
if( a )
{
return( --( a->value ) );
}
return( 0 );
}
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
{
if( a && a->value == oldval )
{
a->value = newval;
return( SDL_TRUE );
}
return( 0 );
}
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
{
if( a && *a == oldval )
{
*a = newval;
return( SDL_TRUE );
}
return( 0 );
}