blob: 43343022275a52123c983d88c20158c2d19ae5aa [file] [log] [blame]
barte32f8622010-03-06 10:54:36 +00001/*
2 * Test program that illustrates how to annotate a smart pointer
3 * implementation. In a multithreaded program the following is relevant when
4 * working with smart pointers:
5 * - whether or not the objects pointed at are shared over threads.
6 * - whether or not the methods of the objects pointed at are thread-safe.
7 * - whether or not the smart pointer objects are shared over threads.
8 * - whether or not the smart pointer object itself is thread-safe.
9 *
10 * Most smart pointer implemenations are not thread-safe
11 * (e.g. boost::shared_ptr<>, tr1::shared_ptr<> and the smart_ptr<>
12 * implementation below). This means that it is not safe to modify a shared
13 * pointer object that is shared over threads without proper synchronization.
14 *
15 * Even for non-thread-safe smart pointers it is possible to have different
16 * threads access the same object via smart pointers without triggering data
17 * races on the smart pointer objects.
18 *
19 * A smart pointer implementation guarantees that the destructor of the object
20 * pointed at is invoked after the last smart pointer that points to that
21 * object has been destroyed or reset. Data race detection tools cannot detect
22 * this ordering without explicit annotation for smart pointers that track
23 * references without invoking synchronization operations recognized by data
24 * race detection tools.
25 */
26
27
28#include <cassert> // assert()
29#include <climits> // PTHREAD_STACK_MIN
bart5530f5f2010-03-07 10:42:15 +000030#include <iostream> // std::cerr
barte32f8622010-03-06 10:54:36 +000031#include <stdlib.h> // atoi()
bart6b9b1b02013-10-02 16:22:23 +000032#include <vector>
bartc710de62010-03-04 08:51:30 +000033#ifdef _WIN32
barte32f8622010-03-06 10:54:36 +000034#include <process.h> // _beginthreadex()
35#include <windows.h> // CRITICAL_SECTION
bartc710de62010-03-04 08:51:30 +000036#else
barte32f8622010-03-06 10:54:36 +000037#include <pthread.h> // pthread_mutex_t
bartc710de62010-03-04 08:51:30 +000038#endif
bart5530f5f2010-03-07 10:42:15 +000039#include "unified_annotations.h"
40
41
bart19aa3922011-07-13 10:43:05 +000042static bool s_enable_annotations;
barte32f8622010-03-06 10:54:36 +000043
bartc710de62010-03-04 08:51:30 +000044
45#ifdef _WIN32
barte32f8622010-03-06 10:54:36 +000046
bartc710de62010-03-04 08:51:30 +000047class AtomicInt32
48{
49public:
50 AtomicInt32(const int value = 0) : m_value(value) { }
51 ~AtomicInt32() { }
52 LONG operator++() { return InterlockedIncrement(&m_value); }
53 LONG operator--() { return InterlockedDecrement(&m_value); }
54
55private:
56 volatile LONG m_value;
57};
58
59class Mutex
60{
61public:
62 Mutex() : m_mutex()
63 { InitializeCriticalSection(&m_mutex); }
64 ~Mutex()
65 { DeleteCriticalSection(&m_mutex); }
66 void Lock()
67 { EnterCriticalSection(&m_mutex); }
68 void Unlock()
69 { LeaveCriticalSection(&m_mutex); }
70
71private:
72 CRITICAL_SECTION m_mutex;
73};
74
bartc710de62010-03-04 08:51:30 +000075class Thread
76{
77public:
78 Thread() : m_thread(INVALID_HANDLE_VALUE) { }
79 ~Thread() { }
80 void Create(void* (*pf)(void*), void* arg)
81 {
barte32f8622010-03-06 10:54:36 +000082 WrapperArgs* wrapper_arg_p = new WrapperArgs(pf, arg);
83 m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, wrapper,
84 wrapper_arg_p, 0, NULL));
bartc710de62010-03-04 08:51:30 +000085 }
86 void Join()
87 { WaitForSingleObject(m_thread, INFINITE); }
88
89private:
barte32f8622010-03-06 10:54:36 +000090 struct WrapperArgs
bartc710de62010-03-04 08:51:30 +000091 {
barte32f8622010-03-06 10:54:36 +000092 WrapperArgs(void* (*pf)(void*), void* arg) : m_pf(pf), m_arg(arg) { }
bartc710de62010-03-04 08:51:30 +000093
94 void* (*m_pf)(void*);
95 void* m_arg;
96 };
97 static unsigned int __stdcall wrapper(void* arg)
98 {
barte32f8622010-03-06 10:54:36 +000099 WrapperArgs* wrapper_arg_p = reinterpret_cast<WrapperArgs*>(arg);
100 WrapperArgs wa = *wrapper_arg_p;
bartc710de62010-03-04 08:51:30 +0000101 delete wrapper_arg_p;
102 return reinterpret_cast<unsigned>((wa.m_pf)(wa.m_arg));
103 }
104 HANDLE m_thread;
105};
barte32f8622010-03-06 10:54:36 +0000106
bartc710de62010-03-04 08:51:30 +0000107#else // _WIN32
barte32f8622010-03-06 10:54:36 +0000108
bartc710de62010-03-04 08:51:30 +0000109class AtomicInt32
110{
111public:
112 AtomicInt32(const int value = 0) : m_value(value) { }
113 ~AtomicInt32() { }
114 int operator++() { return __sync_add_and_fetch(&m_value, 1); }
115 int operator--() { return __sync_sub_and_fetch(&m_value, 1); }
116private:
117 volatile int m_value;
118};
119
120class Mutex
121{
122public:
123 Mutex() : m_mutex()
124 { pthread_mutex_init(&m_mutex, NULL); }
125 ~Mutex()
126 { pthread_mutex_destroy(&m_mutex); }
127 void Lock()
128 { pthread_mutex_lock(&m_mutex); }
129 void Unlock()
130 { pthread_mutex_unlock(&m_mutex); }
131
132private:
133 pthread_mutex_t m_mutex;
134};
135
bartc710de62010-03-04 08:51:30 +0000136class Thread
137{
138public:
139 Thread() : m_tid() { }
140 ~Thread() { }
141 void Create(void* (*pf)(void*), void* arg)
barte32f8622010-03-06 10:54:36 +0000142 {
143 pthread_attr_t attr;
144 pthread_attr_init(&attr);
145 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096);
146 pthread_create(&m_tid, &attr, pf, arg);
147 pthread_attr_destroy(&attr);
148 }
bartc710de62010-03-04 08:51:30 +0000149 void Join()
150 { pthread_join(m_tid, NULL); }
151private:
152 pthread_t m_tid;
153};
barte32f8622010-03-06 10:54:36 +0000154
155#endif // !defined(_WIN32)
bartc710de62010-03-04 08:51:30 +0000156
bart21e49d72010-03-02 08:57:50 +0000157
158template<class T>
159class smart_ptr
160{
161public:
bartc710de62010-03-04 08:51:30 +0000162 typedef AtomicInt32 counter_t;
bart21e49d72010-03-02 08:57:50 +0000163
164 template <typename Q> friend class smart_ptr;
165
166 explicit smart_ptr()
167 : m_ptr(NULL), m_count_ptr(NULL)
168 { }
169
170 explicit smart_ptr(T* const pT)
171 : m_ptr(NULL), m_count_ptr(NULL)
172 {
173 set(pT, pT ? new counter_t(0) : NULL);
174 }
175
176 template <typename Q>
177 explicit smart_ptr(Q* const q)
178 : m_ptr(NULL), m_count_ptr(NULL)
179 {
180 set(q, q ? new counter_t(0) : NULL);
181 }
182
183 ~smart_ptr()
184 {
185 set(NULL, NULL);
186 }
187
188 smart_ptr(const smart_ptr<T>& sp)
189 : m_ptr(NULL), m_count_ptr(NULL)
190 {
191 set(sp.m_ptr, sp.m_count_ptr);
192 }
193
194 template <typename Q>
195 smart_ptr(const smart_ptr<Q>& sp)
196 : m_ptr(NULL), m_count_ptr(NULL)
197 {
198 set(sp.m_ptr, sp.m_count_ptr);
199 }
200
201 smart_ptr& operator=(const smart_ptr<T>& sp)
202 {
203 set(sp.m_ptr, sp.m_count_ptr);
204 return *this;
205 }
206
207 smart_ptr& operator=(T* const p)
208 {
209 set(p, p ? new counter_t(0) : NULL);
210 return *this;
211 }
212
213 template <typename Q>
214 smart_ptr& operator=(Q* const q)
215 {
216 set(q, q ? new counter_t(0) : NULL);
217 return *this;
218 }
219
220 T* operator->() const
221 {
222 assert(m_ptr);
223 return m_ptr;
224 }
225
226 T& operator*() const
227 {
228 assert(m_ptr);
229 return *m_ptr;
230 }
231
232private:
bartc710de62010-03-04 08:51:30 +0000233 void set(T* const pT, counter_t* const count_ptr)
bart21e49d72010-03-02 08:57:50 +0000234 {
235 if (m_ptr != pT)
236 {
barte32f8622010-03-06 10:54:36 +0000237 if (m_count_ptr)
bart21e49d72010-03-02 08:57:50 +0000238 {
bart5530f5f2010-03-07 10:42:15 +0000239 if (s_enable_annotations)
bart62049c42010-09-09 10:12:43 +0000240 U_ANNOTATE_HAPPENS_BEFORE(m_count_ptr);
barte32f8622010-03-06 10:54:36 +0000241 if (--(*m_count_ptr) == 0)
242 {
bart5530f5f2010-03-07 10:42:15 +0000243 if (s_enable_annotations)
bart62049c42010-09-09 10:12:43 +0000244 U_ANNOTATE_HAPPENS_AFTER(m_count_ptr);
barte32f8622010-03-06 10:54:36 +0000245 delete m_ptr;
246 m_ptr = NULL;
247 delete m_count_ptr;
248 m_count_ptr = NULL;
249 }
bart21e49d72010-03-02 08:57:50 +0000250 }
251 m_ptr = pT;
252 m_count_ptr = count_ptr;
253 if (count_ptr)
bartc710de62010-03-04 08:51:30 +0000254 ++(*m_count_ptr);
bart21e49d72010-03-02 08:57:50 +0000255 }
256 }
257
bartc710de62010-03-04 08:51:30 +0000258 T* m_ptr;
259 counter_t* m_count_ptr;
bart21e49d72010-03-02 08:57:50 +0000260};
261
262class counter
263{
264public:
265 counter()
266 : m_mutex(), m_count()
barte32f8622010-03-06 10:54:36 +0000267 { }
bart21e49d72010-03-02 08:57:50 +0000268 ~counter()
barte32f8622010-03-06 10:54:36 +0000269 {
270 // Data race detection tools that do not recognize the
271 // ANNOTATE_HAPPENS_BEFORE() / ANNOTATE_HAPPENS_AFTER() annotations in the
272 // smart_ptr<> implementation will report that the assignment below
273 // triggers a data race.
274 m_count = -1;
275 }
bart21e49d72010-03-02 08:57:50 +0000276 int get() const
277 {
278 int result;
bartc710de62010-03-04 08:51:30 +0000279 m_mutex.Lock();
bart21e49d72010-03-02 08:57:50 +0000280 result = m_count;
bartc710de62010-03-04 08:51:30 +0000281 m_mutex.Unlock();
bart21e49d72010-03-02 08:57:50 +0000282 return result;
283 }
284 int post_increment()
285 {
286 int result;
bartc710de62010-03-04 08:51:30 +0000287 m_mutex.Lock();
bart21e49d72010-03-02 08:57:50 +0000288 result = m_count++;
bartc710de62010-03-04 08:51:30 +0000289 m_mutex.Unlock();
bart21e49d72010-03-02 08:57:50 +0000290 return result;
291 }
292
293private:
bartc710de62010-03-04 08:51:30 +0000294 mutable Mutex m_mutex;
295 int m_count;
bart21e49d72010-03-02 08:57:50 +0000296};
297
bart21e49d72010-03-02 08:57:50 +0000298static void* thread_func(void* arg)
299{
barte32f8622010-03-06 10:54:36 +0000300 smart_ptr<counter>* pp = reinterpret_cast<smart_ptr<counter>*>(arg);
301 (*pp)->post_increment();
302 *pp = NULL;
303 delete pp;
bart21e49d72010-03-02 08:57:50 +0000304 return NULL;
305}
306
307int main(int argc, char** argv)
308{
barte32f8622010-03-06 10:54:36 +0000309 const int nthreads = std::max(argc > 1 ? atoi(argv[1]) : 1, 1);
bart5530f5f2010-03-07 10:42:15 +0000310 const int iterations = std::max(argc > 2 ? atoi(argv[2]) : 1, 1);
311 s_enable_annotations = argc > 3 ? !!atoi(argv[3]) : true;
bart21e49d72010-03-02 08:57:50 +0000312
bart5530f5f2010-03-07 10:42:15 +0000313 for (int j = 0; j < iterations; ++j)
314 {
bart6b9b1b02013-10-02 16:22:23 +0000315 std::vector<Thread> T(nthreads);
bart5530f5f2010-03-07 10:42:15 +0000316 smart_ptr<counter> p(new counter);
317 p->post_increment();
bart6b9b1b02013-10-02 16:22:23 +0000318 for (std::vector<Thread>::iterator q = T.begin(); q != T.end(); q++)
319 q->Create(thread_func, new smart_ptr<counter>(p));
bart863f1eb2011-08-30 15:09:37 +0000320 {
321 // Avoid that counter.m_mutex introduces a false ordering on the
322 // counter.m_count accesses.
323 const timespec delay = { 0, 100 * 1000 * 1000 };
324 nanosleep(&delay, 0);
325 }
bart5530f5f2010-03-07 10:42:15 +0000326 p = NULL;
bart6b9b1b02013-10-02 16:22:23 +0000327 for (std::vector<Thread>::iterator q = T.begin(); q != T.end(); q++)
328 q->Join();
bart5530f5f2010-03-07 10:42:15 +0000329 }
330 std::cerr << "Done.\n";
bart21e49d72010-03-02 08:57:50 +0000331 return 0;
332}