Skip to content

File porting.h

File List > base > porting.h

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * porting.h - Functions supporting platform porting
 */

#ifndef _PORTING_H_
#define _PORTING_H_

#ident "$Id$"

#include "config.h"

#if defined (AIX)
#include <sys/socket.h>
#endif

#if !defined (__GNUC__)
#define __attribute__(X)
#endif

#if defined (__GNUC__) && defined (__GNUC_MINOR__) && defined (__GNUC_PATCHLEVEL__)
#define CUB_GCC_VERSION (__GNUC__ * 10000 \
             + __GNUC_MINOR__ * 100 \
             + __GNUC_PATCHLEVEL__)
#endif

#if defined (WINDOWS)
#ifdef CUBRID_EXPORTING
#define EXPORT_IMPORT    __declspec(dllexport)
#else
#define EXPORT_IMPORT    __declspec(dllimport)
#endif
#else /* WINDOWS */
  // all symbols are exported by default
#define EXPORT_IMPORT
#endif /* WINDOWS */

#if defined (WINDOWS)
#define L_cuserid 9
#else /* WINDOWS */
#ifndef L_cuserid
#define L_cuserid 9
#endif /* !L_cuserid */
#endif /* WINDOWS */

#define ONE_K       1024
#define ONE_M       1048576
#define ONE_G       1073741824
#define ONE_T       1099511627776LL
#define ONE_P       1125899906842624LL

#define ONE_SEC     1000
#define ONE_MIN     60000
#define ONE_HOUR    3600000

#define CTIME_MAX 64

#ifndef LLONG_MAX
#define LLONG_MAX   9223372036854775807LL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN   (-LLONG_MAX - 1LL)
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX  18446744073709551615ULL
#endif


#define MEM_SIZE_IS_VALID(size) \
  (((long long unsigned) (size) <= ULONG_MAX) \
   || (sizeof (long long unsigned) <= sizeof (size_t)))

#if defined (__cplusplus)
#include <type_traits>
#include <utility>
#endif // C++

#if defined (WINDOWS)
#include <fcntl.h>
#include <direct.h>
#include <process.h>
#include <sys/timeb.h>
#include <time.h>
#include <sys/locking.h>
#include <windows.h>
#include <winbase.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <assert.h>

#if !defined (ENOMSG)
/* not defined errno on Windows */
#define ENOMSG      100
#endif

#if !defined PATH_MAX
#define PATH_MAX    256
#endif
#if !defined NAME_MAX
#define NAME_MAX    256
#endif

#if !defined (_MSC_VER) || _MSC_VER < 1700 || (defined __cplusplus && _MSC_VER == 1700)
#define log2(x)                 (log ((double) x) / log ((double) 2))
#endif /* !_MSC_VER or c before _MSC_VER 1700 or c++ at 1700 */
extern char *realpath (const char *path, char *resolved_path);
#define sleep(sec) Sleep(1000*(sec))
#define usleep(usec) Sleep((usec)/1000)

#define mkdir(dir, mode)        _mkdir(dir)
#define getpid()                _getpid()
#define snprintf                    _sprintf_p
#define strcasecmp(str1, str2)      _stricmp(str1, str2)
#define strncasecmp(str1, str2, size)     _strnicmp(str1, str2, size)
#define lseek(fd, offset, origin)   _lseeki64(fd, offset, origin)
#define fseek(fd, offset, origin)   _fseeki64(fd, offset, origin)
#define ftruncate(fd, size)     _chsize_s(fd, size)
#define strdup(src)                 _strdup(src)
#define getcwd(buffer, length) _getcwd(buffer, length)
#define popen _popen
#define pclose _pclose
#define strtok_r            strtok_s
#define strtoll             _strtoi64
#define strtoull            _strtoui64
// todo - remove define stat; name is too common
#define stat            _stati64
#define fstat           _fstati64
#define ftell           _ftelli64
#define ftime           _ftime_s
#define timeb           _timeb
#define fileno      _fileno
#define vsnprintf   cub_vsnprintf
#define tempnam         _tempnam
#define printf          _printf_p
#define fprintf         _fprintf_p
#define vfprintf        _vfprintf_p
#define vprintf         _vprintf_p
#define strtof      strtof_win
#define strndup         strndup_win

#if defined (_WIN32)
#define mktime         mktime_for_win32
#endif
#if (_WIN32_WINNT < 0x0600)
#define POLLRDNORM  0x0100
#define POLLRDBAND  0x0200
#define POLLIN      (POLLRDNORM | POLLRDBAND)
#define POLLPRI     0x0400

#define POLLWRNORM  0x0010
#define POLLOUT     (POLLWRNORM)
#define POLLWRBAND  0x0020

#define POLLERR     0x0001
#define POLLHUP     0x0002
#define POLLNVAL    0x0004

struct pollfd
{
  SOCKET fd;
  SHORT events;
  SHORT revents;
};
#endif /* (_WIN32_WINNT < 0x0600) */

typedef unsigned long int nfds_t;
extern int poll (struct pollfd *fds, nfds_t nfds, int timeout);

#if 0
#define O_RDONLY                _O_RDONLY
#endif
#define O_SYNC                  0



#undef O_CREAT
#undef O_RDWR
#undef O_RDONLY
#undef O_TRUNC
#undef O_EXCL

#define O_CREAT _O_CREAT|_O_BINARY
#define O_RDWR _O_RDWR|_O_BINARY
#define O_RDONLY _O_RDONLY|_O_BINARY
#define O_TRUNC _O_TRUNC|_O_BINARY
#define O_EXCL _O_EXCL|_O_BINARY

/* Fake up approxomate DOS definitions see sys/stat.h */
/* for umask() stub */
#define S_IRGRP 0
#define S_IWGRP 0
#define S_IROTH 0
#define S_IWOTH 0

/* read, write, execute for owner */
#define S_IRWXU _S_IREAD | _S_IWRITE | _S_IEXEC
/* rwx for group, same as owner since there are no groups in DOS */
#define S_IRWXG S_IRWXU
/* rwx for other, same as owner since there are no groups in DOS */
#define S_IRWXO S_IRWXU

/* access() mode flags */
#define F_OK    0       /* Test for existence.  */
#define W_OK    2       /* Test for write permission.  */
#define R_OK    4       /* Test for read permission.  */

/* definitions for the WINDOWS implementation of lockf() */
#define F_ULOCK     _LK_UNLCK
#define F_LOCK      _LK_LOCK
#define F_TLOCK     _LK_NBLCK
#define F_TEST      -1

/* definitions for the WINDOWS implmentation of pathconf() */
#define _PC_NAME_MAX 4
#define _PC_PATH_MAX 5
#define _PC_NO_TRUNC 8

typedef char *caddr_t;

typedef SSIZE_T ssize_t;

#if 0
struct stat
{
  _dev_t st_dev;
  _ino_t st_ino;
  unsigned short st_mode;
  short st_nlink;
  short st_uid;
  short st_gid;
  _dev_t st_rdev;
  _off_t st_size;
  time_t st_atime;
  time_t st_mtime;
  time_t st_ctime;
};
extern int stat (const char *path, struct stat *buf);
#endif

extern int gettimeofday (struct timeval *tp, void *tzp);

extern int lockf (int fd, int cmd, long size);

extern char *cuserid (char *string);

extern int getlogin_r (char *buf, size_t bufsize);

extern struct tm *localtime_r (const time_t * time, struct tm *tm_val);

extern char *ctime_r (const time_t * time, char *time_buf);

#if 0
extern int umask (int mask);
#endif
int fsync (int filedes);

long pathconf (char *path, int name);

/*
 * Used by the sigfillset() etc. function in pcio.c
 */
typedef struct sigsettype
{
  unsigned int mask;
  void (*abrt_state) (int);
  void (*fpe_state) (int);
  void (*ill_state) (int);
  void (*int_state) (int);
  void (*term_state) (int);
  void (*sev_state) (int);
} sigset_t;

int sigfillset (sigset_t * set);

int sigprocmask (int how, sigset_t * set, sigset_t * oldset);

/*
 * MS Windows specific operations
 */
extern void pc_init (void);
extern void pc_final (void);
#if defined (ENABLE_UNUSED_FUNCTION)
extern int lock_region (int fd, int cmd, long offset, long size);
#endif
extern int free_space (const char *, int);

#define _longjmp                longjmp
/*
#define _setjmp                 setjmp
*/
#else /* WINDOWS */

#if !defined (HAVE_CTIME_R)
#error "HAVE_CTIME_R"
#endif

#if !defined (HAVE_LOCALTIME_R)
#error "HAVE_LOCALTIME_R"
#endif

#if !defined (HAVE_DRAND48_R)
#error "HAVE_DRAND48_R"
#endif
#endif /* WINDOWS */

#define snprintf_dots_truncate(dest, max_len, ...) \
  if (snprintf (dest, max_len, __VA_ARGS__) < 0) \
    snprintf (dest + max_len - 4, 4, "...")
#define strncpy_size(buf, str, size) \
  strncpy (buf, str, size); buf[(size) - 1] = '\0'
#if defined (__cplusplus)
// *INDENT-OFF*
template<typename T>
inline void
check_is_array (const T & a)
{
  static_assert (std::is_array<T>::value == 1, "expected array");
}
#define strncpy_bufsize(buf, str) \
  strncpy_size (buf, str, sizeof (buf)); check_is_array (buf)
// *INDENT-ON*
#else // not C++
#define strncpy_bufsize(buf, str) \
  strncpy_size (buf, str, sizeof (buf))
#endif // not C++

#if defined (WINDOWS)
#define PATH_SEPARATOR  '\\'
#else /* WINDOWS */
#define PATH_SEPARATOR  '/'
#endif /* WINDOWS */
#define PATH_CURRENT    '.'

#if defined (WINDOWS)
#define IS_PATH_SEPARATOR(c) ((c) == PATH_SEPARATOR || (c) == '/')
#else
#define IS_PATH_SEPARATOR(c) ((c) == PATH_SEPARATOR)
#endif

#if defined (WINDOWS)
#define IS_ABS_PATH(p) IS_PATH_SEPARATOR((p)[0]) \
    || (isalpha((p)[0]) && (p)[1] == ':' && IS_PATH_SEPARATOR((p)[2]))
#else /* WINDOWS */
#define IS_ABS_PATH(p) IS_PATH_SEPARATOR((p)[0])
#endif /* WINDOWS */

/*
 * Some platforms (e.g., Solaris) evidently don't define _longjmp.  If
 * it's not available, just use regular old longjmp.
 */
#if defined (SOLARIS) || defined (WINDOWS)
#define LONGJMP longjmp
#define SETJMP setjmp
#else
#define LONGJMP _longjmp
#define SETJMP _setjmp
#endif

#define CUB_MAXHOSTNAMELEN 256  /* 255 + 1(for NULL terminator) */

#define GETHOSTNAME(p, l) css_gethostname(p, l)

#if defined (WINDOWS)
#define FINITE(x) _finite(x)
#elif defined (HPUX)
#define FINITE(x) isfinite(x)
#else /* ! WINDOWS && ! HPUX */
#define FINITE(x) finite(x)
#endif

#if defined (WINDOWS)
#define difftime64(time1, time2) _difftime64(time1, time2)
#else /* !WINDOWS */
#define difftime64(time1, time2) difftime(time1, time2)
#endif /* !WINDOWS */

#if defined (WINDOWS)
#ifndef wcswcs
#define wcswcs(ws1, ws2)     wcsstr((ws1), (ws2))
#endif
#define wcsspn(ws1, ws2)     ((int) wcsspn((ws1), (ws2)))
#endif /* WINDOWS */

#if defined (SOLARIS)
#define wcslen(ws)           wslen((ws))
#define wcschr(ws, wc)       wschr((ws), (wc))
#define wcsrchr(ws, wc)      wsrchr((ws), (wc))
#define wcstok(ws1, ws2)     wstok((ws1), (ws2))
#define wcscoll(ws1, ws2)    wscoll((ws1), (ws2))
#define wcsspn(ws1, ws2)     wsspn((ws1), (ws2))
#define wcscspn(ws1, ws2)    wscspn((ws1), (ws2))
#define wcscmp(ws1, ws2)     wscmp((ws1), (ws2))
#define wcsncmp(ws1, ws2, n) wsncmp((ws1), (ws2), (n))
#define wcscpy(ws1, ws2)     wscpy((ws1), (ws2))
#define wcsncpy(ws1, ws2, n) wsncpy((ws1), (ws2), (n))
#endif /* SOLARIS */

#if !defined (HAVE_STRDUP)
extern char *strdup (const char *str);
#endif /* HAVE_STRDUP */

#if !defined (HAVE_VASPRINTF)
extern int vasprintf (char **ptr, const char *format, va_list ap);
#endif /* HAVE_VASPRINTF */
#if !defined (HAVE_ASPRINTF)
extern int asprintf (char **ptr, const char *format, ...);
#endif /* HAVE_ASPRINTF */
#if defined (HAVE_ERR_H)
#include <err.h>
#else
#define err(fd, ...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0)
#define errx(fd, ...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0)
#endif
extern int cub_dirname_r (const char *path, char *pathbuf, size_t buflen);
#if defined (AIX)
double aix_ceil (double x);
#define ceil(x) aix_ceil(x)
#endif

#if !defined (HAVE_DIRNAME)
char *dirname (const char *path);
#endif /* HAVE_DIRNAME */
extern int basename_r (const char *path, char *pathbuf, size_t buflen);
#if !defined (HAVE_BASENAME)
extern char *basename (const char *path);
#endif /* HAVE_BASENAME */
#if defined (WINDOWS)
#if !defined (HAVE_STRSEP)
extern char *strsep (char **stringp, const char *delim);
#endif
extern char *getpass (const char *prompt);
#endif

#if defined (ENABLE_UNUSED_FUNCTION)
extern int utona (unsigned int u, char *s, size_t n);
extern int itona (int i, char *s, size_t n);
#endif

extern char *stristr (const char *s, const char *find);

#if 1
#define SUPPRESS_STRLEN_WARNING
#else /* !1 */
/* TODO: this causes a compile error on windows, since it uses in its headers std::strlen. anyway, this is an ugly hack
 *       too.
 *       now, we have hundreds of annoying warnings of casts from size_t to int. so either rename this define and all
 *       its usages, or replaces all occurrences of strlen with (int) strlen. either way, all project is changed. */
#define strlen(s1)  ((int) strlen(s1))
#endif /* !1 */
#define CAST_STRLEN (int)
#define CAST_BUFLEN (int)
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 32
#define OFF_T_MAX  INT_MAX
#else
#define OFF_T_MAX  LLONG_MAX
#endif

#if defined (WINDOWS)
#define IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
typedef int socklen_t;
#else
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define IS_INVALID_SOCKET(socket) ((socket) < 0)
#endif

/*
 * wrapper for cuserid()
 */
extern char *getuserid (char *string, int size);
/*
 * wrapper for OS dependent operations
 */
extern int os_rename_file (const char *src_path, const char *dest_path);

/* os_send_kill() - send the KILL signal to ourselves */
#if defined (WINDOWS)
#define os_send_kill() os_send_signal(SIGABRT)
#else
#define os_send_kill() os_send_signal(SIGKILL)
#endif
typedef void (*SIGNAL_HANDLER_FUNCTION) (int sig_no);
extern SIGNAL_HANDLER_FUNCTION os_set_signal_handler (const int sig_no, SIGNAL_HANDLER_FUNCTION sig_handler);
extern void os_send_signal (const int sig_no);

#if defined (WINDOWS)
#define atoll(a)    _atoi64((a))
#if !defined(_MSC_VER) || _MSC_VER < 1800
/* ref: https://msdn.microsoft.com/en-us/library/a206stx2.aspx */
#define llabs(a)    _abs64((a))
#endif /* _MSC_VER && _MSC_VER < 1800 */
#endif

#if defined (AIX) && !defined (NAME_MAX)
#define NAME_MAX pathconf("/",_PC_NAME_MAX)
#endif

#if defined (AIX) && !defined (DONT_HOOK_MALLOC)
void *aix_malloc (size_t size);
#define malloc(a) aix_malloc(a)
#endif

#if defined (AIX) && !defined (SOL_TCP)
#define SOL_TCP IPPROTO_TCP
#endif

#if defined (WINDOWS)
int setenv (const char *name, const char *value, int overwrite);
int cub_vsnprintf (char *buffer, size_t count, const char *format, va_list argptr);
#endif

#if defined (WINDOWS)
/* The following structure is used to generate uniformly distributed
 * pseudo-random numbers reentrantly.
 */
struct drand48_data
{
  unsigned short _rand48_seed[3];
};

/* These functions are implemented in rand.c. And rand.c will be included
 * on Windows build.
 */
extern long lrand48 (void);
extern void srand48 (long seed);
extern double drand48 (void);
extern int srand48_r (long int seedval, struct drand48_data *buffer);
extern int lrand48_r (struct drand48_data *buffer, long int *result);
extern int drand48_r (struct drand48_data *buffer, double *result);
extern int rand_r (unsigned int *seedp);

#if !defined(_MSC_VER) || _MSC_VER < 1800
  /* Ref: https://msdn.microsoft.com/en-us/library/dn353646(v=vs.140).aspx */
extern double round (double d);
#endif /* !_MSC_VER || _MSC_VER < 1800 */

/* Maybe replace this with std::mutex */
typedef struct
{
  CRITICAL_SECTION cs;
  CRITICAL_SECTION *csp;
  UINT32 watermark;
} pthread_mutex_t;

typedef HANDLE pthread_mutexattr_t;

/* Use a large prime as watermark */
#define WATERMARK_MUTEX_INITIALIZED 0x96438AF7

#define PTHREAD_MUTEX_INITIALIZER   {{ NULL, 0, 0, NULL, NULL, 0 }, NULL, 0}

typedef enum
{
  COND_SIGNAL = 0,
  COND_BROADCAST = 1,
  MAX_EVENTS = 2
} EVENTS;

typedef union
{
  CONDITION_VARIABLE native_cond;

  struct
  {
    bool initialized;
    unsigned int waiting;
    CRITICAL_SECTION lock_waiting;
    HANDLE events[MAX_EVENTS];
    HANDLE broadcast_block_event;
  };
} pthread_cond_t;


typedef HANDLE pthread_condattr_t;

#if !defined (ETIMEDOUT)
#define ETIMEDOUT WAIT_TIMEOUT
#endif
#define PTHREAD_COND_INITIALIZER    { NULL }

#if defined(_MSC_VER) && _MSC_VER >= 1900 && !defined(_CRT_NO_TIME_T)
#define _TIMESPEC_DEFINED
#endif /* _MSC_VER && _MSC_VER >= 1900 && !_CRT_NO_TIME_T */
#if !defined(_TIMESPEC_DEFINED)
#define _TIMESPEC_DEFINED
struct timespec
{
  int tv_sec;
  int tv_nsec;
};
#endif /* !_TIMESPEC_DEFINED */

extern pthread_mutex_t css_Internal_mutex_for_mutex_initialize;

int pthread_mutex_init (pthread_mutex_t * mutex, pthread_mutexattr_t * attr);
int pthread_mutex_destroy (pthread_mutex_t * mutex);

void port_win_mutex_init_and_lock (pthread_mutex_t * mutex);
int port_win_mutex_init_and_trylock (pthread_mutex_t * mutex);

__inline int
pthread_mutex_lock (pthread_mutex_t * mutex)
{
  if (mutex->csp == &mutex->cs && mutex->watermark == WATERMARK_MUTEX_INITIALIZED)
    {
      EnterCriticalSection (mutex->csp);
    }
  else
    {
      port_win_mutex_init_and_lock (mutex);
    }

  return 0;
}

__inline int
pthread_mutex_unlock (pthread_mutex_t * mutex)
{
  if (mutex->csp->LockCount == -1)
    {
      /* this means unlock mutex which isn't locked */
      assert (0);
      return 0;
    }

  LeaveCriticalSection (mutex->csp);
  return 0;
}

__inline int
pthread_mutex_trylock (pthread_mutex_t * mutex)
{
  if (mutex->csp == &mutex->cs && mutex->watermark == WATERMARK_MUTEX_INITIALIZED)
    {
      if (TryEnterCriticalSection (mutex->csp))
    {
      if (mutex->csp->RecursionCount > 1)
        {
          LeaveCriticalSection (mutex->csp);
          return EBUSY;
        }

      return 0;
    }

      return EBUSY;
    }
  else
    {
      return port_win_mutex_init_and_trylock (mutex);
    }

  return 0;
}

int pthread_mutexattr_init (pthread_mutexattr_t * attr);
int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int type);
int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);

int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr);
int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex);
int pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, struct timespec *ts);
int pthread_cond_destroy (pthread_cond_t * cond);
int pthread_cond_signal (pthread_cond_t * cond);
int pthread_cond_broadcast (pthread_cond_t * cond);



/* Data Types */
typedef HANDLE pthread_t;
typedef int pthread_attr_t;
typedef int pthread_key_t;

#define THREAD_RET_T unsigned int
#define THREAD_CALLING_CONVENTION __stdcall

int pthread_create (pthread_t * thread, const pthread_attr_t * attr,
            THREAD_RET_T (THREAD_CALLING_CONVENTION * start_routine) (void *), void *arg);
void pthread_exit (THREAD_RET_T ptr);
pthread_t pthread_self (void);
int pthread_join (pthread_t thread, void **value_ptr);

#define pthread_attr_init(dummy1)   0
#define pthread_attr_destroy(dummy1)    0

int pthread_key_create (pthread_key_t * key, void (*destructor) (void *));
int pthread_key_delete (pthread_key_t key);
int pthread_setspecific (pthread_key_t key, const void *value);
void *pthread_getspecific (pthread_key_t key);

#else /* WINDOWS */

#define THREAD_RET_T void*
#define THREAD_CALLING_CONVENTION

#endif /* WINDOWS */

#if (defined (WINDOWS) || defined (X86))
#define COPYMEM(type,dst,src)   do {        \
  *((type *) (dst)) = *((type *) (src));    \
}while(0)
#else /* WINDOWS || X86 */
#define COPYMEM(type,dst,src)   do {        \
  memcpy((dst), (src), sizeof(type));       \
}while(0)
#endif /* WINDOWS || X86 */

/*
 * Interfaces for atomic operations
 *
 * Developers should check HAVE_ATOMIC_BUILTINS before using atomic builtins
 * as follows.
 *  #if defined (HAVE_ATOMIC_BUILTINS)
 *   ... write codes with atomic builtins ...
 *  #else
 *   ... leave legacy codes or write codes without atomic builtins ...
 *  #endif
 *
 * ATOMIC_TAS_xx (atomic test-and-set) writes new_val into *ptr, and returns
 * the previous contents of *ptr. ATOMIC_CAS_xx (atomic compare-and-swap) returns
 * true if the swap is done. It is only done if *ptr equals to cmp_val.
 * ATOMIC_INC_xx (atomic increment) returns the result of *ptr + amount.
 *
 * Regarding Windows, there are two types of APIs to provide atomic operations.
 * While InterlockedXXX functions handles 32bit values, InterlockedXXX64 handles
 * 64bit values. That is why we define two types of macros.
 */
#ifdef __cplusplus

#if defined (WINDOWS)
#define MEMORY_BARRIER() \
    MemoryBarrier()
#define HAVE_ATOMIC_BUILTINS
#else
#if defined (HAVE_GCC_ATOMIC_BUILTINS)
#define HAVE_ATOMIC_BUILTINS
#if defined (X86) && defined (CUB_GCC_VERSION) && (CUB_GCC_VERSION < 40400)
#define MEMORY_BARRIER() \
        do { \
          asm volatile("mfence" ::: "memory"); \
          __sync_synchronize(); \
        } while (0)
#else
#define MEMORY_BARRIER() \
              __sync_synchronize()
#endif
#endif
#endif /* defined (WINDOWS) */

#endif /* __cplusplus */

#if defined(HAVE_ATOMIC_BUILTINS)

#if defined (WINDOWS)

#ifndef _WIN64
/*
 * These functions are used on Windows 32bit OS.
 * InterlockedXXX64 functions are provided by Windows Vista (client)/Windows
 * 2003 (server) or later versions. So, Windows XP 32bit does not have them.
 * We provide the following functions to support atomic operations on all
 * Windows versions.
 */
extern UINT64 win32_compare_exchange64 (UINT64 volatile *val_ptr, UINT64 swap_val, UINT64 cmp_val);
extern UINT64 win32_exchange_add64 (UINT64 volatile *ptr, UINT64 amount);
extern UINT64 win32_exchange64 (UINT64 volatile *ptr, UINT64 new_val);

#endif /* !_WIN64 */
#endif /* defined (WINDOWS) */

#ifndef __cplusplus
#define static_assert(a, b)
#endif /* not __cplusplus */

/* *INDENT-OFF* */
template <typename T, typename V> inline T ATOMIC_INC_32 (volatile T *ptr, V amount)
{
  static_assert (sizeof (T) == sizeof (UINT32), "Not 32bit");
  static_assert (sizeof (V) == sizeof (UINT32), "Not 32bit");
#if defined (WINDOWS)
#if _MSC_VER <= 1500
  return InterlockedExchangeAdd (reinterpret_cast <volatile LONG *>(ptr), amount) + amount;
#else
  return InterlockedExchangeAdd (reinterpret_cast <volatile UINT32 *>(ptr), amount) + amount;
#endif
#else
  return __sync_add_and_fetch (ptr, amount);
#endif
}

template <typename T, typename V1, typename V2> inline bool ATOMIC_CAS_32 (volatile T *ptr, V1 cmp_val, V2 swap_val)
{
  static_assert (sizeof (T) == sizeof (UINT32), "Not 32bit");
  static_assert (sizeof (V1) == sizeof (UINT32), "Not 32bit");
  static_assert (sizeof (V2) == sizeof (UINT32), "Not 32bit");
#if defined (WINDOWS)
#if _MSC_VER <= 1500
  return InterlockedCompareExchange (reinterpret_cast <volatile LONG *>(ptr), swap_val, cmp_val) == cmp_val;
#else
  return InterlockedCompareExchange (reinterpret_cast <volatile UINT32 *>(ptr), swap_val, cmp_val) == cmp_val;
#endif
#else
  return __sync_bool_compare_and_swap (ptr, cmp_val, swap_val);
#endif
}

template <typename T, typename V> inline T ATOMIC_TAS_32 (volatile T *ptr, V amount)
{
  static_assert (sizeof (T) == sizeof (UINT32), "Not 32bit");
  static_assert (sizeof (V) <= sizeof (UINT32), "Not 32bit");
#if defined (WINDOWS)
#if _MSC_VER <= 1500
  return InterlockedExchange (reinterpret_cast <volatile LONG *>(ptr), amount);
#else
  return InterlockedExchange (reinterpret_cast <volatile UINT32 *>(ptr), amount);
#endif
#else
  return __sync_lock_test_and_set (ptr, amount);
#endif
}

template <typename T, typename V> inline T ATOMIC_INC_64 (volatile T *ptr, V amount)
{
  static_assert (sizeof (T) == sizeof (UINT64), "Not 64bit");
#if defined (_WIN64)
  return (T) InterlockedExchangeAdd64 (reinterpret_cast <volatile INT64 *>(ptr), amount) + amount;
#elif defined(WINDOWS)
  return win32_exchange_add64 (reinterpret_cast <volatile UINT64 *>(ptr), amount) + amount;
#else
  return __sync_add_and_fetch (ptr, amount);
#endif
}

template <typename T, typename V1, typename V2> inline bool ATOMIC_CAS_64 (volatile T *ptr, V1 cmp_val, V2 swap_val)
{
  static_assert (sizeof (T) == sizeof (UINT64), "Not 64bit");
#if defined (_WIN64)
  return InterlockedCompareExchange64 (reinterpret_cast <volatile INT64 *>(ptr), swap_val, cmp_val) == cmp_val;
#elif defined(WINDOWS)
  return win32_compare_exchange64 (reinterpret_cast <volatile UINT64 *>(ptr), swap_val, cmp_val) == cmp_val;
#else
  return __sync_bool_compare_and_swap (ptr, cmp_val, swap_val);
#endif
}

template <typename T, typename V> inline T ATOMIC_TAS_64 (volatile T *ptr, V amount)
{
  static_assert (sizeof (T) == sizeof (UINT64), "Not 64bit");
#if defined (_WIN64)
  return (T) InterlockedExchange64 (reinterpret_cast <volatile INT64 *>(ptr), (__int64) amount);
#elif defined(WINDOWS)
  return win32_exchange64 (reinterpret_cast <volatile UINT64 *>(ptr), amount);
#else
  return __sync_lock_test_and_set (ptr, amount);
#endif
}

namespace dispatch
{
  template <bool B> struct Bool2Type
    {
      enum { value = B };
    };

  template <typename T, typename V1, typename V2> inline bool atomic_cas (volatile T *ptr, V1 cmp_val, V2 swap_val,
                                      Bool2Type <true> /*_is_64_bit*/ )
    {
      return ATOMIC_CAS_64 (ptr, cmp_val, swap_val);
    }

  template <typename T, typename V1, typename V2> inline bool atomic_cas (volatile T *ptr, V1 cmp_val, V2 swap_val,
                                      Bool2Type <false> /*_is_64_bit*/ )
    {
      return ATOMIC_CAS_32 (ptr, cmp_val, swap_val);
    }

  template <typename T, typename V> inline T atomic_tas (volatile T *ptr, V amount, Bool2Type <true> /*_is_64_bit*/ )
    {
      return ATOMIC_TAS_64 (ptr, amount);
    }

  template <typename T, typename V> inline T atomic_tas (volatile T * ptr, V amount, Bool2Type <false> /*_is_64_bit*/ )
    {
      return ATOMIC_TAS_32 (ptr, amount);
    }

  template <typename T, typename V> inline T atomic_inc (volatile T *ptr, V amount, Bool2Type <true> /*_is_64_bit*/ )
    {
      return ATOMIC_INC_64 (ptr, amount);
    }

  template <typename T, typename V> inline T atomic_inc (volatile T * ptr, V amount, Bool2Type <false> /*_is_64_bit*/ )
    {
      return ATOMIC_INC_32 (ptr, amount);
    }
}               /* namespace dispatch */

template <typename T, typename V> inline T ATOMIC_TAS (volatile T *ptr, V amount)
{
  return dispatch::atomic_tas (ptr, amount, dispatch::Bool2Type <sizeof (T) == sizeof (UINT64)> ());
}

template <typename T, typename V1, typename V2> inline bool ATOMIC_CAS (volatile T *ptr, V1 cmp_val, V2 swap_val)
{
  return dispatch::atomic_cas (ptr, cmp_val, swap_val, dispatch::Bool2Type <sizeof (T) == sizeof (UINT64)> ());
}

template <typename T> inline T *ATOMIC_TAS_ADDR (T * volatile *ptr, T *new_val)
{
#if defined (WINDOWS)
  return static_cast <T *>(InterlockedExchangePointer (reinterpret_cast <volatile PVOID *>(ptr), new_val));
#else
  return __sync_lock_test_and_set (ptr, new_val);
#endif
}

template <typename T> inline bool ATOMIC_CAS_ADDR (T * volatile *ptr, T *cmp_val, T *swap_val)
{
#if defined (WINDOWS)
  return InterlockedCompareExchangePointer (reinterpret_cast <volatile PVOID *>(ptr), swap_val, cmp_val) == cmp_val;
#else
  return __sync_bool_compare_and_swap (ptr, cmp_val, swap_val);
#endif
}

template <typename T, typename V> inline T ATOMIC_INC (volatile T *ptr, V amount)
{
  return dispatch::atomic_inc (ptr, amount, dispatch::Bool2Type <sizeof (T) == sizeof (UINT64)> ());
}

template <typename T> inline T ATOMIC_LOAD (volatile T *ptr)
{
  return ATOMIC_INC (ptr, 0);
}

template <typename T, typename V> inline void ATOMIC_STORE (volatile T *ptr, V amount)
{
  (void) ATOMIC_TAS (ptr, amount);
}

/* *INDENT-ON* */

#define ATOMIC_LOAD_64(ptr) ATOMIC_INC_64(ptr, 0)
#define ATOMIC_STORE_64(ptr, val) ATOMIC_TAS(ptr, val)

#endif /* defined(HAVE_ATOMIC_BUILTINS) */

#if defined (WINDOWS)
extern double strtod_win (const char *str, char **end_ptr);
#define string_to_double(str, end_ptr) strtod_win((str), (end_ptr));
#else
#define string_to_double(str, end_ptr) strtod((str), (end_ptr))
#endif

extern INT64 timeval_diff_in_msec (const struct timeval *end_time, const struct timeval *start_time);
extern int timeval_add_msec (struct timeval *added_time, const struct timeval *start_time, int msec);
extern int timeval_to_timespec (struct timespec *to, const struct timeval *from);

extern FILE *port_open_memstream (char **ptr, size_t * sizeloc);

extern void port_close_memstream (FILE * fp, char **ptr, size_t * sizeloc);

extern int parse_bigint (INT64 * ret_p, const char *str_p, int base);

extern int str_to_int32 (int *ret_p, char **end_p, const char *str_p, int base);
extern int str_to_uint32 (unsigned int *ret_p, char **end_p, const char *str_p, int base);
extern int str_to_int64 (INT64 * ret_p, char **end_p, const char *str_p, int base);
extern int str_to_uint64 (UINT64 * ret_p, char **end_p, const char *str_p, int base);
extern int str_to_double (double *ret_p, char **end_p, const char *str_p);
extern int str_to_float (float *ret_p, char **end_p, const char *str_p);

#if defined (WINDOWS)
extern float strtof_win (const char *nptr, char **endptr);
extern char *strndup_win (const char *src, size_t size);
#endif

#ifndef HAVE_STRLCPY
extern size_t strlcpy (char *, const char *, size_t);
#endif

#if (defined (WINDOWS) && defined (_WIN32))
extern time_t mktime_for_win32 (struct tm *tm);
#endif

#if (defined (WINDOWS) && !defined (PRId64))
#define PRId64 "lld"
#define PRIx64 "llx"
#endif

extern int msleep (const long msec);

#ifdef __cplusplus
extern "C"
{
#endif
  extern int parse_int (int *ret_p, const char *str_p, int base);
#ifdef __cplusplus
}
#endif

#if defined (_MSC_VER) || defined (__GNUC__)
#define PORTABLE_FUNC_NAME __func__
#else
#define PORTABLE_FUNC_NAME "(unknown)"
#endif

#ifdef __GNUC__
#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#else
#define UNUSED(x) x
#endif

#ifdef __GNUC__
#define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x
#else
#define UNUSED_FUNCTION(x) x
#endif

/* casts for C++ and C to be used in *.c files; cpp files should use C++ specific syntax. */
/* todo: we should split porting.h into several files to avoid recompiling whole project every time we change
 *       something. when we do that, we can avoid including dangerous macro's like these in header files.
 *       so, try not to include this in header files. */
#ifdef STATIC_CAST
#error "STATIC_CAST definition conflict"
#else               /* !STATIC_CAST */
#ifdef __cplusplus
#define STATIC_CAST(dest_type, expr) static_cast<dest_type>(expr)
#else               /* !__cplusplus */
#define STATIC_CAST(dest_type, expr) ((dest_type) (expr))
#endif              /* !__cplusplus */
#endif              /* !STATIC_CAST */

#ifdef CONST_CAST
#error "CONST_CAST definition conflict"
#else               /* !CONST_CAST */
#ifdef __cplusplus
#define CONST_CAST(dest_type, expr) const_cast<dest_type>(expr)
#else               /* !__cplusplus */
#define CONST_CAST(dest_type, expr) ((dest_type) (expr))
#endif              /* !__cplusplus */
#endif              /* !CONST_CAST */

#ifdef DYNAMIC_CAST
#error "DYNAMIC_CAST definition conflict"
#else               /* !DYNAMIC_CAST */
#ifdef __cplusplus
#define DYNAMIC_CAST(dest_type, expr) dynamic_cast<dest_type>(expr)
#else               /* !__cplusplus */
#define DYNAMIC_CAST(dest_type, expr) ((dest_type) (expr))
#endif              /* !__cplusplus */
#endif              /* !DYNAMIC_CAST */

#ifdef REINTERPRET_CAST
#error "REINTERPRET_CAST definition conflict"
#else               /* !REINTERPRET_CAST */
#ifdef __cplusplus
#define REINTERPRET_CAST(dest_type, expr) reinterpret_cast<dest_type>(expr)
#else               /* !__cplusplus */
#define REINTERPRET_CAST(dest_type, expr) ((dest_type) (expr))
#endif              /* !__cplusplus */
#endif              /* !REINTERPRET_CAST */


/* Use REFP to declare a reference to pointer in *.c files without indent complaining. Do not use it in .cpp files. */
#ifdef REFPTR
#error "REFP definition conflict"
#else               /* !REFPTR */
#define REFPTR(T, name) T *& name
#endif              /* !REFPTR */

#if defined (__GNUC__)
#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define prefetch(x, y, z) __builtin_prefetch((x), (y), (z))
#else
#define likely(x)   (x)
#define unlikely(x) (x)
#define prefetch(x, y, z) (void) 0
#endif

#define PREFETCH_READ 0
#define PREFETCH_WRITE 1
#define PREFETCH_CACHE_NEVER 0
#define PREFETCH_CACHE_L3 1
#define PREFETCH_CACHE_L2 2
#define PREFETCH_CACHE_L1 3

#endif              /* _PORTING_H_ */