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