libzmq master
The Intelligent Transport Layer

atomic_counter.hpp

Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines