LIBASO(3)

NAME
ASO - Atomic Scalar Operations

SYNOPSIS
#include <aso.h>
uint8_t    asocas8(uint8_t volatile*, int, int);
uint8_t    asoget8(uint8_t volatile*);
uint8_t    asoadd8(uint8_t volatile*, uint8_t);
uint8_t    asosub8(uint8_t volatile*, uint8_t);
uint8_t    asoinc8(uint8_t volatile*);
uint8_t    asodec8(uint8_t volatile*);
uint16_t    asocas16(uint16_t volatile*, uint16_t, uint16_t);
uint16_t    asoget16(uint16_t volatile*);
uint16_t    asoadd16(uint16_t volatile*, uint16_t);
uint16_t    asosub16(uint16_t volatile*, uint16_t);
uint16_t    asoinc16(uint16_t volatile*);
uint16_t    asodec16(uint16_t volatile*);
uint32_t    asocas32(uint32_t volatile*, uint32_t, uint32_t);
uint32_t    asoget32(uint32_t volatile*);
uint32_t    asoadd32(uint32_t volatile*, uint32_t);
uint32_t    asosub32(uint32_t volatile*, uint32_t);
uint32_t    asoinc32(uint32_t volatile*);
uint32_t    asodec32(uint32_t volatile*);
uint64_t    asocas64(uint64_t volatile*, uint64_t, uint64_t);
uint64_t    asoget64(uint64_t volatile*);
uint64_t    asoadd64(uint64_t volatile*, uint64_t);
uint64_t    asosub64(uint64_t volatile*, uint64_t);
uint64_t    asoinc64(uint64_t volatile*);
uint64_t    asodec64(uint64_t volatile*);
unsigned char    asocaschar(unsigned char volatile*, int, int);
unsigned char    asogetchar(unsigned char volatile*);
unsigned char    asoaddchar(unsigned char volatile*, int);
unsigned char    asosubchar(unsigned char volatile*, int);
unsigned char    asoincchar(unsigned char volatile*);
unsigned char    asodecchar(unsigned char volatile*);
unsigned short    asocasshort(unsigned short volatile*, unsigned short, unsigned short);
unsigned short    asogetshort(unsigned short volatile*);
unsigned short    asoaddshort(unsigned short volatile*, int);
unsigned short    asosubshort(unsigned short volatile*, int);
unsigned short    asoincshort(unsigned short volatile*);
unsigned short    asodecshort(unsigned short volatile*);
unsigned int    asocasint(unsigned int volatile*, unsigned int, unsigned int);
unsigned int    asogetint(unsigned int volatile*);
unsigned int    asoaddint(unsigned int volatile*, unsigned int);
unsigned int    asosubint(unsigned int volatile*, unsigned int);
unsigned int    asoincint(unsigned int volatile*);
unsigned int    asodecint(unsigned int volatile*);
unsigned long    asocaslong(unsigned long volatile*, unsigned long, unsigned long);
unsigned long    asogetlong(unsigned long volatile*);
unsigned long    asoaddlong(unsigned long volatile*, unsigned long);
unsigned long    asosublong(unsigned long volatile*, unsigned long);
unsigned long    asoinclong(unsigned long volatile*);
unsigned long    asodeclong(unsigned long volatile*);
size_t    asocassize(size_t volatile*, size_t, size_t);
size_t    asogetsize(size_t volatile*);
size_t    asoaddsize(size_t volatile*, size_t);
size_t    asosubsize(size_t volatile*, size_t);
size_t    asoincsize(size_t volatile*);
size_t    asodecsize(size_t volatile*);
void*    asocasptr(void volatile*, void*, void*);
void*    asogetptr(void volatile*);
int    asolock(unsigned int volatile*, unsigned int, int);
void    asospindecl(void);
void    asospininit(void);
void    asospinnext(void);
void    asospinrest(void);
#define    _ASO_INTRINSIC    [012]

DESCRIPTION

ASO provides functions to perform atomic scalar operations. The functions on the type uint32_t will be fully described below. Other functions work similarly on their respective types. 64 bit operations are provided if the compiler supports 64 bit integers and/or pointers. On most modern architectures (with modern compilers) the ASO functions are macros that reference the respective intrinsic operations directly. Operations lacking intrinsics are implemented by composing other intrinsics. At minimum a cas (compare and swap) atomic intrinsic must be available for ASO to ensure atomic operations. The value of the macro _ASO_INTRINSIC describes the native environment: 0 No atomic intrinsic operations available. ASO is emulated for a single process/thread and private memory only. 1 Some atomic intrinsic operations are available. ASO works for multi process/thread and shared memory. 2 Atomic intrinsics are implemented using atomic assembler machine instructions. ASO works for multi process/thread and shared memory.

uint8_t, uint16_t, uint32_t, uint64_t These are unsigned integer types of different sizes in bits. For example, uint32_t represents the type of unsigned integer with 32 bits or 4 bytes.

This function returns the value *from.

These functions add num to *dest and subtract num from *dest in an atomic step. The return value is the old value in *dest.

These functions increment *dest by 1 and decrement *dest by 1 in an atomic step. The return value is the old value in *dest. Consider an example where two concurrent threads/processes call asoadd8() on the same dest with values, say v1 and v2. The eventual value in dest will be as if *dest += v1+v2 was performed in a single-threaded execution. That should be contrasted with a situation where, instead of asoadd8(), only normal arithmetics were used. Then, the end result could be any of *dest += v1, *dest += v2 or *dest += v1+v2, depending on states of the hardware cache and the process scheduling.

This function provides the atomic compare-and-swap operation. If the current content of dest is equal to tstval then it will be set to newval. If multiple threads/processes are performing the same operations only one will succeed with a return value of tstval. The return value is the old value in *dest.

This function uses key, a non-zero unsigned integer, to lock or unlock the lock. It returns 0 or 1 on success and -1 on failure. The argument type can be one of the below values: ASO_TRYLOCK: This call makes a single attempt to use the given key to acquire a lock. If successful, it returns 1; else it returns -1. ASO_LOCK: This call uses a spin loop to acquire a lock with the given key. On success, it returns 1. There is no failure mode with this call. ASO_UNLOCK: This call unlocks the lock if it was locked with key. It returns 1 on success and -1 on failure.

These macro functions can be used to construct a concurrent spin-loop to process resources. They attempt to balance out computing resource among threads and/or processes competing for the same resources. asospindecl() declares needed variables so it should be used in a syntactic context suitable for such declarations. asospinrest() sleeps for a fraction of a second. Below is an example of how to manage a critical section of code using a spin-lock:
      unsigned int lock;
      asospindecl();
      for(asospininit();; asospinnext() )
          if(asocasint(&lock, 0, 1) == 0)
               break;
      ... critical section of code ...
      asocasint(&lock, 1, 0); /* release lock */

AUTHOR
Kiem-Phong Vo, Adam Edgar, and Glenn Fowler