macro LFDS700_PAL_ATOMIC_EXCHANGE
Source File
└───liblfds700 └───inc └───liblfds700 lfds700_lfds700_porting_abstraction_layer_compiler.h
Macro
#define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) [compiler atomic exchange instrinsic]
Parameters
pointer_to_destination
- The address of a liblfds700_pal_atom_t volatile, which *pointer_to_exchange will be written to.
pointer_to_exchange
- The address of a liblfds700_pal_atom_t (non-volatile, but volatile works as well of course), which *pointer_to_destination will be written to.
Return Value
No return value.
Example
#define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ { \ LFDS700_PAL_BARRIER_COMPILER_FULL; \ *(lfds700_pal_atom_t *) (pointer_to_exchange) = (lfds700_pal_atom_t) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) *(pointer_to_exchange) ); \ LFDS700_PAL_BARRIER_COMPILER_FULL; \ }
Optionality
This macro is optional. If it is not given, the macro must be absent, rather than empty.
Notes
All of the atomic operation macros open and close with curley braces as some of them need to declare variables on the stack, so that they can operate in ways which match their 'prototype' (i.e. they may need a bit of temporary storage, as the way in which the macro is prototyped doesn't map directly to the atomic intrinsic prototype for that platform).
The actual atomic intrinsic itself MUST be immediately preceeded and followed by LFDS700_PAL_BARRIER_COMPILER_FULL. This is to prevent compiler re-ordering.
Finally, we get to the actual atomic operation itself. The liblfds700_pal_atom_t types need to be cast to the types the intrinsic expects, and to the maximum extent possible eschew any memory barriers. On ARM, for example, memory barriers and atomic operations are wholly seperated and on that platform, the operation is and is only an atomic operation. The data structures themselves issue memory barriers as and when they must, and any additional barriers issued within the atomic macros are only overhead. On x86 and x64, sadly, memory barriers are built into the atomic operations and cannot be removed. On Itanium, it looks like atomic operations must occur with a barrier, but it is possible to choose a load, store or full barrier, and as such on that platform, the load barrier is always used, as it is the lowest cost of the three.
If this atomic operaton is not available, the macro must be left undefined, which will lead to a placeholder version automatically being used. This placeholder version if called first calls LFDS700_PAL_ASSERT and then, assuming execution has continued (i.e. LFDS700_PAL_ASSERT is not defined, or is defined but this is a release user-mode build and so asserts are not being checked) will attempt to write 0 into memory location 0, to deliberately crash.