/*
  Copyright (C) 2003 GraphicsMagick Group
  Copyright (C) 2002 ImageMagick Studio
 
  This program is covered by multiple licenses, which are described in
  Copyright.txt. You should have received a copy of Copyright.txt with this
  package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
 
  ImageMagick Spinlock  Methods. These are highly lightweight functions that
  are used to prevent deadlocks on access to global data when the normal
  semaphore system has not yet been initialized. They are intended to only
  be used to protect operations that are very fast - like a flag that tells
  you that something has been inited, or bumping a counter. Do NOT use this
  for protecting an operation that will take any significant amount of time.
*/
#ifndef _SPINLOCKS_H
#define _SPINLOCKS_H

#if defined(MSWINDOWS)

#define SPINLOCK_DELAY_MILLI_SECS 10

static LONG volatile
  spinlock_mutex = 0;

/* Wait for spin lock */
static void _spinlock_wait (LONG volatile *sl)
{
  /*
    LONG InterlockedCompareExchange(LONG volatile* dest, LONG xchg,
    LONG compare)

    Performs an atomic compare-and-exchange operation on the specified
    values. The function compares two specified 32-bit values and
    exchanges with another 32-bit value based on the outcome of the
    comparison.

    If you are exchanging pointer values, this function has been
    superseded by the InterlockedCompareExchangePointer function.

    To operate on 64-bit values, use the InterlockedCompareExchange64
    function.
  */
  while (InterlockedCompareExchange (sl, 1, 0) != 0)
  {
    /* slight delay - just in case OS does not giveup CPU */
    Sleep (SPINLOCK_DELAY_MILLI_SECS);
  }
}
/* Release spin lock */
static void _spinlock_release (LONG volatile *sl)
{
  /*
    LONG InterlockedExchange (LONG volatile* dest, LONG val)

    Sets a 32-bit variable to the specified value as an atomic
    operation.

    To operate on a pointer variable, use the
    InterlockedExchangePointer function.
    
    To operate on a 64-bit variable, use the InterlockedExchange64
    function.
  */
  InterlockedExchange (sl, 0);
}
#define SPINLOCK_WAIT _spinlock_wait(&spinlock_mutex)
#define SPINLOCK_RELEASE _spinlock_release(&spinlock_mutex)

#else /* not MSWINDOWS */

#if defined(HAVE_PTHREAD)

static pthread_mutex_t
  spinlock_mutex = PTHREAD_MUTEX_INITIALIZER;
#define SPINLOCK_WAIT (void) pthread_mutex_lock(&spinlock_mutex)
#define SPINLOCK_RELEASE (void) pthread_mutex_unlock(&spinlock_mutex)

#else /* not HAVE_PTHREAD */

#define SPINLOCK_WAIT
#define SPINLOCK_RELEASE

#endif /* HAVE_PTHREAD */

#endif /* MSWINDOWS */
#endif /* _SPINLOCKS_H */
