Skip to content
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

[Brl.Blitz] Mac: bbAtomicAdd (etc) deprecated #261

Open
GWRon opened this issue Feb 12, 2023 · 6 comments
Open

[Brl.Blitz] Mac: bbAtomicAdd (etc) deprecated #261

GWRon opened this issue Feb 12, 2023 · 6 comments

Comments

@GWRon
Copy link
Contributor

GWRon commented Feb 12, 2023

While checking for ways to avoid mutexes when simply manipulating integers I saw there is "bbAtomicAdd".

Implementation is:

int bbAtomicAdd( volatile int *p,int incr ){
#if !defined(__ANDROID__) && !defined(_WIN32)
#	ifndef __APPLE__
		return __sync_fetch_and_add(p, incr);
#	else
		return OSAtomicAdd32(incr, p);
#	endif
#else
	return __sync_fetch_and_add(p, incr);
#endif

But OSAtomicAdd32 is deprecated by Apple:

/*! @abstract Atomically adds two 32-bit values.
    @discussion
	This function adds the value given by <code>__theAmount</code> to the
	value in the memory location referenced by <code>__theValue</code>,
 	storing the result back to that memory location atomically.
    @result Returns the new value.
 */
OSATOMIC_DEPRECATED_REPLACE_WITH(atomic_fetch_add)
__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
int32_t	OSAtomicAdd32( int32_t __theAmount, volatile int32_t *__theValue );

I am not sure if we can - and should - already replace it with the suggested atomic_fetch_add

@GWRon
Copy link
Contributor Author

GWRon commented Feb 12, 2023

I already asked this on discord but maybe it fits here too:

in Brl.Treads AtomicSwap() is defined:

Function AtomicSwap:Int( target:Int Var,value:Int )
	Repeat
		Local oldval:Int=target
		If CompareAndSwap( Varptr target,oldval,value ) Return oldval
	Forever
End Function

What happens if a second thread manipulates target after it is stored in Local oldVal but before executing CompareAndSwap ?

Asking as CompareAndSwap is called with "oldVal" rather than "target" (which would use the "original" value then).
This means if something changed "target" meanwhile, the Repeat ... Forever might never exit.

This minimizes the chances I guess.

Function AtomicSwap:Int( target:Int Var,value:Int )
	Repeat
		Local oldval:Int=target
		If CompareAndSwap( Varptr target,target,value ) Return oldval
	Forever
End Function

BUT ... the issue here might remain: If someone really wants to use the returned "oldVal" it might NOT be the one which really was replaced. (this is why there is not just __sync_bool_compare_and_swap (the one used on non-apple) but also __sync_value_compare_and_swap

Also I am not sure what GCC creates out of the C-Code, as the function indirection might lead to more temporary variables and thus ways for other threads to manipulate the "original" meanwhile.

The generated C code for now looks like this:

BBINT brl_threads_CompareAndSwap(BBINT* bbt_target,BBINT bbt_oldValue,BBINT bbt_newValue){
	return bbAtomicCAS((int*)&(*bbt_target),(int)bbt_oldValue,(int)bbt_newValue);
}

BBINT brl_threads_AtomicSwap(BBINT* bbt_target,BBINT bbt_value){
	do{
		BBINT bbt_oldval=*bbt_target;
		if(brl_threads_CompareAndSwap(&(*bbt_target),bbt_oldval,bbt_value)!=0){
			return bbt_oldval;
		}
	}while(!(0));
}

directly calling bbAtomicCas:

Function AtomicSwap:Int( target:Int Var,value:Int )
	Repeat
		Local oldval:Int=target
		If bbAtomicCAS( Varptr target,target,value ) Return oldval
	Forever
End Function
BBINT brl_threads_AtomicSwap(BBINT* bbt_target,BBINT bbt_value){
	do{
		BBINT bbt_oldval=*bbt_target;
		if(bbAtomicCAS((int*)&(*bbt_target),(int)*bbt_target,(int)bbt_value)!=0){
			return bbt_oldval;
		}
	}while(!(0));
}

Dunno if the GCC optimizes it to the same final assembler code at the end.

@woollybah
Copy link
Member

We could always force a minimum of C11 and implement support for C11's "atomic" primitives...

Rather than "Int", we'd need to define the variable as an atomic int, eg "AtomicInt", which you'd need to use instead for atomic operations. But then it would be guaranteed to work correctly.

@GWRon
Copy link
Contributor Author

GWRon commented Feb 12, 2023 via email

@woollybah
Copy link
Member

Well, there's nothing to directly replace it with on macOS, since the preferred replacement is to use atomic_fetch_add, which expects something like an atomic_int.

@GWRon
Copy link
Contributor Author

GWRon commented Feb 13, 2023

Seems gcc offers atomic functions since 4.8
https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html

So doesn't that mean we could use that (for non macos targets)?
The atomic store variant sounds also interesting (set without compare)

@GWRon
Copy link
Contributor Author

GWRon commented Feb 13, 2023

Regarding "C11" ... You made some efforts to have it "C99" compatible (or so) to support old linux boxes with old GCC.
It might be potentially useful to have something working for them too.

Hmm ... but it might mean to keep it "potentially incorrect" as it is now.

Couldn't we introduce "Atomic" as a keyword?

Field Atomic i:int

Local Atomic i:int

Asking as introducing int_atomic might be simpler but I am not sure how often other stuff would be needed too (atomic types ).
Anyways. If you add some kind of int_atomic (or atomic_int to have it similar to the C naming scheme) do not forget about long, float and double and other >=32bit variants.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants