summaryrefslogtreecommitdiff
path: root/src/atomic_bitmap.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/atomic_bitmap.hpp')
-rw-r--r--src/atomic_bitmap.hpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/atomic_bitmap.hpp b/src/atomic_bitmap.hpp
new file mode 100644
index 0000000..a5440de
--- /dev/null
+++ b/src/atomic_bitmap.hpp
@@ -0,0 +1,286 @@
+/*
+ Copyright (c) 2007-2009 FastMQ Inc.
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZS_ATOMIC_BITMAP_HPP_INCLUDED__
+#define __ZS_ATOMIC_BITMAP_HPP_INCLUDED__
+
+#include "stdint.hpp"
+#include "platform.hpp"
+
+// These are the conditions to choose between different implementations
+// of atomic_bitmap.
+
+#if defined ZS_FORCE_MUTEXES
+#define ZS_ATOMIC_BITMAP_MUTEX
+#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
+#define ZS_ATOMIC_BITMAP_X86
+#elif 0 && defined __sparc__ && defined __GNUC__
+#define ZS_ATOMIC_BITMAP_SPARC
+#elif defined ZS_HAVE_WINDOWS
+#define ZS_ATOMIC_BITMAP_WINDOWS
+#elif defined ZS_HAVE_SOLARIS
+#define ZS_ATOMIC_BITMAP_SOLARIS
+#else
+#define ZS_ATOMIC_BITMAP_MUTEX
+#endif
+
+#if defined ZS_ATOMIC_BITMAP_MUTEX
+#include "mutex.hpp"
+#elif defined ZS_ATOMIC_BITMAP_WINDOWS
+#include "windows.hpp"
+#elif defined ZS_ATOMIC_BITMAP_SOLARIS
+#include <atomic.h>
+#endif
+
+namespace zs
+{
+
+ // This class encapuslates several bitwise atomic operations on unsigned
+ // integer. Selection of operations is driven specifically by the needs
+ // of ypollset implementation.
+
+ class atomic_bitmap_t
+ {
+ public:
+
+#if (defined ZMQ_ATOMIC_BITMAP_X86 || defined ZMQ_FORCE_MUTEXES) \
+ && defined __x86_64__
+ typedef uint64_t bitmap_t;
+#else
+ typedef uint32_t bitmap_t;
+#endif
+
+ inline atomic_bitmap_t (bitmap_t value_ = 0) :
+ value (value_)
+ {
+ }
+
+ inline ~atomic_bitmap_t ()
+ {
+ }
+
+ // Bit-test-set-and-reset. Sets one bit of the value and resets
+ // another one. Returns the original value of the reset bit.
+ inline bool btsr (int set_index_, int reset_index_)
+ {
+#if defined ZS_ATOMIC_BITMAP_WINDOWS
+ while (true) {
+ bitmap_t oldval = value;
+ bitmap_t newval = (oldval | (bitmap_t (1) << set_index_)) &
+ ~(bitmap_t (1) << reset_index_);
+ if (InterlockedCompareExchange ((volatile LONG*) &value, newval,
+ oldval) == (LONG) oldval)
+ return (oldval & (bitmap_t (1) << reset_index_)) ?
+ true : false;
+ }
+#elif defined ZS_ATOMIC_BITMAP_SOLARIS
+ while (true) {
+ bitmap_t oldval = value;
+ bitmap_t newval = (oldval | (bitmap_t (1) << set_index_)) &
+ ~(bitmap_t (1) << reset_index_);
+ if (atomic_cas_32 (&value, oldval, newval) == oldval)
+ return (oldval & (bitmap_t (1) << reset_index_)) ?
+ true : false;
+ }
+#elif defined ZS_ATOMIC_BITMAP_X86
+ bitmap_t oldval, dummy;
+ __asm__ volatile (
+ "mov %0, %1\n\t"
+ "1:"
+ "mov %1, %2\n\t"
+ "bts %3, %2\n\t"
+ "btr %4, %2\n\t"
+ "lock cmpxchg %2, %0\n\t"
+ "jnz 1b\n\t"
+ : "+m" (value), "=&a" (oldval), "=&r" (dummy)
+ : "r" (bitmap_t(set_index_)), "r" (bitmap_t(reset_index_))
+ : "cc");
+ return (bool) (oldval & (bitmap_t(1) << reset_index_));
+#elif defined ZS_ATOMIC_BITMAP_SPARC
+ volatile bitmap_t* valptr = &value;
+ bitmap_t set_val = bitmap_t(1) << set_index_;
+ bitmap_t reset_val = ~(bitmap_t(1) << reset_index_);
+ bitmap_t tmp;
+ bitmap_t oldval;
+ __asm__ volatile(
+ "ld [%5], %2 \n\t"
+ "1: \n\t"
+ "or %2, %0, %3 \n\t"
+ "and %3, %1, %3 \n\t"
+ "cas [%5], %2, %3 \n\t"
+ "cmp %2, %3 \n\t"
+ "bne,a,pn %%icc, 1b \n\t"
+ "mov %3, %2 \n\t"
+ : "+r" (set_val), "+r" (reset_val), "=&r" (tmp),
+ "=&r" (oldval), "+m" (*valptr)
+ : "r" (valptr)
+ : "cc");
+ return oldval;
+#elif defined ZS_ATOMIC_BITMAP_MUTEX
+ sync.lock ();
+ bitmap_t oldval = value;
+ value = (oldval | (bitmap_t (1) << set_index_)) &
+ ~(bitmap_t (1) << reset_index_);
+ sync.unlock ();
+ return (oldval & (bitmap_t (1) << reset_index_)) ? true : false;
+#else
+#error
+#endif
+ }
+
+ // Sets value to newval. Returns the original value.
+ inline bitmap_t xchg (bitmap_t newval_)
+ {
+ bitmap_t oldval;
+#if defined ZS_ATOMIC_BITMAP_WINDOWS
+ oldval = InterlockedExchange ((volatile LONG*) &value, newval_);
+#elif defined ZS_ATOMIC_BITMAP_SOLARIS
+ oldval = atomic_swap_32 (&value, newval_);
+#elif defined ZS_ATOMIC_BITMAP_X86
+ oldval = newval_;
+ __asm__ volatile (
+ "lock; xchg %0, %1"
+ : "=r" (oldval)
+ : "m" (value), "0" (oldval)
+ : "memory");
+#elif defined ZS_ATOMIC_BITMAP_SPARC
+ oldval = value;
+ volatile bitmap_t* ptrin = &value;
+ bitmap_t tmp;
+ bitmap_t prev;
+ __asm__ __volatile__(
+ "ld [%4], %1\n\t"
+ "1:\n\t"
+ "mov %0, %2\n\t"
+ "cas [%4], %1, %2\n\t"
+ "cmp %1, %2\n\t"
+ "bne,a,pn %%icc, 1b\n\t"
+ "mov %2, %1\n\t"
+ : "+r" (newval_), "=&r" (tmp), "=&r" (prev), "+m" (*ptrin)
+ : "r" (ptrin)
+ : "cc");
+ return prev;
+#elif defined ZS_ATOMIC_BITMAP_MUTEX
+ sync.lock ();
+ oldval = value;
+ value = newval_;
+ sync.unlock ();
+#else
+#error
+#endif
+ return oldval;
+ }
+
+ // izte is "if-zero-then-else" atomic operation - if the value is zero
+ // it substitutes it by 'thenval' else it rewrites it by 'elseval'.
+ // Original value of the integer is returned from this function.
+ inline bitmap_t izte (bitmap_t thenval_,
+ bitmap_t elseval_)
+ {
+#if defined ZS_ATOMIC_BITMAP_WINDOWS
+ while (true) {
+ bitmap_t oldval = value;
+ bitmap_t newval = oldval == 0 ? thenval_ : elseval_;
+ if (InterlockedCompareExchange ((volatile LONG*) &value,
+ newval, oldval) == (LONG) oldval)
+ return oldval;
+ }
+#elif defined ZS_ATOMIC_BITMAP_SOLARIS
+ while (true) {
+ bitmap_t oldval = value;
+ bitmap_t newval = oldval == 0 ? thenval_ : elseval_;
+ if (atomic_cas_32 (&value, oldval, newval) == oldval)
+ return oldval;
+ }
+#elif defined ZS_ATOMIC_BITMAP_X86
+ bitmap_t oldval;
+ bitmap_t dummy;
+ __asm__ volatile (
+ "mov %0, %1\n\t"
+ "1:"
+ "mov %3, %2\n\t"
+ "test %1, %1\n\t"
+ "jz 2f\n\t"
+ "mov %4, %2\n\t"
+ "2:"
+ "lock cmpxchg %2, %0\n\t"
+ "jnz 1b\n\t"
+ : "+m" (value), "=&a" (oldval), "=&r" (dummy)
+ : "r" (thenval_), "r" (elseval_)
+ : "cc");
+ return oldval;
+#elif defined ZS_ATOMIC_BITMAP_SPARC
+ volatile bitmap_t* ptrin = &value;
+ bitmap_t tmp;
+ bitmap_t prev;
+ __asm__ __volatile__(
+ "ld [%3], %0 \n\t"
+ "mov 0, %1 \n\t"
+ "cas [%3], %1, %4 \n\t"
+ "cmp %0, %1 \n\t"
+ "be,a,pn %%icc,1f \n\t"
+ "ld [%3], %0 \n\t"
+ "cas [%3], %0, %5 \n\t"
+ "1: \n\t"
+ : "=&r" (tmp), "=&r" (prev), "+m" (*ptrin)
+ : "r" (ptrin), "r" (thenval_), "r" (elseval_)
+ : "cc");
+ return prev;
+#elif defined ZS_ATOMIC_BITMAP_MUTEX
+ sync.lock ();
+ bitmap_t oldval = value;
+ value = oldval ? elseval_ : thenval_;
+ sync.unlock ();
+ return oldval;
+#else
+#error
+#endif
+ }
+
+ private:
+
+ volatile bitmap_t value;
+#if defined ZS_ATOMIC_BITMAP_MUTEX
+ mutex_t sync;
+#endif
+
+ atomic_bitmap_t (const atomic_bitmap_t&);
+ void operator = (const atomic_bitmap_t&);
+ };
+
+}
+
+// Remove macros local to this file.
+#if defined ZS_ATOMIC_BITMAP_WINDOWS
+#undef ZS_ATOMIC_BITMAP_WINDOWS
+#endif
+#if defined ZS_ATOMIC_BITMAP_SOLARIS
+#undef ZS_ATOMIC_BITMAP_SOLARIS
+#endif
+#if defined ZS_ATOMIC_BITMAP_X86
+#undef ZS_ATOMIC_BITMAP_X86
+#endif
+#if defined ZS_ATOMIC_BITMAP_SPARC
+#undef ZS_ATOMIC_BITMAP_SPARC
+#endif
+#if defined ZS_ATOMIC_BITMAP_MUTEX
+#undef ZS_ATOMIC_BITMAP_MUTEX
+#endif
+
+#endif