#ifndef ULIB__UMTX_H
#define ULIB__UMTX_H

#if defined(__FreeBSD__)

#define UMTX_init \
    if (sem_init(&SMEM->LOCK, 1, 1)) \
        Perl_croak_nocontext("panic: sem_init (TRUE) [%s:%d]", __FILE__, __LINE__)
#define UMTX_lock STMT_START { \
    if (sem_wait(&SMEM->LOCK) == 0) break; \
    if (errno == EINVAL) \
        Perl_croak_nocontext("panic: sem_wait (EINVAL) [%s:%d]", __FILE__, __LINE__); \
} STMT_END
#define UMTX_unlock STMT_START { \
    int r = sem_post(&SMEM->LOCK); \
    if (r != 0) \
        Perl_croak_nocontext("panic: sem_post (TRUE) [%s:%d]", __FILE__, __LINE__); \
} STMT_END

#else  /* ! __FreeBSD__ */

#include "atomic.h"
#include "futex.h"
#define UMTX_init SMEM->LOCK.val = 0
#define UMTX_lock { \
    long c; \
    if ((c = cmpxchg(&SMEM->LOCK.val, 0, 1)) != 0) { \
        if (c != 2) \
            c = xchg(&SMEM->LOCK.val, 2); \
        while (c != 0) { \
            futex_wait(&SMEM->LOCK.val, 2, 0); \
            c = xchg(&SMEM->LOCK.val, 2); \
        } \
    } \
}
#define UMTX_unlock { \
    if (xdec(&SMEM->LOCK.val) != 1) { \
        SMEM->LOCK.val = 0; \
        futex_wake(&SMEM->LOCK.val, 1); \
    } \
}

#endif  /* __FreeBSD__ */


/* This is try/catch from XSUB.h, copied here for reference. */
#ifdef NO_XSLOCKSxxx
#  define dXCPT             dJMPENV; int rEtV = 0
#  define XCPT_TRY_START    JMPENV_PUSH(rEtV); if (rEtV == 0)
#  define XCPT_TRY_END      JMPENV_POP;
#  define XCPT_CATCH        if (rEtV != 0)
#  define XCPT_RETHROW      JMPENV_JUMP(rEtV)
#endif

#define UMTX_INIT   UMTX_init
#define UMTX_LOCK   dJMPENV; int rEtV = 0; UMTX_lock; JMPENV_PUSH(rEtV); if (rEtV == 0)
#define UMTX_UNLOCK JMPENV_POP; UMTX_unlock; if (rEtV != 0) { JMPENV_JUMP(rEtV); }

#endif
/* ex:set ts=2 sw=2 itab=spaces: */
