/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: ossatomic.h,v 1.16 2009/04/16 15:29:18 jwest Exp $
 * 
 * Contributors: 
 * IBM - Initial API and implementation
 **********************************************************************/

/*******************************************************************************

   Source File Name = ossatomic.h 

   Descriptive Name = OSSe atomic operations

   Note 1
      The API has divided into two categories:

      1. Implicit sized operations (ossAtomicInc, ossAtomicDec, etc.)
      2. Explicit sized operations (ossAtomicInc32, ossAtomicDec64, etc. )

      The implicit sized operations should be used in most situations.
      The OSSAtomic implicit type is always the same size and layout
      on both 32- and 64-bit architectures.

      The size/layout may not be the same cross-platforms.  For example,
      AIX and NT don't require a common atomic type.  BUT, the size/layout will
      be common between 32- and 64-bit AIX.

      Why?  It is not uncommon for these structures to be used in shared
      memory that is accessed by both 32- and 64-bit processes.

      The OSSAtomic32 and OSSAtomic64 explicit sized types are not guaranteed
      to be the same size or implementation.

   Note 2
      On platforms with "fast" atomic operatios, the atomic API maybe
      implemened using this functions/instructions.  In this case the
      OSSAtomic type is usually a register sized word.

      On other platforms, a combination of an integer value and a lock/latch
      are used to "simulate" true hardware atomic.

      Currently, the platforms are implemented as follows:

      Platform             Counter size   Implementation
      =================    ============   ==============
      32/64-bit AIX PPC    32-bit         Platform specific operations
      32/64-bit NT         32-bit         Platform specific operations
      32/64-bit SPARC      64-bit*        Platform specific operations
      Everything else      64-bit         Simulated operations

      *32-bit SPARC can perform 64-bit compare and swap (casx).

   Note 3
      In order to keep 32- and 64-bit architectures common, the IA32 assembly
      implemented used on 32-bit Windows and 32-bit Linux has been commented
      out.

      Linux is now implemented using the simulation operations.  NT
      is now implemented using the Microsoft atomic functions.  These functions
      are common to both 32- and 64-bit Windows platforms.

      "__inline" is a Microsoft compiler extension, as is "inline" for gcc
      (Linux), which is why they are used unrestricted for those platforms.

   Note 4
      The AIX ossAtomicPoke() implementation uses  compare_and_swap.
      It could possibly be improved later to use the assembly like
      fetch_and_add().  This would require dual pathing the code to
      allow for power vs. powerpc assembly - unless done only for 64 bit.

   Note 5
      If the 32 bit code used on the 64 bit platform, the 32 bit version,
      eg. ossAtomicInc32() must be explicitly called, the input also should
      corresponding to 32 bit. Right now it is support on AIX, SUN, HP only

   Note 8
      The set of function for IA64 is now work on AIX for IA 64 bit
      only right now. It is only compiled on the SCO01 machine and test
      on itanium machine (AIX ia64). If want it to be used on other platform,
      more test should be done, because differnt assembly may require
      paticular syntax, although now most assembler are adapted from the
      assembler provided by the Intel.

   Note 7
      No error check such as overflow etc. are done in this code.  It is
      assumed that the resulting integer operation is meaningful.

   Change Activity
   Defect Date        Who Description
   ====== =========== === ==============================================
   161131 Dec/21/2000 kjs initial drop
   163108 Dec/27/2000 pj  C compatability changes.
   yyyyyy             pj  Reorganize for maintainability.
                          Move SQLO_CSTYPE here from sqlo.h, since this code
                          should eventually replace it and it's associated
                          macros (once this code is finished and an sqloCS
                          equivalent is coded).
   170467 Mar/20/2001 jpk Checked into OSSe
   171727 Apr/06/2001 kjs fix compile time error
   190480 Oct/11/2001 jpk Removed ossAtomicChange, ossAtomicChangeAndRet
                          Added ossAtomicPokeAndRet
                          Added ossAtomicCompareAndPoke
   192160 Oct/23/2001 jpk Make OSSAtomic and OSSRegister the same size
                          on 32- and 64-bit architectures.
                          Make the NT implementation common on both
                          32- and 64-bit.
                          Remove Linux ia32 implementation.
                          Remove C wrappers
   192552 Oct/25/2001 jpk Added _sqlo_lock64on32
   195525 Nov/20/2001 yka Rename OSSExs to OSSLatch
   186134 Mar/01/2002 dns Added support for other platforms (MVS, OS400, Linux)

   Last Changed =    02/08/27  12:38:05

*******************************************************************************/
#ifndef OSSATOMIC_HEADER_INCLUDED
#define OSSATOMIC_HEADER_INCLUDED

#include "ossatomictype.h"
#include "osslatch.h"


#if defined _AIX
	#include <sys/atomic_op.h>
#elif defined MVS
	#include <stdlib.h>
#elif defined(SQLLinux) && defined(__linux__)
	#if defined(USE_PTHREAD_ATOMICS)
		// Empty if we're using Pthread atomics
	#elif defined(__i386__)
		#include <stdlib.h>
		/* redefining new because it is used in asm/system.h and causes a compile error
		   when compiled as C++
		*/
		#define new newval

        /* the following pre-processor handles various versions of */
        /*    asm/system.h and asm/bitops.h                        */
        #include <asm/bitops.h>
        #ifndef  LOCK_PREFIX
           #ifdef CONFIG_SMP
               #define LOCK_PREFIX "lock ; "
           #else
               #define LOCK_PREFIX ""
           #endif
        #endif

        #include <asm/system.h>

	#elif defined(USE_GCC_ATOMICS) && defined(__s390__)
		// asm/atomic.h was included previously, but now doesn't provide us
		// with all the functioins we need
		#ifndef atomic_compare_and_swap
		#define atomic_compare_and_swap(oldval,newval,ptr) \
			!__sync_bool_compare_and_swap(ptr,oldval,newval)
		#endif

	#else /* __s390__ and __powerpc__ */
		#include <asm/atomic.h>
	#endif
#elif defined SQL_OS400
	#include <mih/cmpswp.h>	
#endif

/* Disable the "no return value" warning on MSVC++ */
#if defined SQLWINT && defined _MSC_VER
#pragma warning( disable : 4035 )
#endif


#if defined OSS_ATOMIC_VALUE_IS_32BITS

   #define ossAtomicIncByVal(a,v)            ossAtomicIncByVal32(a,v)
   #define ossAtomicDecByVal(a,v)            ossAtomicDecByVal32(a,v)
   #define ossAtomicInc(a)                   ossAtomicInc32(a)
   #define ossAtomicDec(a)                   ossAtomicDec32(a)

   #define ossAtomicIncByValAndRet(a,v)      ossAtomicIncByValAndRet32(a,v)
   #define ossAtomicDecByValAndRet(a,v)      ossAtomicDecByValAndRet32(a,v)
   #define ossAtomicIncAndRet(a)             ossAtomicIncAndRet32(a)
   #define ossAtomicDecAndRet(a)             ossAtomicDecAndRet32(a)

   #define ossAtomicPeek(a)                  ossAtomicPeek32(a)

   #define ossAtomicPoke(a,v)                ossAtomicPoke32(a,v)
   #define ossAtomicPokeAndRet(a,v)          ossAtomicPokeAndRet32(a,v)

   #define ossAtomicCompareAndPoke(a,c,v)    ossAtomicCompareAndPoke32(a,c,v)

#else

   #define ossAtomicIncByVal(a,v)            ossAtomicIncByVal64(a,v)
   #define ossAtomicDecByVal(a,v)            ossAtomicDecByVal64(a,v)
   #define ossAtomicInc(a)                   ossAtomicInc64(a)
   #define ossAtomicDec(a)                   ossAtomicDec64(a)

   #define ossAtomicIncByValAndRet(a,v)      ossAtomicIncByValAndRet64(a,v)
   #define ossAtomicDecByValAndRet(a,v)      ossAtomicDecByValAndRet64(a,v)
   #define ossAtomicIncAndRet(a)             ossAtomicIncAndRet64(a)
   #define ossAtomicDecAndRet(a)             ossAtomicDecAndRet64(a)

   #define ossAtomicPeek(a)                  ossAtomicPeek64(a)

   #define ossAtomicPoke(a,v)                ossAtomicPoke64(a,v)
   #define ossAtomicPokeAndRet(a,v)          ossAtomicPokeAndRet64(a,v)

   #define ossAtomicCompareAndPoke(a,c,v)    ossAtomicCompareAndPoke64(a,c,v)

#endif


#if defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS
#if defined SQLSUN
/* 186134 DNS - Sun _sqlo_lock functions defined as inline assembler in
   sun_asm.il but we can't use them because the instructions they use are
   not supported on the older hardware that we support
*/
OSS_EXTERNC int _sqlo_lock
(
   void *  addr,
   int     old_val,
   int     new_val
) ;

#if defined SQLO_ARCH_P64

OSS_EXTERNC OSSRegister64 _sqlo_lock64
(
   OSSAtomic64 *  addr,
   OSSRegister64  old_val,
   OSSRegister64  new_val
) ;

#else

OSS_EXTERNC int _sqlo_lock64on32
(
   OSSAtomic64 *  addr,
   OSSRegister64  old_val,
   OSSRegister64  new_val
) ;

#define _sqlo_lock64 _sqlo_lock64on32

#endif

//#elif defined SQLAIX_IA64 && defined SQLO_ARCH_P64
//
///*******************************************************************************
//
//   This set of function is available for AIX for IA 64 bit only, right now
//   it is only compiled on the SCO01 machine and test on itanium machine because
//   lack of native assembler.
//   If want it to be used on other platform, more test should be done,
//   because differnt assembly may require paticular syntax, although right now
//   most assembler are adapted from the assembler provided by the Intel
//
//   See the prologue in the generic section of ossatomic.h
//   IA64 part of atomic API
//
//*******************************************************************************/
//
///* The following extern functions are defined in ia64AtomicApi.s */
//OSS_EXTERNC int iaAtomicInc64( OSSAtomic64 * address );
//OSS_EXTERNC int iaAtomicDec64( OSSAtomic64* address );
//OSS_EXTERNC int iaAtomicIncByVal64( OSSAtomic64 *addr, OSSRegister64 val );
//OSS_EXTERNC int iaAtomicChange64( OSSAtomic64 *addr, OSSRegister64 val );
//
#endif
#endif

/*******************************************************************************

   FIXME:

   1. The IA64 AIX code below is missing the 32 bit versions (both IA64 32 bit
      and IA32 32 bit).
   2. Instead of using the iaAtomic functions above, it may very well be
      possible to use the fetch_and_add apis and compare_and_swap apis, which
      I will bet have been implemented for IA64 AIX too.
      This would fix 1. as a side effect, and would handle the lack of the
      assembler.  An alternate way of doing the assembly could be via the
      pragma mc_func (although that is quite confusing).
   3. check for consistency of comments, indenting, ...

*******************************************************************************/


/*******************************************************************************

   Name
      ossAtomicInit

   Equivalent Prototype
      void ossAtomicInit( OSSAtomic * addr, OSSRegister val )

   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         Initial integer value

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

#define ossAtomicInit( addr, val )  \
   ((ossLatchInit(&((addr)->latch))),((addr)->value = (val)))

#else

#define ossAtomicInit( addr, val ) (*(addr) = (val))

#endif


/*******************************************************************************

   Name
      ossAtomicIncByValXX
      ossAtomicDecByValXX

   Equivalent Prototypes
      void ossAtomicDecByValXX( OSSAtomicXX *addr, OSSRegisterXX val )
      void ossAtomicIncByValXX( OSSAtomicXX *addr, OSSRegisterXX val )

   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         An integer value

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

#define ossAtomicIncByVal32( addr , val ) \
{ \
   ossLatchGet( &((addr)->latch) ) ; \
   (addr)->value += (val) ; \
   ossLatchRelease( &((addr)->latch) ) ; \
}

/* The above macro isn't type specific so reused it */
#define ossAtomicIncByVal64( addr , val ) ossAtomicIncByVal32( addr , val )

#elif defined SQLAIXPPC

#define ossAtomicIncByVal32( addr, val ) \
{ \
   fetch_and_add( (atomic_p)(addr), (val) ) ; \
}

#define ossAtomicIncByVal64( addr, val ) \
{ \
   fetch_and_addlp( (atomic_l)(addr), (val) ) ; \
}

#elif defined SQLSUN

#define ossAtomicIncByVal32( addr, val ) \
{ \
   OSSRegister32 old ; \
   do \
   { \
      old = *(addr) ; \
   } while ( _sqlo_lock( (void *)(addr), (old), (old) + (val) ) ) ; \
}

#define ossAtomicIncByVal64( addr, val ) \
{ \
   OSSRegister64 old ; \
   do \
   { \
      old = *(addr) ; \
   } while( _sqlo_lock64( (addr), (old), (old) + (val) ) ) ; \
}

#elif defined SQLWINT

#define ossAtomicIncByVal32( addr, val ) \
{ \
   InterlockedExchangeAdd( (PLONG)(addr), (val) ) ; \
}

#ifdef _WIN64
#define ossAtomicIncByVal64( addr, val ) \
{ \
   InterlockedExchangeAdd( (PLONG)(addr), (val) ) ; \
}
#endif

//#elif defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline void ossAtomicIncByVal32( OSSAtomic32 * addr, OSSRegister32 val )
//{
//   _asm
//   {
//      mov   ecx, addr
//      mov   eax, val
//      lock  add [ecx], eax
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline void ossAtomicIncByVal32( OSSAtomic32 * addr, OSSRegister32 val )
//{
//   __asm__ __volatile__(" movl %1 ,  %%ecx \n"
//                        " lock             \n"
//                        " add  %0, (%%ecx) "
//                        :
//                        : "r"(val), "m"(addr)
//                        : "ecx" );
//}
//
//#elif defined SQLAIX_IA64
//
//#define ossAtomicIncByVal64( addr , val ) iaAtomicIncByVal64( addr, val )
//
#else
/* 186134 DNS - commented this out because we don't use this function
                so we don't need it defined on every platform
#error Unsupported platform
*/
#endif


#define ossAtomicDecByVal32( addr, val ) ossAtomicIncByVal32( (addr), -(val) )
#define ossAtomicDecByVal64( addr, val ) ossAtomicIncByVal64( (addr), -(val) )

//#if defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline void ossAtomicDecByVal32( OSSAtomic32 * addr, OSSRegister32 val )
//{
//   _asm
//   {
//      mov   ecx, addr
//      mov   eax, val
//      lock  sub  [ecx], eax
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline void ossAtomicDecByVal32( OSSAtomic32 *addr, OSSRegister32 val )
//{
//   __asm__ __volatile__(" movl %1 ,  %%ecx \n"
//                        " lock               \n"
//                        " sub  %0, (%%ecx)  "
//                        :
//                        : "r"(val), "m"(addr)
//                        : "ecx" );
//}
//
//#endif


/*******************************************************************************

   Name
      ossAtomicIncXX
      ossAtomicDecXX

   Equivalent Prototype
      void ossAtomicIncXX( OSSAtomic32 *addr )
      void ossAtomicDecXX( OSSAtomic32 *addr )

   Input
      1. addr
         Address of an OSSAtomic type

*******************************************************************************/
#define ossAtomicInc32( addr ) ossAtomicIncByVal32( (addr), 1 )
#define ossAtomicInc64( addr ) ossAtomicIncByVal64( (addr), 1 )

//#if defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline void ossAtomicInc32( OSSAtomic32 * addr )
//{
//   _asm
//   {
//      mov   ecx,   addr
//      lock  inc    DWORD PTR   [ecx]
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline void ossAtomicInc32( OSSAtomic32 * addr )
//{
//   __asm__ __volatile__(" movl %0 ,  %%ecx \n"
//                        " lock            \n"
//                        " incl (%%ecx)    "
//                        :
//                        : "m"(addr)
//                        : "ecx" );
//}
//
//#endif


#define ossAtomicDec32( addr ) ossAtomicDecByVal32( (addr), 1 )
#define ossAtomicDec64( addr ) ossAtomicDecByVal64( (addr), 1 )

//#if defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline void ossAtomicDec32( OSSAtomic32 * addr )
//{
//   _asm
//   {
//      mov   ecx,   addr
//      lock  dec    DWORD PTR   [ecx]
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline void ossAtomicDec32( OSSAtomic32 * addr )
//{
//   __asm__ __volatile__(" movl %0 ,  %%ecx\n"
//                        " lock          \n"
//                        " decl (%%ecx)  "
//                        :
//                        : "m"(addr)
//                        : "ecx" );
//}
//
//#elif defined SQLAIX_IA64
//
//#define ossAtomicInc64( addr ) iaAtomicInc64( addr )
//#define ossAtomicDec64( addr ) iaAtomicDec64( addr )
//
//#endif


/*******************************************************************************

   Name
      ossAtomicIncByValAndRetXX
      ossAtomicDecByValAndRetXX

   Equivalent Prototype
      OSSRegisterXX ossAtomicIncByValAndRetXX( OSSAtomicXX  * addr,
                                               OSSRegisterXX val )
      OSSRegisterXX ossAtomicDecByValAndRetXX( OSSAtomicXX * addr,
                                               OSSRegisterXX val )

   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         Integer amount to increase or decrease

   Normal Return
      The original value before doing the operation.

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

inline OSSRegister32 ossAtomicIncByValAndRet32
(
   OSSAtomic32 *  addr,
   OSSRegister32  val
)
{
   OSSRegister32 old ;

   ossLatchGet( &(addr->latch) ) ;
   old = addr->value ;
   addr->value += val ;
   ossLatchRelease( &(addr->latch) ) ;

   return old ;
}

inline OSSRegister64 ossAtomicIncByValAndRet64
(
   OSSAtomic64 *  addr,
   OSSRegister64  val
)
{
   OSSRegister64 old ;

   ossLatchGet( &(addr->latch) ) ;
   old = addr->value ;
   addr->value += val ;
   ossLatchRelease( &(addr->latch) ) ;

   return old ;
}

#elif defined SQLAIXPPC

#define ossAtomicIncByValAndRet32( addr, val ) \
   fetch_and_add( (atomic_p)(addr), (val) )

#define ossAtomicIncByValAndRet64( addr, val ) \
   fetch_and_addlp( (atomic_l)(addr), (val) )

#elif defined SQLSUN

inline OSSRegister32 ossAtomicIncByValAndRet32
(
   OSSAtomic32 *  addr,
   OSSRegister32  val
)
{
   OSSRegister32 old ;

   do
   {
      old = *(addr) ;
   } while ( _sqlo_lock( (void *)addr, old , old + val ) ) ;

   return old ;
}

inline OSSRegister64 ossAtomicIncByValAndRet64
(
   OSSAtomic64 *  addr,
   OSSRegister64  val
)
{
   OSSRegister64 old ;

   do
   {
      old = *(addr) ;
   } while ( _sqlo_lock64( addr, old , old + val ) ) ;

   return old ;
}

#elif defined SQLWINT

#define ossAtomicIncByValAndRet32( addr, val ) \
   InterlockedExchangeAdd( (PLONG)(addr), (val) )
#ifdef _WIN64
#define ossAtomicIncByValAndRet64( addr, val ) \
   InterlockedExchangeAdd( (PLONG)(addr), (val) )
#endif

//#elif defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline OSSRegister32 ossAtomicIncByValAndRet32(
//      OSSAtomic32 * addr,
//      OSSRegister32 val )
//{  _asm
//   {
//      mov   ecx,  addr
//      mov   eax,  val
//      lock  xadd  [ecx], eax
//   }
//}

#elif defined SQLLinux && defined SQLO_INTEL_IA32

inline OSSRegister32 ossAtomicIncByValAndRet32(
      OSSAtomic32 * addr,
      OSSRegister32 val )
{
   OSSRegister32 old;

   __asm__ __volatile__(" mov %2 ,  %%ecx \n"
                        " movl %1, %0   \n"
                        " lock          \n"
                        " xadd %0, (%%ecx)"
                        : "=a"(old)
                        : "r" (val) ,"m"(addr)
                        : "ecx" );
   return old ;
}
#elif defined SQLLinux && defined SQLO_INTEL_EM64T

inline OSSRegister32 ossAtomicIncByValAndRet32(
      OSSAtomic32 * addr,
      OSSRegister32 val )
{
   OSSRegister32 old;

   __asm__ __volatile__(" mov %2 ,  %%rcx \n"
                        " mov %1, %0   \n"
                        " lock          \n"
                        " xadd %0, (%%rcx)"
                        : "=a"(old)
                        : "r" (val) ,"m"(addr)
                        : "rcx" );
   return old ;
}

inline OSSRegister64 ossAtomicIncByValAndRet64(
      OSSAtomic64 * addr,
      OSSRegister64 val )
{
   OSSRegister64 old;

   __asm__ __volatile__(" mov %2 ,  %%rcx \n"
                        " mov %1, %0   \n"
                        " lock          \n"
                        " xadd %0, (%%rcx)"
                        : "=a"(old)
                        : "r" (val) ,"m"(addr)
                        : "rcx" );
   return old ;
}

#elif defined(SQLLinux) && defined(__linux__) && defined(__powerpc__)

inline OSSRegister32 ossAtomicIncByValAndRet32(OSSAtomic32 * addr, OSSRegister32 val )
{
	return atomic_add_return(val, (atomic_t *)addr);
}

inline OSSRegister64 ossAtomicIncByValAndRet64(OSSAtomic64 * addr, OSSRegister64 val )
{
	return atomic_add_return(val, (atomic_t *)addr);
}

#elif defined(SQLLinux) && defined(__linux__) && defined(__s390__)

inline OSSRegister32 ossAtomicIncByValAndRet32(
      OSSAtomic32 * addr,
      OSSRegister32 val )
{
   OSSRegister32 old ;

   do
   {
      old = *(addr) ;
#if !defined(USE_GCC_ATOMICS)
   } while ( atomic_compare_and_swap( old, old + val, (atomic_t*) addr )) ;
#else
   } while ( atomic_compare_and_swap( old, old + val, addr )) ;
#endif
   return old ;
}

// Added the following 64bit fcn (note: no atomic_t* cast) - sl
#ifdef __s390x__
inline OSSRegister64 ossAtomicIncByValAndRet64(
      OSSAtomic64 * addr,
      OSSRegister64 val )
{
   OSSRegister64 old ;

   do
   {
      old = *(addr) ;
#if !defined(USE_GCC_ATOMICS)
   } while ( atomic_compare_and_swap( old, old + val, (atomic_t*)addr )) ;
#else
   } while ( atomic_compare_and_swap( old, old + val, addr )) ;
#endif
   return old ;
}
#endif

//
//#elif defined SQLAIX_IA64
//
//#define ossAtomicIncByValAndRet64( addr, val ) iaAtomicIncByVal64( addr, val )
//
#elif defined MVS

#ifdef __cplusplus
inline
OSSRegister32 ossAtomicIncByValAndRet32(
                OSSAtomic32 *addr,  // memory location to increase the value
                OSSRegister32 val // the size to increase
                )
#else
#pragma inline(ossAtomicIncByValAndRet32)
OSSRegister32 ossAtomicIncByValAndRet32(
                OSSAtomic32 *addr,  // memory location to increase the value
                OSSRegister32 val // the size to increase
                )
#endif
{
   OSSRegister32 orig = *addr;
   while ( cs( &orig, addr, orig + val) ) ;
   return orig;
}

#elif defined SQL_OS400

inline OSSRegister32 ossAtomicIncByValAndRet32(
      OSSAtomic32 * addr,
      OSSRegister32 val )
{
   OSSRegister32 orig = *addr;
   while ( !_CMPSWP( (void *)&orig, (void *)addr, orig + val) ) ;
   return orig;
}
#else

#error Unsupported platform

#endif


#define ossAtomicDecByValAndRet32( addr, val ) \
   ossAtomicIncByValAndRet32( addr, -(val) )

#define ossAtomicDecByValAndRet64( addr, val ) \
   ossAtomicIncByValAndRet64( addr, -(val) )

//#if defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline OSSRegister32 ossAtomicDecByValAndRet32(
//      OSSAtomic32 * addr,
//      OSSRegister32 val )
//{
//   _asm
//   {
//      mov   ecx,  addr
//      mov   eax,  val
//      neg   eax
//      lock  xadd  [ecx], eax
//   }
//}
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline OSSRegister32 ossAtomicDecByValAndRet32(
//      OSSAtomic32 * addr,
//      OSSRegister32 val )
//{
//   OSSRegister32 old;
//   __asm__ __volatile__(" mov %2 ,  %%ecx \n"
//                        " movl %1, %0     \n"
//                        " neg  %0         \n"
//                        " lock            \n"
//                        " xadd  %0, (%%ecx) "
//                        : "=a"(old)
//                        : "r" (val) ,"m"(addr)
//                        : "ecx" );
//   return  old;
//}


/*******************************************************************************

   Name
      ossAtomicIncAndRetXX
      ossAtomicDecAndRetXX

   Equivalent Prototype
      OSSRegisterXX ossAtomicIncAndRetXX( OSSAtomicXX *addr )
      OSSRegisterXX ossAtomicDecAndRetXX( OSSAtomicXX *addr )

   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         An integer amount to increase or decrease

   Normal Return
      The original value before doing the operation.

*******************************************************************************/
#define ossAtomicIncAndRet32( addr ) ossAtomicIncByValAndRet32( (addr), 1 )
#define ossAtomicIncAndRet64( addr ) ossAtomicIncByValAndRet64( (addr), 1 )

#define ossAtomicDecAndRet32( addr ) ossAtomicDecByValAndRet32( (addr), 1 )
#define ossAtomicDecAndRet64( addr ) ossAtomicDecByValAndRet64( (addr), 1 )

//#if defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline OSSRegister32 ossAtomicIncAndRet32( OSSAtomic32 * addr )
//{
//   _asm
//   {
//      mov   ecx,  addr
//      mov   eax,  1
//      lock  xadd  [ecx], eax
//   }
//}
//
//__inline OSSRegister32 ossAtomicDecAndRet32( OSSAtomic32 * addr )
//{
//   _asm
//   {
//      mov   ecx,  addr
//      mov   eax,  -1
//      lock  xadd  [ecx], eax
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline OSSRegister32 ossAtomicIncAndRet32( OSSAtomic32 * addr )
//{
//   OSSRegister32 old;
//
//   __asm__ __volatile__(" movl $1 ,  %0 \n"
//                        " movl %1 ,  %%ecx    \n"
//                        " lock                \n"
//                        "  xaddl  %0, (%%ecx) "
//                        : "=a"(old)
//                        : "m"(addr)
//                        : "ecx" );
//   return old;
//}
//
//inline OSSRegister32 ossAtomicDecAndRet32( OSSAtomic32 * addr )
//{
//   OSSRegister32 old;
//
//   __asm__ __volatile__(" movl $-1 ,  %0 \n"
//                        " movl %1,  %%ecx  \n"
//                        " lock                   \n"
//                        " xadd  %0, (%%ecx) "
//                        : "=a"(old)
//                        : "m"(addr)
//                        : "ecx" );
//
//   return old;
//}
//
//#elif defined SQLAIX_IA64
//
//#define ossAtomicDecAndRet64( addr ) iaAtomicDec64( addr )
//
//#endif


/*******************************************************************************

   Name
      ossAtomicPeekXX

   Equivalent prototype
       OSSRegisterXX ossAtomicPeekXX( OSSAtomicXX * addr )

   Input
      1. addr
         Address of an OSSAtomic type

   Normal Return
      The value at the specified address

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS
#define ossAtomicPeek32( addr ) ((addr)->value)
#else
#define ossAtomicPeek32( addr ) (*(addr))
#endif

/* Macro above is non type specific */
#define ossAtomicPeek64( addr ) ossAtomicPeek32( (addr) )


/*******************************************************************************

   Name
      ossAtomicPokeXX

   Equivalent prototype
      void AtomicPokeXX( OSSAtomicXX * addr, OSSRegisterXX val )

   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         New integer amount to assign

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

#define ossAtomicPoke32( addr, val ) \
{ \
   ossLatchGet( &((addr)->latch) ) ; \
   (addr)->value = (val) ; \
   ossLatchRelease( &((addr)->latch) ) ; \
}

/* Above macro non type specific */
#define ossAtomicPoke64( addr, val ) ossAtomicPoke32( addr, val )

#elif defined SQLAIXPPC

#define ossAtomicPoke32( addr, val ) \
{ \
   while ( !compare_and_swap( (atomic_p)(addr), (int *)(addr), (val) ) ) ; \
}

#define ossAtomicPoke64( addr, val ) \
{ \
   while ( !compare_and_swaplp( (atomic_l)(addr), (long *)(addr), (val) ) ) ; \
}

#elif defined SQLSUN

#define ossAtomicPoke32( addr, val ) \
{ \
   while ( _sqlo_lock( (void *)(addr), *(addr), (val) ) ) ; \
}

#define ossAtomicPoke64( addr, val ) \
{ \
   while ( _sqlo_lock64( (addr), *(addr), (val) ) ) ; \
}

#elif defined SQLWINT

#define ossAtomicPoke32( addr, val ) \
{ \
   InterlockedExchange( (LPLONG)(addr), (val) ) ; \
}
#ifdef _WIN64
#define ossAtomicPoke64( addr, val ) \
{ \
   InterlockedExchange( (LPLONG)(addr), (val) ) ; \
}
#endif

//#elif defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline void ossAtomicPoke32( OSSAtomic32 * addr, OSSRegister32 val )
//{
//   _asm
//   {
//      mov   ecx,   addr
//      mov   eax,   val
//      lock  xchg   [ecx],   eax
//   }
//}
//
#elif defined SQLLinux && defined SQLO_INTEL_IA32
inline void ossAtomicPoke32( OSSAtomic32 * addr, OSSRegister32 val )
{
   __asm__ __volatile__("movl %0 ,  %%eax \n"
                        " movl %1 ,  %%ecx      \n"
                        " lock                  \n"
                        "  xchgl  %%eax, (%%ecx) "
                        :
                        : "r"(val), "m"(addr)
                        : "eax","ecx" );

}
#elif defined SQLLinux && defined SQLO_INTEL_EM64T

inline void ossAtomicPoke32( OSSAtomic32 * addr, OSSRegister32 val )
{
   __asm__ __volatile__("mov %0 ,  %%eax \n"
                        " mov %1 ,  %%ecx      \n"
                        " lock                  \n"
                        "  xchgl  %%eax, (%%ecx) "
                        :
                        : "r"(val), "m"(addr)
                        : "eax","ecx" );

}

inline void ossAtomicPoke64( OSSAtomic64 * addr, OSSRegister64 val )
{
   __asm__ __volatile__(" mov %0 , %%rax \n"
			" mov %1 ,  %%rcx      \n"
                        " lock                  \n"
                        " xchg  %%rax, (%%rcx) "
                        :
                        : "r"(val), "m"(addr)
                        : "rax","rcx" );

}

#elif defined(SQLLinux) && defined(__linux__) && defined(__powerpc__)
	#define ossAtomicPoke32( addr, val ) atomic_set( (atomic_t *)(addr), (val) )
	#define ossAtomicPoke64( addr, val ) atomic_set( (atomic_t *)(addr), (val) )

#elif defined(SQLLinux) && defined(__linux__) && defined(__s390__)
#if !defined(USE_GCC_ATOMICS)
	#define ossAtomicPoke32( addr, val ) atomic_set( (atomic_t *)(addr), (val) )
	#define ossAtomicPoke64(addr,val) atomic_set( (atomic_t *)(addr), (val) )
#else

	// replaced atomic_set(addr,val) with an alternative that doesn't rely on
	// the atomic.h kernel header
	// made regular assignment, no more atomic than what was being done before
	// other alternative is to find a new function, maybe use xchg alternative,
	// or use OSSRegister32 version below, make a 64bit version as well
	#define ossAtomicPoke32(addr,val) __sync_lock_test_and_set(addr,val)
	#define ossAtomicPoke64(addr,val) __sync_lock_test_and_set(addr,val)

	// defined atomic_set(v,i) as (((v)->counter) = (i))
	// above function used to not return anything, this function has a return value
	// similar to pokeandret function, best solution for now - sl
#endif
/* 186134 DNS - the definition above seems to work so we won't use the definition below
inline void ossAtomicPoke32( OSSAtomic32 * addr, OSSRegister32 val )
{
   OSSRegister32 old ;

   do
   {
      old = *(addr) ;
   } while ( atomic_compare_and_swap( old, val, (void *)addr) ) ;

   return;
}
*/

//
//#elif defined SQLAIX_IA64
//
//#ifdef SQLO_ARCH_P64
//#define ossAtomicPoke64( addr, val ) iaAtomicChange64( addr, val )
//#endif
//
#elif defined MVS

#ifdef __cplusplus
inline
void ossAtomicPoke32(
                OSSAtomic32 *addr,  // memory location to set to the value
                OSSRegister32 val // the new value
                )
#else
#pragma inline(ossAtomicPoke32)
void ossAtomicPoke32(
                OSSAtomic32 *addr,  // memory location to set the value
                OSSRegister32 val // the new value
                )
#endif
{
   OSSRegister32 orig = *addr;
   while ( cs( &orig, addr, val) ) ;
   return;
}

#elif defined SQL_OS400
inline void ossAtomicPoke32( OSSAtomic32 * addr, OSSRegister32 val )
{
   OSSRegister32 orig = *addr;
   while ( !_CMPSWP( (void *)&orig, (void *)addr, val) ) ;
   return;
}
#else

#error Unsupported platform

#endif


/*******************************************************************************

   Name
      ossAtomicPokeAndRetXX

   Equivalent prototype
      OSSRegisterXX ossAtomicPokeAndRetXX( OSSAtomicXX * addr,
                                           OSSRegisterXX val )
   Input
      1. addr
         Address of an OSSAtomic type
      2. val
         New integer amount to assign

   Normal Return
      The original value before being changed

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

inline OSSRegister32 ossAtomicPokeAndRet32
(
   OSSAtomic32 *  addr,
   OSSRegister32  val
)
{
   OSSRegister32 old ;

   ossLatchGet( &(addr->latch) ) ;
   old = addr->value ;
   addr->value = val ;
   ossLatchRelease( &(addr->latch) ) ;

   return old ;
}

inline OSSRegister64 ossAtomicPokeAndRet64
(
   OSSAtomic64 *  addr,
   OSSRegister64  val
)
{
   OSSRegister64 old ;

   ossLatchGet( &(addr->latch ) ) ;
   old = addr->value ;
   addr->value = val ;
   ossLatchRelease( &(addr->latch ) ) ;

   return old ;
}

#elif defined SQLAIXPPC

inline OSSRegister32 ossAtomicPokeAndRet32
(
   OSSAtomic32 *  addr,
   OSSRegister32  val
)
{
   OSSRegister32 old ;

   do
   {
      old = *addr ;
   } while ( !compare_and_swap( (atomic_p)addr, (int *)addr, val ) ) ;

   return old ;
}

inline OSSRegister64 ossAtomicPokeAndRet64
(
   OSSAtomic64 *  addr,
   OSSRegister64  val
)
{
   OSSRegister64 old ;

   do
   {
       old = *addr;
   } while ( !compare_and_swaplp( (atomic_l)addr, (long *)addr, val ) ) ;

   return old;
}

#elif defined SQLSUN

inline OSSRegister32 ossAtomicPokeAndRet32
(
   OSSAtomic32 *  addr,
   OSSRegister32  val
)
{
   OSSRegister32 old ;

   do
   {
      old = *(addr) ;
   } while ( _sqlo_lock( (void *)addr, old, val ) ) ;

   return old ;
}

inline OSSRegister64 ossAtomicPokeAndRet64
(
   OSSAtomic64 *  addr,
   OSSRegister64  val
)
{
   OSSRegister64 old ;

   do
   {
      old = *addr ;
   } while ( _sqlo_lock64( addr, old, val ) ) ;

   return old ;
}

#elif defined SQLWINT

#define ossAtomicPokeAndRet32( addr, val ) \
   InterlockedExchange( (LPLONG)(addr), (val) ) ;

//#elif defined SQLWINT && defined SQLO_INTEL_IA32
//
//__inline OSSRegister32 ossAtomicPokeAndRet32(
//      OSSAtomic32 * addr,
//      OSSRegister32 val )
//{
//   _asm
//   {
//      mov   ecx,   addr
//      mov   eax,   val
//      lock  xchg   [ecx],   eax
//   }
//}
//
//#elif defined SQLLinux && defined SQLO_INTEL_IA32
//
//inline OSSRegister32 ossAtomicPokeAndRet32(
//      OSSAtomic32 * addr,
//      OSSRegister32 val )
//{
//   OSSRegister32 old ;
//
//   __asm__ __volatile__(" mov %2 ,  %%ecx \n"
//                        " movl %1, %0      \n"
//                        " lock             \n"
//                        " xchg  %0, (%%ecx)  "
//                        : "=a"(old)
//                        : "r"(val), "m"(addr)
//                        : "ecx" );
//
//   return old ;
//}
//
//#elif defined SQLAIX_IA64
//
//#define ossAtomicPokeAndRet64( addr, val ) iaAtomicChange64( addr, val )
//
#else
/* 186134 DNS - commented this out because we don't use this function
                so we don't need it defined on every platform
#error Unsupported platform
*/
#endif


/*******************************************************************************

   Name
      ossAtomicCompareAndPokeXX

   Equivalent prototype
      OSSRegisterXX ossAtomicCompareAndPokeXX( OSSAtomicXX * addr,
                                               OSSRegisterXX comp,
                                               OSSRegisterXX val )

   Input
      1. addr
         Address of an OSSAtomic type
      2. comp
         An integer value to compare
      3. val
         New integer amount to assign if the old value equals the
         value of comp.

   Return
      Non-zero if successful.  Otherwise the return code is zero.

*******************************************************************************/
#if !defined OSS_ATOMIC_USE_PLATFORM_INSTRUCTIONS

inline OSSRegister32 ossAtomicCompareAndPoke32
(
   OSSAtomic32 *  addr,
   OSSRegister32  comp,
   OSSRegister32  val
)
{
   OSSRegister32 rc = 1 ;

   ossLatchGet( &(addr)->latch ) ;

   if ( (comp) == (addr)->value )
   {
      addr->value = val ;
   }
   else
   {
      rc = 0 ;
   }

   ossLatchRelease( &(addr)->latch ) ;

   return rc ;
}

inline OSSRegister64 ossAtomicCompareAndPoke64
(
   OSSAtomic64 *  addr,
   OSSRegister64  comp,
   OSSRegister64  val
)
{
   OSSRegister64 rc = 1 ;

   ossLatchGet( &(addr)->latch ) ;

   if ( (comp) == (addr)->value )
   {
      addr->value = val ;
   }
   else
   {
      rc = 0 ;
   }

   ossLatchRelease( &(addr)->latch ) ;

   return rc ;
}

#elif defined SQLAIXPPC

inline OSSRegister32 ossAtomicCompareAndPoke32
(
   OSSAtomic32 *  addr,
   OSSRegister32  comp,
   OSSRegister32  val
)
{
   return compare_and_swap( (atomic_p)addr, (int *)&comp, val ) ;
}

inline OSSRegister64 ossAtomicCompareAndPoke64
(
   OSSAtomic64 *  addr,
   OSSRegister64  comp,
   OSSRegister64  val
)
{
   return compare_and_swaplp( (atomic_l)addr, (long *)&comp, val ) ;
}

#elif defined SQLSUN

#define ossAtomicCompareAndPoke32( addr, comp, val ) \
   !( _sqlo_lock( (void *)(addr), (comp), (val) ) )

#define ossAtomicCompareAndPoke64( addr, comp, val ) \
   !( _sqlo_lock64( (addr), (comp), (val) ) )

#elif defined SQLWINT

inline OSSRegister32 ossAtomicCompareAndPoke32
(
   OSSAtomic32 *  addr,
   OSSRegister32  comp,
   OSSRegister32  val
)
{
   OSSRegister32 *old ;
/* 186134 - changed this so it would compile on Win NT and because the return
            value was being interpretted incorrectly - a PVOID is returned,
            not an int
   old = InterlockedCompareExchange( (LPLONG)addr, (LONG)val, (LONG)comp ) ;
*/
   old = (OSSRegister32 *)InterlockedCompareExchange( (PLONG)&addr, (LONG)&val, (LONG)&comp ) ;
   return (OSSRegister32)( *old == comp ) ;
}
#ifdef _WIN64
inline OSSRegister64 ossAtomicCompareAndPoke64
(
   OSSAtomic64 *  addr,
   OSSRegister64  comp,
   OSSRegister64  val
)
{
   OSSRegister64* old ;
   OSSRegister64* old1 ;

/* 186134 - changed this so it would compile on Win NT and because the return
            value was being interpretted incorrectly - a PVOID is returned,
            not an int
   old = InterlockedCompareExchange( (LPLONG)addr, (LONG)val, (LONG)comp ) ;
*/
   old = (OSSRegister64 *)InterlockedCompareExchange64( (volatile LONGLONG *)&addr, (LONG)&val, (LONG)&comp ) ;
   return (OSSRegister64)( *old == comp ) ;
}
#endif


//#elif defined SQLWINT && defined SQLO_INTEL_IA32
//
//inline OSSRegister32 ossAtomicCompareAndPoke32
//(
//   OSSAtomic32 *  addr,
//   OSSRegister32  comp,
//   OSSRegister32  val
//)
//{
//	__asm
//	{
//         mov            eax, comp
// 			mov				ecx, addr
//         mov            edx, val
//         lock cmpxchg   [ecx], edx  /* If successful, ZF is set */
//         sete           al          /* If ZF flag is set, al = 1, else al = 0. */
//         movzx			   eax, al
//	}
//
// Here's another way to do this.  The above method is much more optimal.
//
// OSSRegister32  rc ;
//
//	__asm
//	{
//			mov				eax, comp
//			mov				ecx, addr
//			mov				edx, val
//			lock cmpxchg	[ecx], edx
//
//			/* If cmpxchg is successful, the ZF flag is set. */
//			je				success
//
//			/* Set the return value to zero */
//			mov				rc, 0
//			jmp				end
//
//			/* Set the return value to non-zero */
//		success:
//			mov				rc, 1
//		end:
//   }
//
//   return rc ;
//}
//
#elif defined SQLLinux && defined SQLO_INTEL_IA32

inline OSSRegister32 ossAtomicCompareAndPoke32
(
   OSSAtomic32 *  addr,
   OSSRegister32  comp,
   OSSRegister32  val
)
{
/*
   OSSRegister32  rc ;

   __asm__ __volatile__( "\tmovl %1, %%eax\n"
                         "\tmovl %2, %%ecx\n"
                         "\tmovl %3, %%edx\n"
                         "\tlock\n"
                         "\tcmpxchg %%edx, (%%ecx)\n"
                         "\tje 0f\n"
                         "\tmovl $0, %0\n"
                         "\tjmp 1f\n"
                         "0:\n"
                         "\tmov $1, %0\n"
                         "1:\n"
                         : "=a"(rc)
                         : "r"(comp), "m"(addr), "r"(val)
		      	          : "eax", "ecx", "edx" ) ;
   return rc ;
*/
	return (comp == cmpxchg(addr, comp, val));
}

#elif defined SQLLinux && defined SQLO_INTEL_EM64T

inline OSSRegister64 ossAtomicCompareAndPoke64
(
   OSSAtomic64 *  addr,
   OSSRegister64  comp,
   OSSRegister64  val
)
{
/*
   OSSRegister32  rc ;

   __asm__ __volatile__( "\tmovl %1, %%eax\n"
                         "\tmovl %2, %%ecx\n"
                         "\tmovl %3, %%edx\n"
                         "\tlock\n"
                         "\tcmpxchg %%edx, (%%ecx)\n"
                         "\tje 0f\n"
                         "\tmovl $0, %0\n"
                         "\tjmp 1f\n"
                         "0:\n"
                         "\tmov $1, %0\n"
                         "1:\n"
                         : "=a"(rc)
                         : "r"(comp), "m"(addr), "r"(val)
		      	          : "eax", "ecx", "edx" ) ;
   return rc ;
*/
	return (comp == cmpxchg(addr, comp, val));
}
#elif defined(__linux__) && defined(__powerpc__)
inline OSSRegister32 ossAtomicCompareAndPoke32(OSSAtomic32 *addr, OSSRegister32 comp, OSSRegister32 val)
{
	return (comp == __cmpxchg_u32((volatile int*)addr, comp, val));
}

inline OSSRegister64 ossAtomicCompareAndPoke64(OSSAtomic64 *addr, OSSRegister64 comp, OSSRegister64 val)
{
	return (comp == __cmpxchg_u64((volatile long int*)addr, comp, val));
}

#elif defined(SQLLinux) && defined(__linux__) && defined(__s390__)
	// (atomic *) cast removed - sl
	#define ossAtomicCompareAndPoke32( addr, comp, val ) \
		!( atomic_compare_and_swap(comp, val, addr) )

	#ifdef __s390x__
	#define ossAtomicCompareAndPoke64( addr, comp, val ) \
		!( atomic_compare_and_swap(comp, val, addr) )
	#endif

#elif defined MVS

#ifdef __cplusplus
inline
OSSRegister32 ossAtomicCompareAndPoke32(
                OSSAtomic32 *addr,  // memory location to set to the value
                OSSRegister32 comp, // value to compare
                OSSRegister32 val   // the new value
                )
#else
#pragma inline(ossAtomicCompareAndPoke32)
OSSRegister32 ossAtomicCompareAndPoke32(
                OSSAtomic32 *addr,  // memory location to set to the value
                OSSRegister32 comp, // value to compare
                OSSRegister32 val   // the new value
                )
#endif
{
   OSSRegister32 orig = comp;
   return(!cs(&orig, addr, val) ) ;
}

#elif defined SQL_OS400
inline OSSRegister32 ossAtomicCompareAndPoke32
(
   OSSAtomic32 *  addr,
   OSSRegister32  comp,
   OSSRegister32  val
)
{
   OSSRegister32 orig = comp;
   return(_CMPSWP((void *)&orig, (void *)addr, val) ) ;
}

//
#else

#error Unsupported platform

#endif


/* Re-enable the "no return value" warning on MSVC++ */
#if defined SQLWINT && defined _MSC_VER
#pragma warning( default : 4035 )
#endif


#endif
