/* -*- C -*-
// -------------------------------------------------------------------
// Atomic primitives
// 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.
//
// ------------------------------------------------------------------- */

#include "atomic.h"

#ifndef ATOMIC_MACROS

#if HAVE_PTHREAD
# include <pthread.h>
#elif HAVE_QTHREAD  // never defined at the moment.
# include <QMutex>
# include <QWaitCondition>
#else
# include "GThreads.h"
#endif

/* Select synchronization primitives */

# if defined(_WIN32) || defined(_WIN64)

namespace {
  struct CS { 
    CRITICAL_SECTION cs; 
    CS() { InitializeCriticalSection(&cs); }
    ~CS() { DeleteCriticalSecton(&cs); } }; }
static CS globalCS;
# define MUTEX_LEAVE LeaveCriticalSection(&globalCS.cs)
# define MUTEX_ENTER EnterCriticalSection(&globalCS.cs);

# elif defined (PTHREAD_MUTEX_INITIALIZER)

static pthread_mutex_t ptm = PTHREAD_MUTEX_INITIALIZER;
# define MUTEX_ENTER  pthread_mutex_lock(&ptm)
# define MUTEX_LEAVE  pthread_mutex_unlock(&ptm)

# elif defined(__cplusplus) && defined(_GTHREADS_H_)

static GMonitor m;
# define MUTEX_ENTER  m.enter()
# define MUTEX_LEAVE  m.leave()

# elif defined(__cplusplus) && defined(QMUTEX_H)

static QMutex qtm;
# define MUTEX_ENTER  qtm.lock()
# define MUTEX_LEAVE  qtm.unlock()

# endif


/* atomic primitive emulation */

int
atomicIncrement(int volatile *var)
{
  int res;
  MUTEX_ENTER;
  res = ++(*var);
  MUTEX_LEAVE;
  return res;
}

int 
atomicDecrement(int volatile *var)
{
  int res;
  MUTEX_ENTER;
  res = --(*var);
  MUTEX_LEAVE;
  return res;
}

int 
atomicCompareAndSwap(int volatile *var, int oldval, int newval)
{
  int ret;
  MUTEX_ENTER;
  ret = *var;
  if (ret == oldval)
    *var = newval;
  MUTEX_LEAVE;
  return ret;
}

int 
atomicExchange(int volatile *var, int newval)
{
  int ret;
  MUTEX_ENTER;
  ret = *var;
  *var = newval;
  MUTEX_LEAVE;
  return ret;
}

void* 
atomicExchangePointer(void* volatile *var, void* newval)
{
  void *ret;
  MUTEX_ENTER;
  ret = *var;
  *var = newval;
  MUTEX_LEAVE;
  return ret;
}

#endif 


