diff options
Diffstat (limited to 'src/atomic_bitmap.hpp')
-rw-r--r-- | src/atomic_bitmap.hpp | 286 |
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 |