![]() |
libzmq master
The Intelligent Transport Layer
|
00001 /* 00002 Copyright (c) 2009-2011 250bpm s.r.o. 00003 Copyright (c) 2007-2009 iMatix Corporation 00004 Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file 00005 00006 This file is part of 0MQ. 00007 00008 0MQ is free software; you can redistribute it and/or modify it under 00009 the terms of the GNU Lesser General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 0MQ is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU Lesser General Public License for more details. 00017 00018 You should have received a copy of the GNU Lesser General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 00022 #ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__ 00023 #define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__ 00024 00025 #include "stdint.hpp" 00026 #include "platform.hpp" 00027 00028 #if defined ZMQ_FORCE_MUTEXES 00029 #define ZMQ_ATOMIC_COUNTER_MUTEX 00030 #elif (defined __i386__ || defined __x86_64__) && defined __GNUC__ 00031 #define ZMQ_ATOMIC_COUNTER_X86 00032 #elif defined ZMQ_HAVE_WINDOWS 00033 #define ZMQ_ATOMIC_COUNTER_WINDOWS 00034 #elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD) 00035 #define ZMQ_ATOMIC_COUNTER_ATOMIC_H 00036 #else 00037 #define ZMQ_ATOMIC_COUNTER_MUTEX 00038 #endif 00039 00040 #if defined ZMQ_ATOMIC_COUNTER_MUTEX 00041 #include "mutex.hpp" 00042 #elif defined ZMQ_ATOMIC_COUNTER_WINDOWS 00043 #include "windows.hpp" 00044 #elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H 00045 #include <atomic.h> 00046 #endif 00047 00048 namespace zmq 00049 { 00050 00051 // This class represents an integer that can be incremented/decremented 00052 // in atomic fashion. 00053 00054 class atomic_counter_t 00055 { 00056 public: 00057 00058 typedef uint32_t integer_t; 00059 00060 inline atomic_counter_t (integer_t value_ = 0) : 00061 value (value_) 00062 { 00063 } 00064 00065 inline ~atomic_counter_t () 00066 { 00067 } 00068 00069 // Set counter value (not thread-safe). 00070 inline void set (integer_t value_) 00071 { 00072 value = value_; 00073 } 00074 00075 // Atomic addition. Returns the old value. 00076 inline integer_t add (integer_t increment_) 00077 { 00078 integer_t old_value; 00079 00080 #if defined ZMQ_ATOMIC_COUNTER_WINDOWS 00081 old_value = InterlockedExchangeAdd ((LONG*) &value, increment_); 00082 #elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H 00083 integer_t new_value = atomic_add_32_nv (&value, increment_); 00084 old_value = new_value - increment_; 00085 #elif defined ZMQ_ATOMIC_COUNTER_X86 00086 __asm__ volatile ( 00087 "lock; xadd %0, %1 \n\t" 00088 : "=r" (old_value), "=m" (value) 00089 : "0" (increment_), "m" (value) 00090 : "cc", "memory"); 00091 #elif defined ZMQ_ATOMIC_COUNTER_MUTEX 00092 sync.lock (); 00093 old_value = value; 00094 value += increment_; 00095 sync.unlock (); 00096 #else 00097 #error atomic_counter is not implemented for this platform 00098 #endif 00099 return old_value; 00100 } 00101 00102 // Atomic subtraction. Returns false if the counter drops to zero. 00103 inline bool sub (integer_t decrement) 00104 { 00105 #if defined ZMQ_ATOMIC_COUNTER_WINDOWS 00106 LONG delta = - ((LONG) decrement); 00107 integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta); 00108 return old - decrement != 0; 00109 #elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H 00110 int32_t delta = - ((int32_t) decrement); 00111 integer_t nv = atomic_add_32_nv (&value, delta); 00112 return nv != 0; 00113 #elif defined ZMQ_ATOMIC_COUNTER_X86 00114 integer_t oldval = -decrement; 00115 volatile integer_t *val = &value; 00116 __asm__ volatile ("lock; xaddl %0,%1" 00117 : "=r" (oldval), "=m" (*val) 00118 : "0" (oldval), "m" (*val) 00119 : "cc", "memory"); 00120 return oldval != decrement; 00121 #elif defined ZMQ_ATOMIC_COUNTER_MUTEX 00122 sync.lock (); 00123 value -= decrement; 00124 bool result = value ? true : false; 00125 sync.unlock (); 00126 return result; 00127 #else 00128 #error atomic_counter is not implemented for this platform 00129 #endif 00130 } 00131 00132 inline integer_t get () 00133 { 00134 return value; 00135 } 00136 00137 private: 00138 00139 volatile integer_t value; 00140 #if defined ZMQ_ATOMIC_COUNTER_MUTEX 00141 mutex_t sync; 00142 #endif 00143 00144 atomic_counter_t (const atomic_counter_t&); 00145 const atomic_counter_t& operator = (const atomic_counter_t&); 00146 }; 00147 00148 } 00149 00150 // Remove macros local to this file. 00151 #if defined ZMQ_ATOMIC_COUNTER_WINDOWS 00152 #undef ZMQ_ATOMIC_COUNTER_WINDOWS 00153 #endif 00154 #if defined ZMQ_ATOMIC_COUNTER_ATOMIC_H 00155 #undef ZMQ_ATOMIC_COUNTER_ATOMIC_H 00156 #endif 00157 #if defined ZMQ_ATOMIC_COUNTER_X86 00158 #undef ZMQ_ATOMIC_COUNTER_X86 00159 #endif 00160 #if defined ZMQ_ATOMIC_COUNTER_MUTEX 00161 #undef ZMQ_ATOMIC_COUNTER_MUTEX 00162 #endif 00163 00164 #endif 00165