libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
atomic_ptr.hpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3 
4  This file is part of libzmq, the ZeroMQ core engine in C++.
5 
6  libzmq is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License (LGPL) as published
8  by the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  As a special exception, the Contributors give you permission to link
12  this library with independent modules to produce an executable,
13  regardless of the license terms of these independent modules, and to
14  copy and distribute the resulting executable under terms of your choice,
15  provided that you also meet, for each linked independent module, the
16  terms and conditions of the license of that module. An independent
17  module is a module which is not derived from or based on this library.
18  If you modify this library, you must extend this exception to your
19  version of the library.
20 
21  libzmq is distributed in the hope that it will be useful, but WITHOUT
22  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24  License for more details.
25 
26  You should have received a copy of the GNU Lesser General Public License
27  along with this program. If not, see <http://www.gnu.org/licenses/>.
28 */
29 
30 #ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
31 #define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
32 
33 #include "platform.hpp"
34 
35 #if defined ZMQ_FORCE_MUTEXES
36 #define ZMQ_ATOMIC_PTR_MUTEX
37 #elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
38 #define ZMQ_ATOMIC_PTR_INTRINSIC
39 #elif (defined ZMQ_CXX11 && defined __cplusplus && __cplusplus >= 201103L)
40 #define ZMQ_ATOMIC_PTR_CXX11
41 #elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
42 #define ZMQ_ATOMIC_PTR_X86
43 #elif defined __ARM_ARCH_7A__ && defined __GNUC__
44 #define ZMQ_ATOMIC_PTR_ARM
45 #elif defined __tile__
46 #define ZMQ_ATOMIC_PTR_TILE
47 #elif defined ZMQ_HAVE_WINDOWS
48 #define ZMQ_ATOMIC_PTR_WINDOWS
49 #elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD || defined ZMQ_HAVE_GNU)
50 #define ZMQ_ATOMIC_PTR_ATOMIC_H
51 #else
52 #define ZMQ_ATOMIC_PTR_MUTEX
53 #endif
54 
55 #if defined ZMQ_ATOMIC_PTR_MUTEX
56 #include "mutex.hpp"
57 #elif defined ZMQ_ATOMIC_PTR_CXX11
58 #include <atomic>
59 #elif defined ZMQ_ATOMIC_PTR_WINDOWS
60 #include "windows.hpp"
61 #elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
62 #include <atomic.h>
63 #elif defined ZMQ_ATOMIC_PTR_TILE
64 #include <arch/atomic.h>
65 #endif
66 
67 namespace zmq
68 {
69 
70  // This class encapsulates several atomic operations on pointers.
71 
72  template <typename T> class atomic_ptr_t
73  {
74  public:
75 
76  // Initialise atomic pointer
77  inline atomic_ptr_t ()
78  {
79  ptr = NULL;
80  }
81 
82  // Destroy atomic pointer
83  inline ~atomic_ptr_t ()
84  {
85  }
86 
87  // Set value of atomic pointer in a non-threadsafe way
88  // Use this function only when you are sure that at most one
89  // thread is accessing the pointer at the moment.
90  inline void set (T *ptr_)
91  {
92  this->ptr = ptr_;
93  }
94 
95  // Perform atomic 'exchange pointers' operation. Pointer is set
96  // to the 'val' value. Old value is returned.
97  inline T *xchg (T *val_)
98  {
99 #if defined ZMQ_ATOMIC_PTR_WINDOWS
100  return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
101 #elif defined ZMQ_ATOMIC_PTR_INTRINSIC
102  return (T*) __atomic_exchange_n (&ptr, val_, __ATOMIC_ACQ_REL);
103 #elif defined ZMQ_ATOMIC_PTR_CXX11
104  return ptr.exchange(val_, std::memory_order_acq_rel);
105 #elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
106  return (T*) atomic_swap_ptr (&ptr, val_);
107 #elif defined ZMQ_ATOMIC_PTR_TILE
108  return (T*) arch_atomic_exchange (&ptr, val_);
109 #elif defined ZMQ_ATOMIC_PTR_X86
110  T *old;
111  __asm__ volatile (
112  "lock; xchg %0, %2"
113  : "=r" (old), "=m" (ptr)
114  : "m" (ptr), "0" (val_));
115  return old;
116 #elif defined ZMQ_ATOMIC_PTR_ARM
117  T* old;
118  unsigned int flag;
119  __asm__ volatile (
120  " dmb sy\n\t"
121  "1: ldrex %1, [%3]\n\t"
122  " strex %0, %4, [%3]\n\t"
123  " teq %0, #0\n\t"
124  " bne 1b\n\t"
125  " dmb sy\n\t"
126  : "=&r"(flag), "=&r"(old), "+Qo"(ptr)
127  : "r"(&ptr), "r"(val_)
128  : "cc");
129  return old;
130 #elif defined ZMQ_ATOMIC_PTR_MUTEX
131  sync.lock ();
132  T *old = (T*) ptr;
133  ptr = val_;
134  sync.unlock ();
135  return old;
136 #else
137 #error atomic_ptr is not implemented for this platform
138 #endif
139  }
140 
141  // Perform atomic 'compare and swap' operation on the pointer.
142  // The pointer is compared to 'cmp' argument and if they are
143  // equal, its value is set to 'val'. Old value of the pointer
144  // is returned.
145  inline T *cas (T *cmp_, T *val_)
146  {
147 #if defined ZMQ_ATOMIC_PTR_WINDOWS
148  return (T*) InterlockedCompareExchangePointer (
149  (volatile PVOID*) &ptr, val_, cmp_);
150 #elif defined ZMQ_ATOMIC_PTR_INTRINSIC
151  T *old = cmp_;
152  __atomic_compare_exchange_n (&ptr, (volatile T**) &old, val_, false,
153  __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
154  return old;
155 #elif defined ZMQ_ATOMIC_PTR_CXX11
156  ptr.compare_exchange_strong(cmp_, val_, std::memory_order_acq_rel);
157  return cmp_;
158 #elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
159  return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
160 #elif defined ZMQ_ATOMIC_PTR_TILE
161  return (T*) arch_atomic_val_compare_and_exchange (&ptr, cmp_, val_);
162 #elif defined ZMQ_ATOMIC_PTR_X86
163  T *old;
164  __asm__ volatile (
165  "lock; cmpxchg %2, %3"
166  : "=a" (old), "=m" (ptr)
167  : "r" (val_), "m" (ptr), "0" (cmp_)
168  : "cc");
169  return old;
170 #elif defined ZMQ_ATOMIC_PTR_ARM
171  T *old;
172  unsigned int flag;
173  __asm__ volatile (
174  " dmb sy\n\t"
175  "1: ldrex %1, [%3]\n\t"
176  " mov %0, #0\n\t"
177  " teq %1, %4\n\t"
178  " it eq\n\t"
179  " strexeq %0, %5, [%3]\n\t"
180  " teq %0, #0\n\t"
181  " bne 1b\n\t"
182  " dmb sy\n\t"
183  : "=&r"(flag), "=&r"(old), "+Qo"(ptr)
184  : "r"(&ptr), "r"(cmp_), "r"(val_)
185  : "cc");
186  return old;
187 #elif defined ZMQ_ATOMIC_PTR_MUTEX
188  sync.lock ();
189  T *old = (T*) ptr;
190  if (ptr == cmp_)
191  ptr = val_;
192  sync.unlock ();
193  return old;
194 #else
195 #error atomic_ptr is not implemented for this platform
196 #endif
197  }
198 
199  private:
200 
201 #if defined ZMQ_ATOMIC_PTR_CXX11
202  std::atomic<T*> ptr;
203 #else
204  volatile T *ptr;
205 #endif
206 
207 #if defined ZMQ_ATOMIC_PTR_MUTEX
209 #endif
210 
211 #if ! defined ZMQ_ATOMIC_PTR_CXX11
212  atomic_ptr_t (const atomic_ptr_t&);
213  const atomic_ptr_t &operator = (const atomic_ptr_t&);
214 #endif
215  };
216 
217 }
218 
219 // Remove macros local to this file.
220 #undef ZMQ_ATOMIC_PTR_MUTEX
221 #undef ZMQ_ATOMIC_PTR_INTRINSIC
222 #undef ZMQ_ATOMIC_PTR_CXX11
223 #undef ZMQ_ATOMIC_PTR_X86
224 #undef ZMQ_ATOMIC_PTR_ARM
225 #undef ZMQ_ATOMIC_PTR_TILE
226 #undef ZMQ_ATOMIC_PTR_WINDOWS
227 #undef ZMQ_ATOMIC_PTR_ATOMIC_H
228 
229 #endif
const atomic_ptr_t & operator=(const atomic_ptr_t &)
T * cas(T *cmp_, T *val_)
Definition: atomic_ptr.hpp:145
T * xchg(T *val_)
Definition: atomic_ptr.hpp:97
void unlock()
Definition: mutex.hpp:136
void lock()
Definition: mutex.hpp:120
volatile T * ptr
Definition: atomic_ptr.hpp:204
Definition: address.hpp:35