{Trimming this to @apr for this bit of discussion.}
At 10:16 AM 1/8/2003, Brian Pane wrote:
>On Wed, 2003-01-08 at 07:15, William A. Rowe, Jr. wrote:
>
>> Just an observation reviewing the apr/includes/ changes... I don't like the
>> look of this code;
>>
>> +#define apr_atomic_casptr(mem,with,cmp) (void*)atomic_cmpxchg((unsigned
>> long *)(mem),(unsigned long)(cmp),(unsigned long)(with))
>>
>> Very simply, this is a very easily broken macro... it is too easy to
>> silently
>> pass the wrong pointer arg to apr_atomic_casptr and explode.
>>
>> We need some type safety here, and this macro (I believe) destroys
>> all hope of that. It seems this needs to become a function. Macro to
>> function should be a safe change, since code compiled to an earlier
>> apr will continue to use this unsafe but otherwise usable macro.
>
>There's a good reason why the atomic CAS can't be a function.
>Its most common use is in spinlocks, where the probability of
>having to retry the CAS increases with every clock cycle you
>spend in the "if (cas failed) {retry;}" loop. Adding a function
>call around the CAS would double the length of the code path
>between the lookup of the old value and the compare-and-swap
>of the new value, which in turn doubles the probability that
>the CAS will fail and require a retry.
>
>As for type safety, keep in mind that the role of
>apr_atomic_casptr is to atomically swap any pointer to
>an object. If we were to turn it into a function, its first
>argument would have to be a void**.
In that case... what about a trick (I believe) Ben Laurie taught us?
Using a typedef for clarity:
typedef void*(*apr_atomic_casptr_fn_t)(unsigned long* mem, unsigned long cmp,
unsigned long with);
#define apr_atomic_casptr ((apr_atomic_casptr_fn_t)(atomic_cmpxchg))
In this way, the arguments to apr_atomic_casptr will be evaluated in terms
of the apr_atomic_casptr_fn_t declaration.
This presumes the arguments exactly match the atomic_cmpxchg function,
with the exception of twos-compliment signedness.
Make sense?