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