1/*
2  This file is part of drd, a thread error detector.
3
4  Copyright (C) 2006-2013 Bart Van Assche <bvanassche@acm.org>.
5
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of the
9  License, or (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19  02111-1307, USA.
20
21  The GNU General Public License is contained in the file COPYING.
22*/
23
24
25#include "drd_basics.h"
26#include "drd_clientobj.h"
27#include "drd_error.h"
28#include "drd_mutex.h"
29#include "pub_tool_vki.h"
30#include "pub_tool_errormgr.h"    /* VG_(maybe_record_error)()     */
31#include "pub_tool_libcassert.h"  /* tl_assert()                   */
32#include "pub_tool_libcbase.h"    /* VG_(strlen)                   */
33#include "pub_tool_libcprint.h"   /* VG_(message)()                */
34#include "pub_tool_libcproc.h"    /* VG_(read_millisecond_timer)() */
35#include "pub_tool_machine.h"     /* VG_(get_IP)()                 */
36#include "pub_tool_threadstate.h" /* VG_(get_running_tid)()        */
37
38
39/* Local functions. */
40
41static void mutex_cleanup(struct mutex_info* p);
42static Bool mutex_is_locked(struct mutex_info* const p);
43static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid);
44
45
46/* Local variables. */
47
48static Bool s_trace_mutex;
49static ULong s_mutex_lock_count;
50static ULong s_mutex_segment_creation_count;
51static UInt s_mutex_lock_threshold_ms;
52
53
54/* Function definitions. */
55
56void DRD_(mutex_set_trace)(const Bool trace_mutex)
57{
58   tl_assert(!! trace_mutex == trace_mutex);
59   s_trace_mutex = trace_mutex;
60}
61
62void DRD_(mutex_set_lock_threshold)(const UInt lock_threshold_ms)
63{
64   s_mutex_lock_threshold_ms = lock_threshold_ms;
65}
66
67static
68void DRD_(mutex_initialize)(struct mutex_info* const p,
69                            const Addr mutex, const MutexT mutex_type)
70{
71   tl_assert(mutex);
72   tl_assert(p->a1 == mutex);
73
74   p->cleanup             = (void(*)(DrdClientobj*))mutex_cleanup;
75   p->delete_thread
76      = (void(*)(DrdClientobj*, DrdThreadId))mutex_delete_thread;
77   p->mutex_type          = mutex_type;
78   p->recursion_count     = 0;
79   p->owner               = DRD_INVALID_THREADID;
80   p->last_locked_segment = 0;
81   p->acquiry_time_ms     = 0;
82   p->acquired_at         = 0;
83}
84
85/** Deallocate the memory that was allocated by mutex_initialize(). */
86static void mutex_cleanup(struct mutex_info* p)
87{
88   tl_assert(p);
89
90   if (s_trace_mutex)
91      DRD_(trace_msg)("[%d] mutex_destroy   %s 0x%lx rc %d owner %d",
92                      DRD_(thread_get_running_tid)(),
93                      DRD_(mutex_get_typename)(p), p->a1,
94                      p ? p->recursion_count : -1,
95                      p ? p->owner : DRD_INVALID_THREADID);
96
97   if (mutex_is_locked(p))
98   {
99      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
100                           p->a1, p->recursion_count, p->owner };
101      VG_(maybe_record_error)(VG_(get_running_tid)(),
102                              MutexErr,
103                              VG_(get_IP)(VG_(get_running_tid)()),
104                              "Destroying locked mutex",
105                              &MEI);
106   }
107
108   DRD_(sg_put)(p->last_locked_segment);
109   p->last_locked_segment = 0;
110}
111
112/** Report that address 'mutex' is not the address of a mutex object. */
113void DRD_(not_a_mutex)(const Addr mutex)
114{
115   MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
116                        mutex, -1, DRD_INVALID_THREADID };
117   VG_(maybe_record_error)(VG_(get_running_tid)(),
118                           MutexErr,
119                           VG_(get_IP)(VG_(get_running_tid)()),
120                           "Not a mutex",
121                           &MEI);
122}
123
124/**
125 * Report that address 'mutex' is not the address of a mutex object of the
126 * expected type.
127 */
128static void wrong_mutex_type(const Addr mutex)
129{
130   MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
131                        mutex, -1, DRD_INVALID_THREADID };
132   VG_(maybe_record_error)(VG_(get_running_tid)(),
133                           MutexErr,
134                           VG_(get_IP)(VG_(get_running_tid)()),
135                           "Mutex type mismatch",
136                           &MEI);
137}
138
139static
140struct mutex_info*
141DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
142{
143   struct mutex_info* p;
144
145   tl_assert(offsetof(DrdClientobj, mutex) == 0);
146   p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
147   if (p)
148   {
149      if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
150	 return p;
151      else
152      {
153	 wrong_mutex_type(mutex);
154	 return 0;
155      }
156   }
157
158   if (DRD_(clientobj_present)(mutex, mutex + 1))
159   {
160      DRD_(not_a_mutex)(mutex);
161      return 0;
162   }
163
164   p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex);
165   DRD_(mutex_initialize)(p, mutex, mutex_type);
166   return p;
167}
168
169struct mutex_info* DRD_(mutex_get)(const Addr mutex)
170{
171   tl_assert(offsetof(DrdClientobj, mutex) == 0);
172   return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
173}
174
175/** Called before pthread_mutex_init(). */
176struct mutex_info*
177DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type)
178{
179   struct mutex_info* p;
180
181   if (s_trace_mutex)
182      DRD_(trace_msg)("[%d] mutex_init      %s 0x%lx",
183                      DRD_(thread_get_running_tid)(),
184                      DRD_(mutex_type_name)(mutex_type),
185                      mutex);
186
187   if (mutex_type == mutex_type_invalid_mutex)
188   {
189      DRD_(not_a_mutex)(mutex);
190      return 0;
191   }
192
193   p = DRD_(mutex_get)(mutex);
194   if (p)
195   {
196      const ThreadId vg_tid = VG_(get_running_tid)();
197      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
198                           p->a1, p->recursion_count, p->owner };
199      VG_(maybe_record_error)(vg_tid,
200                              MutexErr,
201                              VG_(get_IP)(vg_tid),
202                              "Mutex reinitialization",
203                              &MEI);
204      p->mutex_type = mutex_type;
205      return p;
206   }
207   p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
208
209   return p;
210}
211
212/** Called after pthread_mutex_destroy(). */
213void DRD_(mutex_post_destroy)(const Addr mutex)
214{
215   struct mutex_info* p;
216
217   p = DRD_(mutex_get)(mutex);
218   if (p == 0)
219   {
220      DRD_(not_a_mutex)(mutex);
221      return;
222   }
223
224   DRD_(clientobj_remove)(mutex, ClientMutex);
225}
226
227/**
228 * Called before pthread_mutex_lock() is invoked. If a data structure for the
229 * client-side object was not yet created, do this now. Also check whether an
230 * attempt is made to lock recursively a synchronization object that must not
231 * be locked recursively.
232 */
233void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
234                          const Bool trylock)
235{
236   struct mutex_info* p;
237
238   p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
239   if (p && mutex_type == mutex_type_unknown)
240      mutex_type = p->mutex_type;
241
242   if (s_trace_mutex)
243      DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d",
244                      DRD_(thread_get_running_tid)(),
245                      trylock ? "pre_mutex_lock " : "mutex_trylock  ",
246                      p ? DRD_(mutex_get_typename)(p) : "(?)",
247                      mutex, p ? p->recursion_count : -1,
248                      p ? p->owner : DRD_INVALID_THREADID);
249
250   if (p == 0)
251   {
252      DRD_(not_a_mutex)(mutex);
253      return;
254   }
255
256   tl_assert(p);
257
258   if (mutex_type == mutex_type_invalid_mutex)
259   {
260      DRD_(not_a_mutex)(mutex);
261      return;
262   }
263
264   if (! trylock
265       && p->owner == DRD_(thread_get_running_tid)()
266       && p->recursion_count >= 1
267       && mutex_type != mutex_type_recursive_mutex)
268   {
269      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
270                           p->a1, p->recursion_count, p->owner };
271      VG_(maybe_record_error)(VG_(get_running_tid)(),
272                              MutexErr,
273                              VG_(get_IP)(VG_(get_running_tid)()),
274                              "Recursive locking not allowed",
275                              &MEI);
276   }
277}
278
279/**
280 * Update mutex_info state when locking the pthread_mutex_t mutex.
281 * Note: this function must be called after pthread_mutex_lock() has been
282 * called, or a race condition is triggered !
283 */
284void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock,
285                           const Bool post_cond_wait)
286{
287   const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
288   struct mutex_info* p;
289
290   p = DRD_(mutex_get)(mutex);
291
292   if (s_trace_mutex)
293      DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d%s",
294                      drd_tid,
295                      post_cond_wait ? "cond_post_wait " : "post_mutex_lock",
296                      p ? DRD_(mutex_get_typename)(p) : "(?)",
297                      mutex, p ? p->recursion_count : 0,
298                      p ? p->owner : VG_INVALID_THREADID,
299                      took_lock ? "" : " (locking failed)");
300
301   if (! p || ! took_lock)
302      return;
303
304   if (p->recursion_count == 0) {
305      if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID)
306      {
307         tl_assert(p->last_locked_segment);
308
309         DRD_(thread_new_segment_and_combine_vc)(drd_tid,
310                                                 p->last_locked_segment);
311      }
312      else
313         DRD_(thread_new_segment)(drd_tid);
314
315      s_mutex_segment_creation_count++;
316
317      p->owner           = drd_tid;
318      p->acquiry_time_ms = VG_(read_millisecond_timer)();
319      p->acquired_at     = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
320      s_mutex_lock_count++;
321   } else if (p->owner != drd_tid) {
322      const ThreadId vg_tid = VG_(get_running_tid)();
323      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
324                           p->a1, p->recursion_count, p->owner };
325      VG_(maybe_record_error)(vg_tid,
326                              MutexErr,
327                              VG_(get_IP)(vg_tid),
328                              "The impossible happened: mutex is locked"
329                              " simultaneously by two threads",
330                              &MEI);
331      p->owner = drd_tid;
332   }
333   p->recursion_count++;
334}
335
336/**
337 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
338 *
339 * @param[in] mutex      Address of the client mutex.
340 * @param[in] mutex_type Mutex type.
341 *
342 * @return New value of the mutex recursion count.
343 *
344 * @note This function must be called before pthread_mutex_unlock() is called,
345 *       or a race condition is triggered !
346 */
347void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type)
348{
349   const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
350   const ThreadId vg_tid = VG_(get_running_tid)();
351   struct mutex_info* p;
352
353   p = DRD_(mutex_get)(mutex);
354   if (p && mutex_type == mutex_type_unknown)
355      mutex_type = p->mutex_type;
356
357   if (s_trace_mutex) {
358      DRD_(trace_msg)("[%d] mutex_unlock    %s 0x%lx rc %d",
359                      drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)",
360                      mutex, p ? p->recursion_count : 0);
361   }
362
363   if (p == 0 || mutex_type == mutex_type_invalid_mutex)
364   {
365      DRD_(not_a_mutex)(mutex);
366      return;
367   }
368
369   if (p->owner == DRD_INVALID_THREADID)
370   {
371      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
372                           p->a1, p->recursion_count, p->owner };
373      VG_(maybe_record_error)(vg_tid,
374                              MutexErr,
375                              VG_(get_IP)(vg_tid),
376                              "Mutex not locked",
377                              &MEI);
378      return;
379   }
380
381   tl_assert(p);
382   if (p->mutex_type != mutex_type) {
383      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
384                           p->a1, p->recursion_count, p->owner };
385      VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid),
386                              "Mutex type changed", &MEI);
387   }
388   tl_assert(p->mutex_type == mutex_type);
389   tl_assert(p->owner != DRD_INVALID_THREADID);
390
391   if (p->owner != drd_tid || p->recursion_count <= 0)
392   {
393      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
394                           p->a1, p->recursion_count, p->owner };
395      VG_(maybe_record_error)(vg_tid,
396                              MutexErr,
397                              VG_(get_IP)(vg_tid),
398                              "Mutex not locked by calling thread",
399                              &MEI);
400      return;
401   }
402   tl_assert(p->recursion_count > 0);
403   p->recursion_count--;
404   tl_assert(p->recursion_count >= 0);
405
406   if (p->recursion_count == 0)
407   {
408      if (s_mutex_lock_threshold_ms > 0)
409      {
410         Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
411         if (held > s_mutex_lock_threshold_ms)
412         {
413            HoldtimeErrInfo HEI
414               = { DRD_(thread_get_running_tid)(),
415                   mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
416            VG_(maybe_record_error)(vg_tid,
417                                    HoldtimeErr,
418                                    VG_(get_IP)(vg_tid),
419                                    "mutex",
420                                    &HEI);
421         }
422      }
423
424      /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
425      /* current vector clock of the thread such that it is available when  */
426      /* this mutex is locked again.                                        */
427
428      DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
429      DRD_(thread_new_segment)(drd_tid);
430      p->acquired_at = 0;
431      s_mutex_segment_creation_count++;
432   }
433}
434
435void DRD_(spinlock_init_or_unlock)(const Addr spinlock)
436{
437   struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock);
438   if (mutex_p)
439   {
440      DRD_(mutex_unlock)(spinlock, mutex_type_spinlock);
441   }
442   else
443   {
444      DRD_(mutex_init)(spinlock, mutex_type_spinlock);
445   }
446}
447
448const HChar* DRD_(mutex_get_typename)(struct mutex_info* const p)
449{
450   tl_assert(p);
451
452   return DRD_(mutex_type_name)(p->mutex_type);
453}
454
455const HChar* DRD_(mutex_type_name)(const MutexT mt)
456{
457   switch (mt)
458   {
459   case mutex_type_unknown:
460      return "mutex";
461   case mutex_type_invalid_mutex:
462      return "invalid mutex";
463   case mutex_type_recursive_mutex:
464      return "recursive mutex";
465   case mutex_type_errorcheck_mutex:
466      return "error checking mutex";
467   case mutex_type_default_mutex:
468      return "mutex";
469   case mutex_type_spinlock:
470      return "spinlock";
471   }
472   tl_assert(0);
473   return "?";
474}
475
476/** Return true if the specified mutex is locked by any thread. */
477static Bool mutex_is_locked(struct mutex_info* const p)
478{
479   tl_assert(p);
480   return (p->recursion_count > 0);
481}
482
483Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid)
484{
485   struct mutex_info* const p = DRD_(mutex_get)(mutex);
486   if (p)
487   {
488      return (p->recursion_count > 0 && p->owner == tid);
489   }
490   return False;
491}
492
493int DRD_(mutex_get_recursion_count)(const Addr mutex)
494{
495   struct mutex_info* const p = DRD_(mutex_get)(mutex);
496   tl_assert(p);
497   return p->recursion_count;
498}
499
500/**
501 * Call this function when thread tid stops to exist, such that the
502 * "last owner" field can be cleared if it still refers to that thread.
503 */
504static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid)
505{
506   tl_assert(p);
507
508   if (p->owner == tid && p->recursion_count > 0)
509   {
510      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
511                           p->a1, p->recursion_count, p->owner };
512      VG_(maybe_record_error)(VG_(get_running_tid)(),
513                              MutexErr,
514                              VG_(get_IP)(VG_(get_running_tid)()),
515                              "Mutex still locked at thread exit",
516                              &MEI);
517      p->owner = VG_INVALID_THREADID;
518   }
519}
520
521ULong DRD_(get_mutex_lock_count)(void)
522{
523   return s_mutex_lock_count;
524}
525
526ULong DRD_(get_mutex_segment_creation_count)(void)
527{
528   return s_mutex_segment_creation_count;
529}
530