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