1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Test program that illustrates how to annotate a smart pointer 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * implementation. In a multithreaded program the following is relevant when 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * working with smart pointers: 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * - whether or not the objects pointed at are shared over threads. 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * - whether or not the methods of the objects pointed at are thread-safe. 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * - whether or not the smart pointer objects are shared over threads. 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * - whether or not the smart pointer object itself is thread-safe. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Most smart pointer implemenations are not thread-safe 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * (e.g. boost::shared_ptr<>, tr1::shared_ptr<> and the smart_ptr<> 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * implementation below). This means that it is not safe to modify a shared 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * pointer object that is shared over threads without proper synchronization. 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Even for non-thread-safe smart pointers it is possible to have different 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * threads access the same object via smart pointers without triggering data 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * races on the smart pointer objects. 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * A smart pointer implementation guarantees that the destructor of the object 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * pointed at is invoked after the last smart pointer that points to that 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * object has been destroyed or reset. Data race detection tools cannot detect 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * this ordering without explicit annotation for smart pointers that track 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * references without invoking synchronization operations recognized by data 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * race detection tools. 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <cassert> // assert() 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <climits> // PTHREAD_STACK_MIN 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <iostream> // std::cerr 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h> // atoi() 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef _WIN32 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <process.h> // _beginthreadex() 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <windows.h> // CRITICAL_SECTION 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h> // pthread_mutex_t 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "unified_annotations.h" 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic bool s_enable_annotations; 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef _WIN32 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass AtomicInt32 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AtomicInt32(const int value = 0) : m_value(value) { } 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~AtomicInt32() { } 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LONG operator++() { return InterlockedIncrement(&m_value); } 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LONG operator--() { return InterlockedDecrement(&m_value); } 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown volatile LONG m_value; 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Mutex 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex() : m_mutex() 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { InitializeCriticalSection(&m_mutex); } 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Mutex() 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { DeleteCriticalSection(&m_mutex); } 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { EnterCriticalSection(&m_mutex); } 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { LeaveCriticalSection(&m_mutex); } 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CRITICAL_SECTION m_mutex; 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Thread 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Thread() : m_thread(INVALID_HANDLE_VALUE) { } 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Thread() { } 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Create(void* (*pf)(void*), void* arg) 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs* wrapper_arg_p = new WrapperArgs(pf, arg); 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, wrapper, 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown wrapper_arg_p, 0, NULL)); 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Join() 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { WaitForSingleObject(m_thread, INFINITE); } 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct WrapperArgs 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs(void* (*pf)(void*), void* arg) : m_pf(pf), m_arg(arg) { } 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void* (*m_pf)(void*); 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void* m_arg; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static unsigned int __stdcall wrapper(void* arg) 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs* wrapper_arg_p = reinterpret_cast<WrapperArgs*>(arg); 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs wa = *wrapper_arg_p; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete wrapper_arg_p; 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return reinterpret_cast<unsigned>((wa.m_pf)(wa.m_arg)); 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HANDLE m_thread; 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else // _WIN32 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass AtomicInt32 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AtomicInt32(const int value = 0) : m_value(value) { } 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~AtomicInt32() { } 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int operator++() { return __sync_add_and_fetch(&m_value, 1); } 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int operator--() { return __sync_sub_and_fetch(&m_value, 1); } 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown volatile int m_value; 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Mutex 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex() : m_mutex() 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_init(&m_mutex, NULL); } 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Mutex() 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_destroy(&m_mutex); } 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_lock(&m_mutex); } 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_unlock(&m_mutex); } 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_t m_mutex; 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Thread 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Thread() : m_tid() { } 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Thread() { } 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Create(void* (*pf)(void*), void* arg) 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_t attr; 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_init(&attr); 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096); 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_create(&m_tid, &attr, pf, arg); 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_destroy(&attr); 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Join() 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_join(m_tid, NULL); } 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t m_tid; 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // !defined(_WIN32) 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntemplate<class T> 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass smart_ptr 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef AtomicInt32 counter_t; 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> friend class smart_ptr; 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr() 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { } 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr(T* const pT) 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(pT, pT ? new counter_t(0) : NULL); 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr(Q* const q) 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(q, q ? new counter_t(0) : NULL); 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~smart_ptr() 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(NULL, NULL); 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr(const smart_ptr<T>& sp) 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr(const smart_ptr<Q>& sp) 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(const smart_ptr<T>& sp) 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(T* const p) 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(p, p ? new counter_t(0) : NULL); 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(Q* const q) 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(q, q ? new counter_t(0) : NULL); 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T* operator->() const 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(m_ptr); 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return m_ptr; 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T& operator*() const 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(m_ptr); 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *m_ptr; 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void set(T* const pT, counter_t* const count_ptr) 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m_ptr != pT) 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m_count_ptr) 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s_enable_annotations) 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown U_ANNOTATE_HAPPENS_BEFORE(m_count_ptr); 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (--(*m_count_ptr) == 0) 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s_enable_annotations) 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown U_ANNOTATE_HAPPENS_AFTER(m_count_ptr); 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete m_ptr; 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_ptr = NULL; 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete m_count_ptr; 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count_ptr = NULL; 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_ptr = pT; 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count_ptr = count_ptr; 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (count_ptr) 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ++(*m_count_ptr); 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T* m_ptr; 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown counter_t* m_count_ptr; 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass counter 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown counter() 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_mutex(), m_count() 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { } 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~counter() 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Data race detection tools that do not recognize the 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // ANNOTATE_HAPPENS_BEFORE() / ANNOTATE_HAPPENS_AFTER() annotations in the 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // smart_ptr<> implementation will report that the assignment below 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // triggers a data race. 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count = -1; 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int get() const 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int result; 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Lock(); 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown result = m_count; 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Unlock(); 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return result; 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int post_increment() 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int result; 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Lock(); 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown result = m_count++; 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Unlock(); 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return result; 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mutable Mutex m_mutex; 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int m_count; 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void* arg) 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr<counter>* pp = reinterpret_cast<smart_ptr<counter>*>(arg); 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*pp)->post_increment(); 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pp = NULL; 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete pp; 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv) 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int nthreads = std::max(argc > 1 ? atoi(argv[1]) : 1, 1); 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int iterations = std::max(argc > 2 ? atoi(argv[2]) : 1, 1); 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_enable_annotations = argc > 3 ? !!atoi(argv[3]) : true; 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (int j = 0; j < iterations; ++j) 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Thread T[nthreads]; 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr<counter> p(new counter); 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->post_increment(); 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (int i = 0; i < nthreads; ++i) 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T[i].Create(thread_func, new smart_ptr<counter>(p)); 320b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { 321b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Avoid that counter.m_mutex introduces a false ordering on the 322b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // counter.m_count accesses. 323b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov const timespec delay = { 0, 100 * 1000 * 1000 }; 324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nanosleep(&delay, 0); 325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = NULL; 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (int i = 0; i < nthreads; ++i) 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T[i].Join(); 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown std::cerr << "Done.\n"; 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 333