summaryrefslogtreecommitdiffstats
path: root/netwerk/sctp/src/user_atomic.h
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/sctp/src/user_atomic.h')
-rw-r--r--netwerk/sctp/src/user_atomic.h315
1 files changed, 315 insertions, 0 deletions
diff --git a/netwerk/sctp/src/user_atomic.h b/netwerk/sctp/src/user_atomic.h
new file mode 100644
index 0000000000..6a59587efc
--- /dev/null
+++ b/netwerk/sctp/src/user_atomic.h
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 2009-2010 Brad Penoff
+ * Copyright (c) 2009-2010 Humaira Kamal
+ * Copyright (c) 2011-2012 Irene Ruengeler
+ * Copyright (c) 2011-2012 Michael Tuexen
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _USER_ATOMIC_H_
+#define _USER_ATOMIC_H_
+
+/* __Userspace__ version of sys/i386/include/atomic.h goes here */
+
+/* TODO In the future, might want to not use i386 specific assembly.
+ * The options include:
+ * - implement them generically (but maybe not truly atomic?) in userspace
+ * - have ifdef's for __Userspace_arch_ perhaps (OS isn't enough...)
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined(__APPLE__) || defined(_WIN32)
+#if defined(_WIN32)
+#define atomic_add_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
+#define atomic_fetchadd_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
+#define atomic_subtract_int(addr, val) InterlockedExchangeAdd((LPLONG)addr,-((LONG)val))
+#define atomic_cmpset_int(dst, exp, src) InterlockedCompareExchange((LPLONG)dst, src, exp)
+#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (InterlockedExchangeAdd((LPLONG)addr, (-1L)) == 1)
+#else
+#include <libkern/OSAtomic.h>
+#define atomic_add_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr)
+#define atomic_fetchadd_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr)
+#define atomic_subtract_int(addr, val) OSAtomicAdd32Barrier(-val, (int32_t *)addr)
+#define atomic_cmpset_int(dst, exp, src) OSAtomicCompareAndSwapIntBarrier(exp, src, (int *)dst)
+#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 0)
+#endif
+
+#if defined(INVARIANTS)
+#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
+{ \
+ int32_t newval; \
+ newval = atomic_fetchadd_int(addr, -val); \
+ if (newval < 0) { \
+ panic("Counter goes negative"); \
+ } \
+}
+#else
+#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
+{ \
+ int32_t newval; \
+ newval = atomic_fetchadd_int(addr, -val); \
+ if (newval < 0) { \
+ *addr = 0; \
+ } \
+}
+#endif
+#if defined(_WIN32)
+static void atomic_init(void) {} /* empty when we are not using atomic_mtx */
+#else
+static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
+#endif
+
+#else
+/* Using gcc built-in functions for atomic memory operations
+ Reference: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
+ Requires gcc version 4.1.0
+ compile with -march=i486
+ */
+
+/*Atomically add V to *P.*/
+#define atomic_add_int(P, V) (void) __sync_fetch_and_add(P, V)
+
+/*Atomically subtrace V from *P.*/
+#define atomic_subtract_int(P, V) (void) __sync_fetch_and_sub(P, V)
+
+/*
+ * Atomically add the value of v to the integer pointed to by p and return
+ * the previous value of *p.
+ */
+#define atomic_fetchadd_int(p, v) __sync_fetch_and_add(p, v)
+
+/* Following explanation from src/sys/i386/include/atomic.h,
+ * for atomic compare and set
+ *
+ * if (*dst == exp) *dst = src (all 32 bit words)
+ *
+ * Returns 0 on failure, non-zero on success
+ */
+
+#define atomic_cmpset_int(dst, exp, src) __sync_bool_compare_and_swap(dst, exp, src)
+
+#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 1)
+#if defined(INVARIANTS)
+#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
+{ \
+ int32_t oldval; \
+ oldval = atomic_fetchadd_int(addr, -val); \
+ if (oldval < val) { \
+ panic("Counter goes negative"); \
+ } \
+}
+#else
+#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
+{ \
+ int32_t oldval; \
+ oldval = atomic_fetchadd_int(addr, -val); \
+ if (oldval < val) { \
+ *addr = 0; \
+ } \
+}
+#endif
+static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
+#endif
+
+#if 0 /* using libatomic_ops */
+#include "user_include/atomic_ops.h"
+
+/*Atomically add incr to *P, and return the original value of *P.*/
+#define atomic_add_int(P, V) AO_fetch_and_add((AO_t*)P, V)
+
+#define atomic_subtract_int(P, V) AO_fetch_and_add((AO_t*)P, -(V))
+
+/*
+ * Atomically add the value of v to the integer pointed to by p and return
+ * the previous value of *p.
+ */
+#define atomic_fetchadd_int(p, v) AO_fetch_and_add((AO_t*)p, v)
+
+/* Atomically compare *addr to old_val, and replace *addr by new_val
+ if the first comparison succeeds. Returns nonzero if the comparison
+ succeeded and *addr was updated.
+*/
+/* Following Explanation from src/sys/i386/include/atomic.h, which
+ matches that of AO_compare_and_swap above.
+ * Atomic compare and set, used by the mutex functions
+ *
+ * if (*dst == exp) *dst = src (all 32 bit words)
+ *
+ * Returns 0 on failure, non-zero on success
+ */
+
+#define atomic_cmpset_int(dst, exp, src) AO_compare_and_swap((AO_t*)dst, exp, src)
+
+static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
+#endif /* closing #if for libatomic */
+
+#if 0 /* using atomic_mtx */
+
+#include <pthread.h>
+
+extern userland_mutex_t atomic_mtx;
+
+#if defined(_WIN32)
+static inline void atomic_init() {
+ InitializeCriticalSection(&atomic_mtx);
+}
+static inline void atomic_destroy() {
+ DeleteCriticalSection(&atomic_mtx);
+}
+static inline void atomic_lock() {
+ EnterCriticalSection(&atomic_mtx);
+}
+static inline void atomic_unlock() {
+ LeaveCriticalSection(&atomic_mtx);
+}
+#else
+static inline void atomic_init() {
+ pthread_mutexattr_t mutex_attr;
+
+ pthread_mutexattr_init(&mutex_attr);
+#ifdef INVARIANTS
+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
+#endif
+ pthread_mutex_init(&accept_mtx, &mutex_attr);
+ pthread_mutexattr_destroy(&mutex_attr);
+}
+static inline void atomic_destroy() {
+ (void)pthread_mutex_destroy(&atomic_mtx);
+}
+static inline void atomic_lock() {
+#ifdef INVARIANTS
+ KASSERT(pthread_mutex_lock(&atomic_mtx) == 0, ("atomic_lock: atomic_mtx already locked"))
+#else
+ (void)pthread_mutex_lock(&atomic_mtx);
+#endif
+}
+static inline void atomic_unlock() {
+#ifdef INVARIANTS
+ KASSERT(pthread_mutex_unlock(&atomic_mtx) == 0, ("atomic_unlock: atomic_mtx not locked"))
+#else
+ (void)pthread_mutex_unlock(&atomic_mtx);
+#endif
+}
+#endif
+/*
+ * For userland, always use lock prefixes so that the binaries will run
+ * on both SMP and !SMP systems.
+ */
+
+#define MPLOCKED "lock ; "
+
+/*
+ * Atomically add the value of v to the integer pointed to by p and return
+ * the previous value of *p.
+ */
+static __inline u_int
+atomic_fetchadd_int(volatile void *n, u_int v)
+{
+ int *p = (int *) n;
+ atomic_lock();
+ __asm __volatile(
+ " " MPLOCKED " "
+ " xaddl %0, %1 ; "
+ "# atomic_fetchadd_int"
+ : "+r" (v), /* 0 (result) */
+ "=m" (*p) /* 1 */
+ : "m" (*p)); /* 2 */
+ atomic_unlock();
+
+ return (v);
+}
+
+
+#ifdef CPU_DISABLE_CMPXCHG
+
+static __inline int
+atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
+{
+ u_char res;
+
+ atomic_lock();
+ __asm __volatile(
+ " pushfl ; "
+ " cli ; "
+ " cmpl %3,%4 ; "
+ " jne 1f ; "
+ " movl %2,%1 ; "
+ "1: "
+ " sete %0 ; "
+ " popfl ; "
+ "# atomic_cmpset_int"
+ : "=q" (res), /* 0 */
+ "=m" (*dst) /* 1 */
+ : "r" (src), /* 2 */
+ "r" (exp), /* 3 */
+ "m" (*dst) /* 4 */
+ : "memory");
+ atomic_unlock();
+
+ return (res);
+}
+
+#else /* !CPU_DISABLE_CMPXCHG */
+
+static __inline int
+atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
+{
+ atomic_lock();
+ u_char res;
+
+ __asm __volatile(
+ " " MPLOCKED " "
+ " cmpxchgl %2,%1 ; "
+ " sete %0 ; "
+ "1: "
+ "# atomic_cmpset_int"
+ : "=a" (res), /* 0 */
+ "=m" (*dst) /* 1 */
+ : "r" (src), /* 2 */
+ "a" (exp), /* 3 */
+ "m" (*dst) /* 4 */
+ : "memory");
+ atomic_unlock();
+
+ return (res);
+}
+
+#endif /* CPU_DISABLE_CMPXCHG */
+
+#define atomic_add_int(P, V) do { \
+ atomic_lock(); \
+ (*(u_int *)(P) += (V)); \
+ atomic_unlock(); \
+} while(0)
+#define atomic_subtract_int(P, V) do { \
+ atomic_lock(); \
+ (*(u_int *)(P) -= (V)); \
+ atomic_unlock(); \
+} while(0)
+
+#endif
+#endif