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