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->ignore_ordering     = False;
80   p->owner               = DRD_INVALID_THREADID;
81   p->last_locked_segment = 0;
82   p->acquiry_time_ms     = 0;
83   p->acquired_at         = 0;
84}
85
86void DRD_(mutex_ignore_ordering)(const Addr mutex)
87{
88   struct mutex_info* p = DRD_(mutex_get)(mutex);
89
90   if (s_trace_mutex)
91      DRD_(trace_msg)("[%d] mutex_ignore_ordering %s 0x%lx",
92                      DRD_(thread_get_running_tid)(),
93                      p ? DRD_(mutex_type_name)(p->mutex_type) : "(?)",
94                      mutex);
95
96   if (p) {
97      p->ignore_ordering = True;
98   } else {
99      DRD_(not_a_mutex)(mutex);
100   }
101}
102
103/** Deallocate the memory that was allocated by mutex_initialize(). */
104static void mutex_cleanup(struct mutex_info* p)
105{
106   tl_assert(p);
107
108   if (s_trace_mutex)
109      DRD_(trace_msg)("[%d] mutex_destroy   %s 0x%lx rc %d owner %d",
110                      DRD_(thread_get_running_tid)(),
111                      DRD_(mutex_get_typename)(p), p->a1,
112                      p ? p->recursion_count : -1,
113                      p ? p->owner : DRD_INVALID_THREADID);
114
115   if (mutex_is_locked(p))
116   {
117      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
118                           p->a1, p->recursion_count, p->owner };
119      VG_(maybe_record_error)(VG_(get_running_tid)(),
120                              MutexErr,
121                              VG_(get_IP)(VG_(get_running_tid)()),
122                              "Destroying locked mutex",
123                              &MEI);
124   }
125
126   DRD_(sg_put)(p->last_locked_segment);
127   p->last_locked_segment = 0;
128}
129
130/** Report that address 'mutex' is not the address of a mutex object. */
131void DRD_(not_a_mutex)(const Addr mutex)
132{
133   MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
134                        mutex, -1, DRD_INVALID_THREADID };
135   VG_(maybe_record_error)(VG_(get_running_tid)(),
136                           MutexErr,
137                           VG_(get_IP)(VG_(get_running_tid)()),
138                           "Not a mutex",
139                           &MEI);
140}
141
142/**
143 * Report that address 'mutex' is not the address of a mutex object of the
144 * expected type.
145 */
146static void wrong_mutex_type(const Addr mutex)
147{
148   MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
149                        mutex, -1, DRD_INVALID_THREADID };
150   VG_(maybe_record_error)(VG_(get_running_tid)(),
151                           MutexErr,
152                           VG_(get_IP)(VG_(get_running_tid)()),
153                           "Mutex type mismatch",
154                           &MEI);
155}
156
157static
158struct mutex_info*
159DRD_(mutex_get_or_allocate)(const Addr mutex, const MutexT mutex_type)
160{
161   struct mutex_info* p;
162
163   tl_assert(offsetof(DrdClientobj, mutex) == 0);
164   p = &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
165   if (p)
166   {
167      if (mutex_type == mutex_type_unknown || p->mutex_type == mutex_type)
168	 return p;
169      else
170      {
171	 wrong_mutex_type(mutex);
172	 return 0;
173      }
174   }
175
176   if (DRD_(clientobj_present)(mutex, mutex + 1))
177   {
178      DRD_(not_a_mutex)(mutex);
179      return 0;
180   }
181
182   p = &(DRD_(clientobj_add)(mutex, ClientMutex)->mutex);
183   DRD_(mutex_initialize)(p, mutex, mutex_type);
184   return p;
185}
186
187struct mutex_info* DRD_(mutex_get)(const Addr mutex)
188{
189   tl_assert(offsetof(DrdClientobj, mutex) == 0);
190   return &(DRD_(clientobj_get)(mutex, ClientMutex)->mutex);
191}
192
193/** Called before pthread_mutex_init(). */
194struct mutex_info*
195DRD_(mutex_init)(const Addr mutex, const MutexT mutex_type)
196{
197   struct mutex_info* p;
198
199   if (s_trace_mutex)
200      DRD_(trace_msg)("[%d] mutex_init      %s 0x%lx",
201                      DRD_(thread_get_running_tid)(),
202                      DRD_(mutex_type_name)(mutex_type),
203                      mutex);
204
205   if (mutex_type == mutex_type_invalid_mutex)
206   {
207      DRD_(not_a_mutex)(mutex);
208      return 0;
209   }
210
211   p = DRD_(mutex_get)(mutex);
212   if (p)
213   {
214      const ThreadId vg_tid = VG_(get_running_tid)();
215      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
216                           p->a1, p->recursion_count, p->owner };
217      VG_(maybe_record_error)(vg_tid,
218                              MutexErr,
219                              VG_(get_IP)(vg_tid),
220                              "Mutex reinitialization",
221                              &MEI);
222      p->mutex_type = mutex_type;
223      return p;
224   }
225   p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
226
227   return p;
228}
229
230/** Called after pthread_mutex_destroy(). */
231void DRD_(mutex_post_destroy)(const Addr mutex)
232{
233   struct mutex_info* p;
234
235   p = DRD_(mutex_get)(mutex);
236   if (p == 0)
237   {
238      DRD_(not_a_mutex)(mutex);
239      return;
240   }
241
242   DRD_(clientobj_remove)(mutex, ClientMutex);
243}
244
245/**
246 * Called before pthread_mutex_lock() is invoked. If a data structure for the
247 * client-side object was not yet created, do this now. Also check whether an
248 * attempt is made to lock recursively a synchronization object that must not
249 * be locked recursively.
250 */
251void DRD_(mutex_pre_lock)(const Addr mutex, MutexT mutex_type,
252                          const Bool trylock)
253{
254   struct mutex_info* p;
255
256   p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
257   if (p && mutex_type == mutex_type_unknown)
258      mutex_type = p->mutex_type;
259
260   if (s_trace_mutex)
261      DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d",
262                      DRD_(thread_get_running_tid)(),
263                      trylock ? "pre_mutex_lock " : "mutex_trylock  ",
264                      p ? DRD_(mutex_get_typename)(p) : "(?)",
265                      mutex, p ? p->recursion_count : -1,
266                      p ? p->owner : DRD_INVALID_THREADID);
267
268   if (p == 0)
269   {
270      DRD_(not_a_mutex)(mutex);
271      return;
272   }
273
274   tl_assert(p);
275
276   if (mutex_type == mutex_type_invalid_mutex)
277   {
278      DRD_(not_a_mutex)(mutex);
279      return;
280   }
281
282   if (! trylock
283       && p->owner == DRD_(thread_get_running_tid)()
284       && p->recursion_count >= 1
285       && mutex_type != mutex_type_recursive_mutex)
286   {
287      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
288                           p->a1, p->recursion_count, p->owner };
289      VG_(maybe_record_error)(VG_(get_running_tid)(),
290                              MutexErr,
291                              VG_(get_IP)(VG_(get_running_tid)()),
292                              "Recursive locking not allowed",
293                              &MEI);
294   }
295}
296
297/**
298 * Update mutex_info state when locking the pthread_mutex_t mutex.
299 * Note: this function must be called after pthread_mutex_lock() has been
300 * called, or a race condition is triggered !
301 */
302void DRD_(mutex_post_lock)(const Addr mutex, const Bool took_lock,
303                           const Bool post_cond_wait)
304{
305   const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
306   struct mutex_info* p;
307
308   p = DRD_(mutex_get)(mutex);
309
310   if (s_trace_mutex)
311      DRD_(trace_msg)("[%d] %s %s 0x%lx rc %d owner %d%s",
312                      drd_tid,
313                      post_cond_wait ? "cond_post_wait " : "post_mutex_lock",
314                      p ? DRD_(mutex_get_typename)(p) : "(?)",
315                      mutex, p ? p->recursion_count : 0,
316                      p ? p->owner : VG_INVALID_THREADID,
317                      took_lock ? "" : " (locking failed)");
318
319   if (! p || ! took_lock)
320      return;
321
322   if (p->recursion_count == 0) {
323      if (!p->ignore_ordering) {
324         if (p->owner != drd_tid && p->owner != DRD_INVALID_THREADID) {
325            tl_assert(p->last_locked_segment);
326
327            DRD_(thread_new_segment_and_combine_vc)(drd_tid,
328                                                    p->last_locked_segment);
329         } else {
330            DRD_(thread_new_segment)(drd_tid);
331         }
332
333         s_mutex_segment_creation_count++;
334      }
335
336      p->owner           = drd_tid;
337      p->acquiry_time_ms = VG_(read_millisecond_timer)();
338      p->acquired_at     = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
339      s_mutex_lock_count++;
340   } else if (p->owner != drd_tid) {
341      const ThreadId vg_tid = VG_(get_running_tid)();
342      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
343                           p->a1, p->recursion_count, p->owner };
344      VG_(maybe_record_error)(vg_tid,
345                              MutexErr,
346                              VG_(get_IP)(vg_tid),
347                              "The impossible happened: mutex is locked"
348                              " simultaneously by two threads",
349                              &MEI);
350      p->owner = drd_tid;
351   }
352   p->recursion_count++;
353}
354
355/**
356 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
357 *
358 * @param[in] mutex      Address of the client mutex.
359 * @param[in] mutex_type Mutex type.
360 *
361 * @return New value of the mutex recursion count.
362 *
363 * @note This function must be called before pthread_mutex_unlock() is called,
364 *       or a race condition is triggered !
365 */
366void DRD_(mutex_unlock)(const Addr mutex, MutexT mutex_type)
367{
368   const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
369   const ThreadId vg_tid = VG_(get_running_tid)();
370   struct mutex_info* p;
371
372   p = DRD_(mutex_get)(mutex);
373   if (p && mutex_type == mutex_type_unknown)
374      mutex_type = p->mutex_type;
375
376   if (s_trace_mutex) {
377      DRD_(trace_msg)("[%d] mutex_unlock    %s 0x%lx rc %d",
378                      drd_tid, p ? DRD_(mutex_get_typename)(p) : "(?)",
379                      mutex, p ? p->recursion_count : 0);
380   }
381
382   if (p == 0 || mutex_type == mutex_type_invalid_mutex)
383   {
384      DRD_(not_a_mutex)(mutex);
385      return;
386   }
387
388   if (p->owner == DRD_INVALID_THREADID)
389   {
390      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
391                           p->a1, p->recursion_count, p->owner };
392      VG_(maybe_record_error)(vg_tid,
393                              MutexErr,
394                              VG_(get_IP)(vg_tid),
395                              "Mutex not locked",
396                              &MEI);
397      return;
398   }
399
400   tl_assert(p);
401   if (p->mutex_type != mutex_type) {
402      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
403                           p->a1, p->recursion_count, p->owner };
404      VG_(maybe_record_error)(vg_tid, MutexErr, VG_(get_IP)(vg_tid),
405                              "Mutex type changed", &MEI);
406   }
407   tl_assert(p->mutex_type == mutex_type);
408   tl_assert(p->owner != DRD_INVALID_THREADID);
409
410   if (p->owner != drd_tid || p->recursion_count <= 0)
411   {
412      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
413                           p->a1, p->recursion_count, p->owner };
414      VG_(maybe_record_error)(vg_tid,
415                              MutexErr,
416                              VG_(get_IP)(vg_tid),
417                              "Mutex not locked by calling thread",
418                              &MEI);
419      return;
420   }
421   tl_assert(p->recursion_count > 0);
422   p->recursion_count--;
423   tl_assert(p->recursion_count >= 0);
424
425   if (p->recursion_count == 0)
426   {
427      if (s_mutex_lock_threshold_ms > 0)
428      {
429         Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
430         if (held > s_mutex_lock_threshold_ms)
431         {
432            HoldtimeErrInfo HEI
433               = { DRD_(thread_get_running_tid)(),
434                   mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
435            VG_(maybe_record_error)(vg_tid,
436                                    HoldtimeErr,
437                                    VG_(get_IP)(vg_tid),
438                                    "mutex",
439                                    &HEI);
440         }
441      }
442
443      /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
444      /* current vector clock of the thread such that it is available when  */
445      /* this mutex is locked again.                                        */
446
447      DRD_(thread_get_latest_segment)(&p->last_locked_segment, drd_tid);
448      if (!p->ignore_ordering)
449         DRD_(thread_new_segment)(drd_tid);
450      p->acquired_at = 0;
451      s_mutex_segment_creation_count++;
452   }
453}
454
455void DRD_(spinlock_init_or_unlock)(const Addr spinlock)
456{
457   struct mutex_info* mutex_p = DRD_(mutex_get)(spinlock);
458   if (mutex_p)
459   {
460      DRD_(mutex_unlock)(spinlock, mutex_type_spinlock);
461   }
462   else
463   {
464      DRD_(mutex_init)(spinlock, mutex_type_spinlock);
465   }
466}
467
468const HChar* DRD_(mutex_get_typename)(struct mutex_info* const p)
469{
470   tl_assert(p);
471
472   return DRD_(mutex_type_name)(p->mutex_type);
473}
474
475const HChar* DRD_(mutex_type_name)(const MutexT mt)
476{
477   switch (mt)
478   {
479   case mutex_type_unknown:
480      return "mutex";
481   case mutex_type_invalid_mutex:
482      return "invalid mutex";
483   case mutex_type_recursive_mutex:
484      return "recursive mutex";
485   case mutex_type_errorcheck_mutex:
486      return "error checking mutex";
487   case mutex_type_default_mutex:
488      return "mutex";
489   case mutex_type_spinlock:
490      return "spinlock";
491   case mutex_type_cxa_guard:
492      return "cxa_guard";
493   }
494   tl_assert(0);
495   return "?";
496}
497
498/** Return true if the specified mutex is locked by any thread. */
499static Bool mutex_is_locked(struct mutex_info* const p)
500{
501   tl_assert(p);
502   return (p->recursion_count > 0);
503}
504
505Bool DRD_(mutex_is_locked_by)(const Addr mutex, const DrdThreadId tid)
506{
507   struct mutex_info* const p = DRD_(mutex_get)(mutex);
508   if (p)
509   {
510      return (p->recursion_count > 0 && p->owner == tid);
511   }
512   return False;
513}
514
515int DRD_(mutex_get_recursion_count)(const Addr mutex)
516{
517   struct mutex_info* const p = DRD_(mutex_get)(mutex);
518   tl_assert(p);
519   return p->recursion_count;
520}
521
522/**
523 * Call this function when thread tid stops to exist, such that the
524 * "last owner" field can be cleared if it still refers to that thread.
525 */
526static void mutex_delete_thread(struct mutex_info* p, const DrdThreadId tid)
527{
528   tl_assert(p);
529
530   if (p->owner == tid && p->recursion_count > 0)
531   {
532      MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
533                           p->a1, p->recursion_count, p->owner };
534      VG_(maybe_record_error)(VG_(get_running_tid)(),
535                              MutexErr,
536                              VG_(get_IP)(VG_(get_running_tid)()),
537                              "Mutex still locked at thread exit",
538                              &MEI);
539      p->owner = VG_INVALID_THREADID;
540   }
541}
542
543ULong DRD_(get_mutex_lock_count)(void)
544{
545   return s_mutex_lock_count;
546}
547
548ULong DRD_(get_mutex_segment_creation_count)(void)
549{
550   return s_mutex_segment_creation_count;
551}
552