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() 32436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <vector> 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef _WIN32 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <process.h> // _beginthreadex() 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <windows.h> // CRITICAL_SECTION 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h> // pthread_mutex_t 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "unified_annotations.h" 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic bool s_enable_annotations; 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef _WIN32 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass AtomicInt32 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AtomicInt32(const int value = 0) : m_value(value) { } 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~AtomicInt32() { } 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LONG operator++() { return InterlockedIncrement(&m_value); } 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LONG operator--() { return InterlockedDecrement(&m_value); } 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown volatile LONG m_value; 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Mutex 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex() : m_mutex() 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { InitializeCriticalSection(&m_mutex); } 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Mutex() 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { DeleteCriticalSection(&m_mutex); } 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { EnterCriticalSection(&m_mutex); } 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { LeaveCriticalSection(&m_mutex); } 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CRITICAL_SECTION m_mutex; 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Thread 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Thread() : m_thread(INVALID_HANDLE_VALUE) { } 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Thread() { } 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Create(void* (*pf)(void*), void* arg) 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs* wrapper_arg_p = new WrapperArgs(pf, arg); 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, wrapper, 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown wrapper_arg_p, 0, NULL)); 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Join() 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { WaitForSingleObject(m_thread, INFINITE); } 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct WrapperArgs 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs(void* (*pf)(void*), void* arg) : m_pf(pf), m_arg(arg) { } 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void* (*m_pf)(void*); 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void* m_arg; 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static unsigned int __stdcall wrapper(void* arg) 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs* wrapper_arg_p = reinterpret_cast<WrapperArgs*>(arg); 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WrapperArgs wa = *wrapper_arg_p; 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete wrapper_arg_p; 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return reinterpret_cast<unsigned>((wa.m_pf)(wa.m_arg)); 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HANDLE m_thread; 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else // _WIN32 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass AtomicInt32 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AtomicInt32(const int value = 0) : m_value(value) { } 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~AtomicInt32() { } 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int operator++() { return __sync_add_and_fetch(&m_value, 1); } 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int operator--() { return __sync_sub_and_fetch(&m_value, 1); } 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown volatile int m_value; 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Mutex 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Mutex() : m_mutex() 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_init(&m_mutex, NULL); } 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Mutex() 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_destroy(&m_mutex); } 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Lock() 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_lock(&m_mutex); } 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Unlock() 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_mutex_unlock(&m_mutex); } 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_t m_mutex; 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass Thread 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Thread() : m_tid() { } 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~Thread() { } 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Create(void* (*pf)(void*), void* arg) 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_t attr; 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_init(&attr); 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096); 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_create(&m_tid, &attr, pf, arg); 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_destroy(&attr); 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Join() 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { pthread_join(m_tid, NULL); } 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t m_tid; 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // !defined(_WIN32) 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntemplate<class T> 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass smart_ptr 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef AtomicInt32 counter_t; 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> friend class smart_ptr; 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr() 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { } 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr(T* const pT) 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(pT, pT ? new counter_t(0) : NULL); 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown explicit smart_ptr(Q* const q) 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(q, q ? new counter_t(0) : NULL); 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~smart_ptr() 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(NULL, NULL); 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr(const smart_ptr<T>& sp) 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr(const smart_ptr<Q>& sp) 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_ptr(NULL), m_count_ptr(NULL) 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(const smart_ptr<T>& sp) 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(sp.m_ptr, sp.m_count_ptr); 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(T* const p) 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(p, p ? new counter_t(0) : NULL); 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown template <typename Q> 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr& operator=(Q* const q) 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set(q, q ? new counter_t(0) : NULL); 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *this; 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T* operator->() const 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(m_ptr); 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return m_ptr; 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T& operator*() const 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(m_ptr); 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return *m_ptr; 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void set(T* const pT, counter_t* const count_ptr) 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m_ptr != pT) 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m_count_ptr) 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s_enable_annotations) 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown U_ANNOTATE_HAPPENS_BEFORE(m_count_ptr); 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (--(*m_count_ptr) == 0) 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (s_enable_annotations) 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown U_ANNOTATE_HAPPENS_AFTER(m_count_ptr); 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete m_ptr; 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_ptr = NULL; 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete m_count_ptr; 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count_ptr = NULL; 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_ptr = pT; 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count_ptr = count_ptr; 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (count_ptr) 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ++(*m_count_ptr); 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown T* m_ptr; 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown counter_t* m_count_ptr; 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass counter 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown counter() 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : m_mutex(), m_count() 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { } 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ~counter() 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Data race detection tools that do not recognize the 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // ANNOTATE_HAPPENS_BEFORE() / ANNOTATE_HAPPENS_AFTER() annotations in the 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // smart_ptr<> implementation will report that the assignment below 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // triggers a data race. 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_count = -1; 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int get() const 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int result; 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Lock(); 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown result = m_count; 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Unlock(); 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return result; 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int post_increment() 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int result; 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Lock(); 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown result = m_count++; 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m_mutex.Unlock(); 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return result; 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mutable Mutex m_mutex; 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int m_count; 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void* arg) 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr<counter>* pp = reinterpret_cast<smart_ptr<counter>*>(arg); 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (*pp)->post_increment(); 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pp = NULL; 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown delete pp; 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv) 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int nthreads = std::max(argc > 1 ? atoi(argv[1]) : 1, 1); 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const int iterations = std::max(argc > 2 ? atoi(argv[2]) : 1, 1); 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_enable_annotations = argc > 3 ? !!atoi(argv[3]) : true; 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (int j = 0; j < iterations; ++j) 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov std::vector<Thread> T(nthreads); 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown smart_ptr<counter> p(new counter); 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->post_increment(); 318436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov for (std::vector<Thread>::iterator q = T.begin(); q != T.end(); q++) 319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov q->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; 327436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov for (std::vector<Thread>::iterator q = T.begin(); q != T.end(); q++) 328436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov q->Join(); 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown std::cerr << "Done.\n"; 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 333