0
0
mirror of https://github.com/zeromq/libzmq.git synced 2025-01-17 21:08:15 +08:00
libzmq/src/atomic_ptr.hpp

203 lines
6.0 KiB
C++
Raw Normal View History

2009-07-29 12:07:54 +02:00
/*
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
2009-07-29 12:07:54 +02:00
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
2009-07-29 12:07:54 +02:00
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
GNU Lesser General Public License for more details.
2009-07-29 12:07:54 +02:00
You should have received a copy of the GNU Lesser General Public License
2009-07-29 12:07:54 +02:00
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2009-08-03 11:30:13 +02:00
#ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
#define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
2009-07-29 12:07:54 +02:00
#include "platform.hpp"
2009-08-03 11:30:13 +02:00
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
2009-08-03 11:30:13 +02:00
#define ZMQ_ATOMIC_PTR_X86
#elif defined __ARM_ARCH_7A__ && defined __GNUC__
#define ZMQ_ATOMIC_PTR_ARM
#elif defined __tile__
#define ZMQ_ATOMIC_PTR_TILE
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_PTR_WINDOWS
#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD)
#define ZMQ_ATOMIC_PTR_ATOMIC_H
2009-07-29 12:07:54 +02:00
#else
2009-08-03 11:30:13 +02:00
#define ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
#endif
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
#include "mutex.hpp"
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_ATOMIC_PTR_WINDOWS
2009-07-29 12:07:54 +02:00
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
2009-07-29 12:07:54 +02:00
#include <atomic.h>
#elif defined ZMQ_ATOMIC_PTR_TILE
#include <arch/atomic.h>
2009-07-29 12:07:54 +02:00
#endif
2009-08-03 11:30:13 +02:00
namespace zmq
2009-07-29 12:07:54 +02:00
{
// This class encapsulates several atomic operations on pointers.
template <typename T> class atomic_ptr_t
{
public:
// Initialise atomic pointer
inline atomic_ptr_t ()
{
ptr = NULL;
}
// Destroy atomic pointer
inline ~atomic_ptr_t ()
{
}
// Set value of atomic pointer in a non-threadsafe way
// Use this function only when you are sure that at most one
// thread is accessing the pointer at the moment.
inline void set (T *ptr_)
{
this->ptr = ptr_;
}
// Perform atomic 'exchange pointers' operation. Pointer is set
// to the 'val' value. Old value is returned.
inline T *xchg (T *val_)
{
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_WINDOWS
2010-04-15 07:32:25 +02:00
return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
2009-07-29 12:07:54 +02:00
return (T*) atomic_swap_ptr (&ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_exchange (&ptr, val_);
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_ATOMIC_PTR_X86
2009-07-29 12:07:54 +02:00
T *old;
__asm__ volatile (
"lock; xchg %0, %2"
: "=r" (old), "=m" (ptr)
: "m" (ptr), "0" (val_));
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T* old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" strex %0, %4, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(val_)
: "cc");
return old;
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
sync.lock ();
T *old = (T*) ptr;
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
2009-07-29 12:07:54 +02:00
#endif
}
// Perform atomic 'compare and swap' operation on the pointer.
// The pointer is compared to 'cmp' argument and if they are
// equal, its value is set to 'val'. Old value of the pointer
// is returned.
inline T *cas (T *cmp_, T *val_)
{
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_WINDOWS
2009-07-29 12:07:54 +02:00
return (T*) InterlockedCompareExchangePointer (
(volatile PVOID*) &ptr, val_, cmp_);
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
2009-07-29 12:07:54 +02:00
return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_val_compare_and_exchange (&ptr, cmp_, val_);
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_ATOMIC_PTR_X86
2009-07-29 12:07:54 +02:00
T *old;
__asm__ volatile (
"lock; cmpxchg %2, %3"
: "=a" (old), "=m" (ptr)
: "r" (val_), "m" (ptr), "0" (cmp_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T *old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" mov %0, #0\n\t"
" teq %1, %4\n\t"
" it eq\n\t"
" strexeq %0, %5, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(cmp_), "r"(val_)
: "cc");
return old;
2009-08-03 11:30:13 +02:00
#elif defined ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
sync.lock ();
T *old = (T*) ptr;
if (ptr == cmp_)
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
2009-07-29 12:07:54 +02:00
#endif
}
private:
volatile T *ptr;
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
mutex_t sync;
#endif
atomic_ptr_t (const atomic_ptr_t&);
const atomic_ptr_t &operator = (const atomic_ptr_t&);
2009-07-29 12:07:54 +02:00
};
}
// Remove macros local to this file.
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_WINDOWS
#undef ZMQ_ATOMIC_PTR_WINDOWS
2009-07-29 12:07:54 +02:00
#endif
#if defined ZMQ_ATOMIC_PTR_ATOMIC_H
#undef ZMQ_ATOMIC_PTR_ATOMIC_H
2009-07-29 12:07:54 +02:00
#endif
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_X86
#undef ZMQ_ATOMIC_PTR_X86
2009-07-29 12:07:54 +02:00
#endif
#if defined ZMQ_ATOMIC_PTR_ARM
#undef ZMQ_ATOMIC_PTR_ARM
#endif
2009-08-03 11:30:13 +02:00
#if defined ZMQ_ATOMIC_PTR_MUTEX
#undef ZMQ_ATOMIC_PTR_MUTEX
2009-07-29 12:07:54 +02:00
#endif
#endif