blob: b9dfea49152e58d09d3baf702c42e57b5e06c5b8 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
sewardj85642922008-01-14 11:54:56 +00004 Copyright (C) 2006-2008 Bart Van Assche
sewardjaf44c822007-11-25 14:01:38 +00005 bart.vanassche@gmail.com
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_error.h"
27#include "drd_mutex.h"
28#include "drd_suppression.h"
sewardj721ad7b2007-11-30 08:30:29 +000029#include "priv_drd_clientreq.h"
sewardjaf44c822007-11-25 14:01:38 +000030#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
31#include "pub_tool_libcassert.h" // tl_assert()
32#include "pub_tool_libcprint.h" // VG_(printf)()
33#include "pub_tool_machine.h" // VG_(get_IP)()
34#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
35
36
37// Type definitions.
38
39struct mutex_info
40{
41 Addr mutex; // Pointer to client mutex.
42 SizeT size; // Size in bytes of client-side object.
sewardj721ad7b2007-11-30 08:30:29 +000043 MutexT mutex_type; // pthread_mutex_t or pthread_spinlock_t.
sewardjaf44c822007-11-25 14:01:38 +000044 int recursion_count; // 0 if free, >= 1 if locked.
45 DrdThreadId owner; // owner if locked, last owner if free.
46 VectorClock vc; // vector clock associated with last unlock.
47};
48
49
sewardj347eeba2008-01-21 14:19:07 +000050// Local functions.
51
52static void mutex_destroy(struct mutex_info* const p);
53
54
sewardjaf44c822007-11-25 14:01:38 +000055// Local variables.
56
57static Bool s_trace_mutex;
58static ULong s_mutex_lock_count;
59struct mutex_info s_mutex[256];
60
61
62// Function definitions.
63
64void mutex_set_trace(const Bool trace_mutex)
65{
66 tl_assert(!! trace_mutex == trace_mutex);
67 s_trace_mutex = trace_mutex;
68}
69
70static
71void mutex_initialize(struct mutex_info* const p,
72 const Addr mutex,
sewardj721ad7b2007-11-30 08:30:29 +000073 const SizeT size,
74 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +000075{
76 tl_assert(mutex != 0);
77 tl_assert(size > 0);
sewardj721ad7b2007-11-30 08:30:29 +000078 tl_assert(mutex_type == mutex_type_mutex
79 || mutex_type == mutex_type_spinlock);
sewardjaf44c822007-11-25 14:01:38 +000080
81 p->mutex = mutex;
82 p->size = size;
sewardj721ad7b2007-11-30 08:30:29 +000083 p->mutex_type = mutex_type;
sewardjaf44c822007-11-25 14:01:38 +000084 p->recursion_count = 0;
85 p->owner = DRD_INVALID_THREADID;
86 vc_init(&p->vc, 0, 0);
87}
88
89static
sewardj721ad7b2007-11-30 08:30:29 +000090struct mutex_info*
91mutex_get_or_allocate(const Addr mutex,
92 const SizeT size,
93 const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +000094{
95 int i;
sewardj721ad7b2007-11-30 08:30:29 +000096
97 tl_assert(mutex_type == mutex_type_mutex
98 || mutex_type == mutex_type_spinlock);
99
sewardjaf44c822007-11-25 14:01:38 +0000100 for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
sewardj721ad7b2007-11-30 08:30:29 +0000101 {
sewardjaf44c822007-11-25 14:01:38 +0000102 if (s_mutex[i].mutex == mutex)
sewardj721ad7b2007-11-30 08:30:29 +0000103 {
104 tl_assert(s_mutex[i].mutex_type == mutex_type);
105 tl_assert(s_mutex[i].size == size);
sewardjaf44c822007-11-25 14:01:38 +0000106 return &s_mutex[i];
sewardj721ad7b2007-11-30 08:30:29 +0000107 }
108 }
sewardjaf44c822007-11-25 14:01:38 +0000109 for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
110 {
111 if (s_mutex[i].mutex == 0)
112 {
sewardj721ad7b2007-11-30 08:30:29 +0000113 mutex_initialize(&s_mutex[i], mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000114 drd_start_suppression(mutex, mutex + size,
115 mutex_get_typename(&s_mutex[i]));
116 return &s_mutex[i];
117 }
118 }
119 tl_assert(0);
120 return 0;
121}
122
sewardj721ad7b2007-11-30 08:30:29 +0000123struct mutex_info*
124mutex_init(const Addr mutex, const SizeT size, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000125{
126 struct mutex_info* mutex_p;
127
sewardjaf44c822007-11-25 14:01:38 +0000128 if (s_trace_mutex)
129 {
130 const ThreadId vg_tid = VG_(get_running_tid)();
131 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
132 VG_(message)(Vg_DebugMsg,
133 "drd_post_mutex_init tid = %d/%d, %s 0x%lx",
134 vg_tid, drd_tid,
sewardj347eeba2008-01-21 14:19:07 +0000135 mutex_type_name(mutex_type),
sewardjaf44c822007-11-25 14:01:38 +0000136 mutex);
137 }
138
sewardj347eeba2008-01-21 14:19:07 +0000139 tl_assert(mutex_type == mutex_type_mutex
140 || mutex_type == mutex_type_spinlock);
141 mutex_p = mutex_get(mutex);
142 if (mutex_p)
143 {
144 const ThreadId vg_tid = VG_(get_running_tid)();
145 MutexErrInfo MEI
146 = { mutex_p->mutex, mutex_p->recursion_count, mutex_p->owner };
147 VG_(maybe_record_error)(vg_tid,
148 MutexErr,
149 VG_(get_IP)(vg_tid),
150 "Mutex reinitialization",
151 &MEI);
152 mutex_destroy(mutex_p);
153 }
154 mutex_p = mutex_get_or_allocate(mutex, size, mutex_type);
155
sewardjaf44c822007-11-25 14:01:38 +0000156 return mutex_p;
157}
158
sewardj347eeba2008-01-21 14:19:07 +0000159static void mutex_destroy(struct mutex_info* const p)
sewardjaf44c822007-11-25 14:01:38 +0000160{
161 if (s_trace_mutex)
162 {
163 const ThreadId vg_tid = VG_(get_running_tid)();
164 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
165 VG_(message)(Vg_DebugMsg,
166 "drd_pre_mutex_destroy tid = %d/%d, %s 0x%lx",
167 vg_tid, drd_tid,
168 mutex_get_typename(p),
169 p->mutex);
170 }
171
172 drd_finish_suppression(p->mutex, p->mutex + p->size);
173
174 vc_cleanup(&p->vc);
175 p->mutex = 0;
176}
177
sewardj347eeba2008-01-21 14:19:07 +0000178void mutex_pre_destroy(struct mutex_info* const p)
179{
180 return mutex_destroy(p);
181}
182
183void mutex_post_destroy(const Addr mutex)
184{
185 struct mutex_info* p;
186
187 p = mutex_get(mutex);
188 tl_assert(p);
189 if (p)
190 {
191 if (mutex_get_recursion_count(mutex) > 0)
192 {
193 const ThreadId vg_tid = VG_(get_running_tid)();
194 MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
195 VG_(maybe_record_error)(vg_tid,
196 MutexErr,
197 VG_(get_IP)(vg_tid),
198 "Destroying locked mutex",
199 &MEI);
200 }
201 mutex_pre_destroy(p);
202 }
203}
204
sewardjaf44c822007-11-25 14:01:38 +0000205struct mutex_info* mutex_get(const Addr mutex)
206{
207 int i;
208 for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
209 if (s_mutex[i].mutex == mutex)
210 return &s_mutex[i];
211 return 0;
212}
213
214/**
215 * Update mutex_info state when locking the pthread_mutex_t mutex.
216 * Note: this function must be called after pthread_mutex_lock() has been
217 * called, or a race condition is triggered !
218 */
sewardj721ad7b2007-11-30 08:30:29 +0000219int mutex_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000220{
221 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(VG_(get_running_tid)());
sewardj721ad7b2007-11-30 08:30:29 +0000222 struct mutex_info* const p = mutex_get_or_allocate(mutex, size, mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000223 const DrdThreadId last_owner = p->owner;
224
225 if (s_trace_mutex)
226 {
227 const ThreadId tid = DrdThreadIdToVgThreadId(drd_tid);
228 VG_(message)(Vg_DebugMsg,
229 "drd_post_mutex_lock tid = %d/%d, %s 0x%lx rc %d owner %d",
230 tid,
231 drd_tid,
232 mutex_get_typename(p),
233 mutex,
234 p ? p->recursion_count : 0,
235 p ? p->owner : VG_INVALID_THREADID);
236 }
237
sewardj721ad7b2007-11-30 08:30:29 +0000238 tl_assert(mutex_type == mutex_type_mutex
239 || mutex_type == mutex_type_spinlock);
240 tl_assert(p->mutex_type == mutex_type);
241 tl_assert(p->size == size);
242
243 if (p->recursion_count >= 1 && mutex_type == mutex_type_spinlock)
sewardjaf44c822007-11-25 14:01:38 +0000244 {
245 // TO DO: tell the user in a more friendly way that it is not allowed to
246 // lock spinlocks recursively.
247 tl_assert(0);
248 }
249
250 if (p->recursion_count == 0)
251 {
252 p->owner = drd_tid;
253 s_mutex_lock_count++;
254 }
255 else if (p->owner != drd_tid)
256 {
257 VG_(message)(Vg_DebugMsg,
258 "The impossible happened: mutex 0x%lx is locked"
259 " simultaneously by two threads (recursion count %d,"
260 " owners %d and %d) !",
261 p->mutex, p->recursion_count, p->owner, drd_tid);
sewardj347eeba2008-01-21 14:19:07 +0000262 p->owner = drd_tid;
sewardjaf44c822007-11-25 14:01:38 +0000263 }
264 p->recursion_count++;
265
266 if (p->recursion_count == 1)
267 {
268 if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
269 thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
270 thread_new_segment(drd_tid);
271 }
272
273 return p->recursion_count;
274}
275
276/**
277 * Update mutex_info state when unlocking the pthread_mutex_t mutex.
278 * Note: this function must be called before pthread_mutex_unlock() is called,
279 * or a race condition is triggered !
280 * @param mutex Pointer to pthread_mutex_t data structure in the client space.
281 * @param tid ThreadId of the thread calling pthread_mutex_unlock().
282 * @param vc Pointer to the current vector clock of thread tid.
283 */
sewardj721ad7b2007-11-30 08:30:29 +0000284int mutex_unlock(const Addr mutex, const MutexT mutex_type)
sewardjaf44c822007-11-25 14:01:38 +0000285{
286 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(VG_(get_running_tid)());
287 const ThreadId vg_tid = DrdThreadIdToVgThreadId(drd_tid);
288 const VectorClock* const vc = thread_get_vc(drd_tid);
289 struct mutex_info* const p = mutex_get(mutex);
290
291 if (s_trace_mutex)
292 {
293 VG_(message)(Vg_DebugMsg,
294 "drd_pre_mutex_unlock tid = %d/%d, %s 0x%lx rc %d",
295 vg_tid, drd_tid,
296 mutex_get_typename(p),
297 mutex,
298 p->recursion_count,
299 p->owner);
300 }
301
302 tl_assert(p);
sewardj721ad7b2007-11-30 08:30:29 +0000303 tl_assert(p->mutex_type == mutex_type);
sewardjaf44c822007-11-25 14:01:38 +0000304 tl_assert(p->owner != DRD_INVALID_THREADID);
sewardj721ad7b2007-11-30 08:30:29 +0000305 tl_assert(mutex_type == mutex_type_mutex
306 || mutex_type == mutex_type_spinlock);
307
sewardjaf44c822007-11-25 14:01:38 +0000308 if (p->owner != drd_tid)
309 {
310 MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
311 VG_(maybe_record_error)(vg_tid,
312 MutexErr,
313 VG_(get_IP)(vg_tid),
314 "Mutex not unlocked by owner thread",
315 &MEI);
316 }
317 p->recursion_count--;
sewardj347eeba2008-01-21 14:19:07 +0000318 if (p->recursion_count < 0)
319 {
320 MutexErrInfo MEI
321 = { p->mutex, p->recursion_count, p->owner };
322 VG_(maybe_record_error)(vg_tid,
323 MutexErr,
324 VG_(get_IP)(vg_tid),
325 "Attempt to unlock a mutex that is not locked",
326 &MEI);
327 p->recursion_count = 0;
328 }
329
sewardjaf44c822007-11-25 14:01:38 +0000330 if (p->recursion_count == 0)
331 {
332 /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
333 /* current vector clock of the thread such that it is available when */
334 /* this mutex is locked again. */
bart301c3112008-02-24 18:22:37 +0000335 vc_assign(&p->vc, vc);
sewardjaf44c822007-11-25 14:01:38 +0000336
337 thread_new_segment(drd_tid);
338 }
339 return p->recursion_count;
340}
341
342const char* mutex_get_typename(struct mutex_info* const p)
343{
344 tl_assert(p);
sewardj721ad7b2007-11-30 08:30:29 +0000345
sewardj347eeba2008-01-21 14:19:07 +0000346 return mutex_type_name(p->mutex_type);
347}
348
349const char* mutex_type_name(const MutexT mt)
350{
351 switch (mt)
sewardjaf44c822007-11-25 14:01:38 +0000352 {
sewardj721ad7b2007-11-30 08:30:29 +0000353 case mutex_type_mutex:
sewardjaf44c822007-11-25 14:01:38 +0000354 return "mutex";
sewardj721ad7b2007-11-30 08:30:29 +0000355 case mutex_type_spinlock:
sewardjaf44c822007-11-25 14:01:38 +0000356 return "spinlock";
357 default:
358 tl_assert(0);
359 }
360 return "?";
361}
362
363Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
364{
365 struct mutex_info* const p = mutex_get(mutex);
366 tl_assert(p);
367 if (p)
368 {
369 return (p->recursion_count > 0 && p->owner == tid);
370 }
371 return False;
372}
373
374const VectorClock* mutex_get_last_vc(const Addr mutex)
375{
376 struct mutex_info* const p = mutex_get(mutex);
377 return p ? &p->vc : 0;
378}
379
380int mutex_get_recursion_count(const Addr mutex)
381{
382 struct mutex_info* const p = mutex_get(mutex);
383 tl_assert(p);
384 return p->recursion_count;
385}
386
387/**
bart301c3112008-02-24 18:22:37 +0000388 * Call this function when thread tid stops to exist, such that the
sewardjaf44c822007-11-25 14:01:38 +0000389 * "last owner" field can be cleared if it still refers to that thread.
390 * TO DO: print an error message if a thread exits while it still has some
391 * mutexes locked.
392 */
bart301c3112008-02-24 18:22:37 +0000393void mutex_thread_delete(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000394{
395 int i;
396 for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
397 {
398 struct mutex_info* const p = &s_mutex[i];
bart301c3112008-02-24 18:22:37 +0000399 if (p->mutex && p->owner == tid)
sewardjaf44c822007-11-25 14:01:38 +0000400 {
401 p->owner = VG_INVALID_THREADID;
402 }
403 }
404}
405
406void mutex_stop_using_mem(const Addr a1, const Addr a2)
407{
408 unsigned i;
409 for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
410 {
411 if (a1 <= s_mutex[i].mutex && s_mutex[i].mutex < a2)
412 {
413 tl_assert(s_mutex[i].mutex + s_mutex[i].size <= a2);
414 mutex_destroy(&s_mutex[i]);
415 }
416 }
417}
418
419ULong get_mutex_lock_count(void)
420{
421 return s_mutex_lock_count;
422}
sewardj347eeba2008-01-21 14:19:07 +0000423
424
425/*
426 * Local variables:
427 * c-basic-offset: 3
428 * End:
429 */