106 lines
3.6 KiB
C
106 lines
3.6 KiB
C
/* -*- C -*-
|
|
// -------------------------------------------------------------------
|
|
// MiniLock - a quick user space lock
|
|
// Copyright (c) 2008 Leon Bottou. All rights reserved
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// ------------------------------------------------------------------- */
|
|
|
|
#ifndef ATOMIC_H
|
|
#define ATOMIC_H
|
|
|
|
/* ------------------------------------------------------------
|
|
// These are primitives to implement very quick locks.
|
|
//
|
|
// Non-blocking usage:
|
|
// if (atomicAcquire(&lock)) {
|
|
// ... // do something protected by the lock
|
|
// atomicRelease(&lock);
|
|
// }
|
|
//
|
|
// Blocking usage:
|
|
// atomicAcquireOrSpin(&lock);
|
|
// // do something protected by the lock
|
|
// atomicRelease(&lock);
|
|
//
|
|
// Rules of thumb:
|
|
// - Acquire and release from the same function with
|
|
// no intervening function calls.
|
|
// - Do not use AcquireOrSpin for waiting a long time.
|
|
// No more than a few microseconds please.
|
|
//
|
|
// Memory ordering:
|
|
// Viewed from another processor
|
|
// - load/stores performed by this cpu after the acquire
|
|
// cannot appear to have happened before the acquire.
|
|
// - load/stores performed by this cpu before the release
|
|
// cannot appear to have happened after the release.
|
|
//
|
|
// Implementation:
|
|
// All depends on the definitions from the initial include file.
|
|
// To perform the non blocking operations:
|
|
// - use intel builtins if available (icc, gcc>=4.1).
|
|
// - use win32 interlocked operations (win32).
|
|
// - use inline assembly code for some platforms.
|
|
// - use pthreads
|
|
// To perform the waiting when spinning takes to long:
|
|
// - use win32 critical sections and events.
|
|
// - use pthreads mutex and conditions.
|
|
// This is controlled by the preprocessor symbols:
|
|
// WIN32
|
|
// __GNUC__ __GNUC_MAJOR__ __GNUC_MINOR__
|
|
// __INTEL_COMPILER
|
|
// and can be overriden by defining
|
|
// HAVE_INTEL_ATOMIC_BUILTINS
|
|
// OBEY_HAVE_INTEL_ATOMIC_BUILTINS
|
|
// and by tweaking the files include in atomic.h.
|
|
// ------------------------------------------------------------ */
|
|
|
|
|
|
# ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* { int tmp = *lock; *lock = 1; return !tmp; }. */
|
|
int atomicAcquire(int volatile *lock);
|
|
|
|
/* { while (!atomicAcquire(lock)) { spin/yield/wait } } */
|
|
void atomicAcquireOrSpin(int volatile *lock);
|
|
|
|
/* { *lock = 0; } */
|
|
void atomicRelease(int volatile *lock);
|
|
|
|
/* { *var += 1; return *var; } */
|
|
int atomicIncrement(int volatile *var);
|
|
|
|
/* { *var -= 1; return *var; } */
|
|
int atomicDecrement(int volatile *var);
|
|
|
|
/* { if (*var == oldval) { *var = newval; return TRUE; } return FALSE; } */
|
|
int atomicCompareAndSwap(int volatile *var, int oldval, int newval);
|
|
|
|
|
|
# ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|