blob: c8ab57018bd7dc6be2fc24ba64a4eb4385eac910 [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_segment.h"
28#include "drd_suppression.h"
29#include "drd_thread.h"
sewardjaf44c822007-11-25 14:01:38 +000030#include "pub_tool_basics.h" // Addr, SizeT
31#include "pub_tool_errormgr.h" // VG_(unique_error)()
32#include "pub_tool_libcassert.h" // tl_assert()
33#include "pub_tool_libcbase.h" // VG_(strlen)()
34#include "pub_tool_libcprint.h" // VG_(printf)()
35#include "pub_tool_machine.h"
36#include "pub_tool_mallocfree.h" // VG_(malloc)(), VG_(free)()
sewardj85642922008-01-14 11:54:56 +000037#include "pub_tool_options.h" // VG_(clo_backtrace_size)
sewardjaf44c822007-11-25 14:01:38 +000038#include "pub_tool_threadstate.h" // VG_(get_pthread_id)()
39
40
41// Defines.
42
43#define DRD_N_THREADS VG_N_THREADS
44
45
46// Type definitions.
47
48typedef struct
49{
50 Segment* first;
51 Segment* last;
52 ThreadId vg_threadid;
53 PThreadId pt_threadid;
54 Addr stack_min_min;
55 Addr stack_min;
56 Addr stack_startup;
57 Addr stack_max;
58 char name[32];
59 /// Indicates whether the Valgrind core knows about this thread.
60 Bool vg_thread_exists;
61 /// Indicates whether there is an associated POSIX thread ID.
62 Bool posix_thread_exists;
63 /// If true, indicates that there is a corresponding POSIX thread ID and
64 /// a corresponding OS thread that is detached.
65 Bool detached_posix_thread;
bart0268dfa2008-03-11 20:10:21 +000066 /// Wether recording of memory accesses is active.
67 Bool is_recording;
68 /// Nesting level of synchronization functions called by the client.
69 Int synchr_nesting;
sewardjaf44c822007-11-25 14:01:38 +000070} ThreadInfo;
71
72
73// Local functions.
74
75static void thread_append_segment(const DrdThreadId tid,
76 Segment* const sg);
77static void thread_update_danger_set(const DrdThreadId tid);
78
79
80// Local variables.
81
82static ULong s_context_switch_count;
83static ULong s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +000084static ULong s_update_danger_set_count;
85static ULong s_danger_set_bitmap_creation_count;
86static ULong s_danger_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000087static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
88static DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +000089static ThreadInfo s_threadinfo[DRD_N_THREADS];
90static struct bitmap* s_danger_set;
bart26f73e12008-02-24 18:37:08 +000091static Bool s_trace_context_switches = False;
92static Bool s_trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000093
94
95// Function definitions.
96
bart26f73e12008-02-24 18:37:08 +000097void thread_trace_context_switches(const Bool t)
98{
99 s_trace_context_switches = t;
100}
101
102void thread_trace_danger_set(const Bool t)
103{
104 s_trace_danger_set = t;
105}
106
sewardjaf44c822007-11-25 14:01:38 +0000107__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
108{
109 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
110 && ! (s_threadinfo[tid].vg_thread_exists == False
111 && s_threadinfo[tid].posix_thread_exists == False
112 && s_threadinfo[tid].detached_posix_thread == False));
113}
114
115/**
116 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
117 * Valgrind's ThreadId does not yet exist.
118 **/
119DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
120{
121 int i;
122
123 if (tid == VG_INVALID_THREADID)
124 return DRD_INVALID_THREADID;
125
126 for (i = 1; i < DRD_N_THREADS; i++)
127 {
128 if (s_threadinfo[i].vg_thread_exists == True
129 && s_threadinfo[i].vg_threadid == tid)
130 {
131 return i;
132 }
133 }
134
135 return DRD_INVALID_THREADID;
136}
137
138static
139DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
140{
141 int i;
142
143 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
144
145 for (i = 1; i < DRD_N_THREADS; i++)
146 {
147 if (s_threadinfo[i].vg_thread_exists == False
148 && s_threadinfo[i].posix_thread_exists == False
149 && s_threadinfo[i].detached_posix_thread == False)
150 {
151 s_threadinfo[i].vg_thread_exists = True;
152 s_threadinfo[i].vg_threadid = tid;
153 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
154 s_threadinfo[i].stack_min_min = 0;
155 s_threadinfo[i].stack_min = 0;
156 s_threadinfo[i].stack_startup = 0;
157 s_threadinfo[i].stack_max = 0;
158 VG_(snprintf)(s_threadinfo[i].name, sizeof(s_threadinfo[i].name),
159 "thread %d", tid);
160 s_threadinfo[i].name[sizeof(s_threadinfo[i].name) - 1] = 0;
bart0268dfa2008-03-11 20:10:21 +0000161 s_threadinfo[i].is_recording = True;
162 s_threadinfo[i].synchr_nesting = 0;
sewardjaf44c822007-11-25 14:01:38 +0000163 if (s_threadinfo[i].first != 0)
164 VG_(printf)("drd thread id = %d\n", i);
165 tl_assert(s_threadinfo[i].first == 0);
166 tl_assert(s_threadinfo[i].last == 0);
167 return i;
168 }
169 }
170
171 tl_assert(False);
172
173 return DRD_INVALID_THREADID;
174}
175
176DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
177{
178 int i;
179
180 tl_assert(tid != INVALID_POSIX_THREADID);
181
182 for (i = 1; i < DRD_N_THREADS; i++)
183 {
184 if (s_threadinfo[i].posix_thread_exists
185 && s_threadinfo[i].pt_threadid == tid)
186 {
187 return i;
188 }
189 }
190 return DRD_INVALID_THREADID;
191}
192
193ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
194{
195 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
196 return (s_threadinfo[tid].vg_thread_exists
197 ? s_threadinfo[tid].vg_threadid
198 : VG_INVALID_THREADID);
199}
200
bart26f73e12008-02-24 18:37:08 +0000201/** Sanity check of the doubly linked list of segments referenced by a
202 * ThreadInfo struct.
203 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000204 */
205static Bool sane_ThreadInfo(const ThreadInfo* const ti)
206{
207 Segment* p;
208 for (p = ti->first; p; p = p->next) {
209 if (p->next && p->next->prev != p)
210 return False;
211 if (p->next == 0 && p != ti->last)
212 return False;
213 }
214 for (p = ti->last; p; p = p->prev) {
215 if (p->prev && p->prev->next != p)
216 return False;
217 if (p->prev == 0 && p != ti->first)
218 return False;
219 }
220 return True;
221}
222
223DrdThreadId thread_pre_create(const DrdThreadId creator,
224 const ThreadId vg_created)
225{
226 DrdThreadId created;
227
228 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
229 created = VgThreadIdToNewDrdThreadId(vg_created);
230 tl_assert(0 <= created && created < DRD_N_THREADS
231 && created != DRD_INVALID_THREADID);
232
233 tl_assert(s_threadinfo[created].first == 0);
234 tl_assert(s_threadinfo[created].last == 0);
235 thread_append_segment(created, sg_new(creator, created));
236
237 return created;
238}
239
bart26f73e12008-02-24 18:37:08 +0000240/** Allocate the first segment for a thread. Call this just after
241 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000242 */
243DrdThreadId thread_post_create(const ThreadId vg_created)
244{
245 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
246
247 tl_assert(0 <= created && created < DRD_N_THREADS
248 && created != DRD_INVALID_THREADID);
249
250 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
251 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
252 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
253 s_threadinfo[created].stack_min_min = s_threadinfo[created].stack_max;
254 tl_assert(s_threadinfo[created].stack_max != 0);
255
256 return created;
257}
258
259/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
260/* and accesses this data structure from multiple threads without locking. */
261/* Any conflicting accesses in the range stack_startup..stack_max will be */
262/* ignored. */
263void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
264{
265#if 0
266 VG_(message)(Vg_DebugMsg, "thread_set_stack_startup: thread %d (%d)"
267 " stack 0x%x .. 0x%lx (size %d)",
268 s_threadinfo[tid].vg_threadid, tid,
269 stack_startup,
270 s_threadinfo[tid].stack_max,
271 s_threadinfo[tid].stack_max - stack_startup);
272#endif
273 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
274 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
275 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
276 s_threadinfo[tid].stack_startup = stack_startup;
277}
278
279Addr thread_get_stack_min(const DrdThreadId tid)
280{
281 tl_assert(0 <= tid && tid < DRD_N_THREADS
282 && tid != DRD_INVALID_THREADID);
283 return s_threadinfo[tid].stack_min;
284}
285
286void thread_set_stack_min(const DrdThreadId tid, const Addr stack_min)
287{
288#if 0
289 VG_(message)(Vg_DebugMsg, "thread %d (%d) stack_min = 0x%x"
290 " (size %d, max %d, delta %d)",
291 s_threadinfo[tid].vg_threadid, tid,
292 stack_min,
293 s_threadinfo[tid].stack_max - stack_min,
294 s_threadinfo[tid].stack_max - s_threadinfo[tid].stack_min_min,
295 s_threadinfo[tid].stack_min - stack_min);
296#endif
297 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
298 if (s_threadinfo[tid].stack_max)
299 {
300 s_threadinfo[tid].stack_min = stack_min;
301 if (stack_min < s_threadinfo[tid].stack_min_min)
302 {
303 s_threadinfo[tid].stack_min_min = stack_min;
304 }
305 tl_assert(s_threadinfo[tid].stack_min_min
306 <= s_threadinfo[tid].stack_min);
307 tl_assert(s_threadinfo[tid].stack_min < s_threadinfo[tid].stack_max);
308 }
309}
310
311DrdThreadId thread_lookup_stackaddr(const Addr a,
312 Addr* const stack_min,
313 Addr* const stack_max)
314{
315 unsigned i;
316 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
317 {
318 if (s_threadinfo[i].stack_min <= a && a <= s_threadinfo[i].stack_max)
319 {
320 *stack_min = s_threadinfo[i].stack_min;
321 *stack_max = s_threadinfo[i].stack_max;
322 return i;
323 }
324 }
325 return DRD_INVALID_THREADID;
326}
327
328/**
329 * Clean up thread-specific data structures. Call this just after
330 * pthread_join().
331 */
332void thread_delete(const DrdThreadId tid)
333{
334 Segment* sg;
335 Segment* sg_prev;
336
337 tl_assert(0 <= tid && tid < DRD_N_THREADS
338 && tid != DRD_INVALID_THREADID);
bart0268dfa2008-03-11 20:10:21 +0000339 tl_assert(s_threadinfo[tid].synchr_nesting == 0);
sewardjaf44c822007-11-25 14:01:38 +0000340 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
341 {
342 sg_prev = sg->prev;
343 sg_delete(sg);
344 }
345 s_threadinfo[tid].vg_thread_exists = False;
346 s_threadinfo[tid].posix_thread_exists = False;
347 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
348 s_threadinfo[tid].first = 0;
349 s_threadinfo[tid].last = 0;
350}
351
352/* Called after a thread performed its last memory access and before */
353/* thread_delete() is called. Note: thread_delete() is only called for */
354/* joinable threads, not for detached threads. */
355void thread_finished(const DrdThreadId tid)
356{
357 tl_assert(0 <= tid && tid < DRD_N_THREADS
358 && tid != DRD_INVALID_THREADID);
359
360 thread_stop_using_mem(s_threadinfo[tid].stack_min,
361 s_threadinfo[tid].stack_max);
362
363 s_threadinfo[tid].vg_thread_exists = False;
364
365 if (s_threadinfo[tid].detached_posix_thread)
366 {
367 /* Once a detached thread has finished, its stack is deallocated and */
368 /* should no longer be taken into account when computing the danger set*/
369 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
370
371 /* For a detached thread, calling pthread_exit() invalidates the */
372 /* POSIX thread ID associated with the detached thread. For joinable */
373 /* POSIX threads however, the POSIX thread ID remains live after the */
374 /* pthread_exit() call until pthread_join() is called. */
375 s_threadinfo[tid].posix_thread_exists = False;
376 }
377}
378
379void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
380{
381 tl_assert(0 <= tid && tid < DRD_N_THREADS
382 && tid != DRD_INVALID_THREADID);
383 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
384 tl_assert(ptid != INVALID_POSIX_THREADID);
385 s_threadinfo[tid].posix_thread_exists = True;
386 s_threadinfo[tid].pt_threadid = ptid;
387}
388
389Bool thread_get_joinable(const DrdThreadId tid)
390{
391 tl_assert(0 <= tid && tid < DRD_N_THREADS
392 && tid != DRD_INVALID_THREADID);
393 return ! s_threadinfo[tid].detached_posix_thread;
394}
395
396void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
397{
398 tl_assert(0 <= tid && tid < DRD_N_THREADS
399 && tid != DRD_INVALID_THREADID);
400 tl_assert(!! joinable == joinable);
401 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
402#if 0
403 VG_(message)(Vg_DebugMsg,
404 "thread_set_joinable(%d/%d, %s)",
405 tid,
406 s_threadinfo[tid].vg_threadid,
407 joinable ? "joinable" : "detached");
408#endif
409 s_threadinfo[tid].detached_posix_thread = ! joinable;
410}
411
412const char* thread_get_name(const DrdThreadId tid)
413{
414 tl_assert(0 <= tid && tid < DRD_N_THREADS
415 && tid != DRD_INVALID_THREADID);
416 return s_threadinfo[tid].name;
417}
418
419void thread_set_name(const DrdThreadId tid, const char* const name)
420{
421 tl_assert(0 <= tid && tid < DRD_N_THREADS
422 && tid != DRD_INVALID_THREADID);
423 VG_(strncpy)(s_threadinfo[tid].name, name,
424 sizeof(s_threadinfo[tid].name));
425 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
426}
427
428void thread_set_name_fmt(const DrdThreadId tid, const char* const fmt,
429 const UWord arg)
430{
431 tl_assert(0 <= tid && tid < DRD_N_THREADS
432 && tid != DRD_INVALID_THREADID);
433 VG_(snprintf)(s_threadinfo[tid].name, sizeof(s_threadinfo[tid].name),
434 fmt, arg);
435 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
436}
sewardj8b09d4f2007-12-04 21:27:18 +0000437
sewardjaf44c822007-11-25 14:01:38 +0000438DrdThreadId thread_get_running_tid(void)
439{
sewardj8b09d4f2007-12-04 21:27:18 +0000440 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
441 return s_drd_running_tid;
sewardjaf44c822007-11-25 14:01:38 +0000442}
443
sewardj8b09d4f2007-12-04 21:27:18 +0000444void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000445{
tom7c1a19a2008-01-02 10:13:04 +0000446 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000447
448 if (vg_tid != s_vg_running_tid)
449 {
450 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
451 }
452
453 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
454 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
455}
456
457void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
458{
sewardj8b09d4f2007-12-04 21:27:18 +0000459 tl_assert(vg_tid != VG_INVALID_THREADID);
460 tl_assert(drd_tid != DRD_INVALID_THREADID);
461
462 if (vg_tid != s_vg_running_tid)
463 {
bart26f73e12008-02-24 18:37:08 +0000464 if (s_trace_context_switches
465 && s_drd_running_tid != DRD_INVALID_THREADID)
466 {
467 VG_(message)(Vg_DebugMsg,
468 "Context switch from thread %d to thread %d",
469 s_drd_running_tid, drd_tid);
470 }
sewardj8b09d4f2007-12-04 21:27:18 +0000471 s_vg_running_tid = vg_tid;
472 s_drd_running_tid = drd_tid;
473 thread_update_danger_set(drd_tid);
474 s_context_switch_count++;
475 }
476
477 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
478 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000479}
480
bart0268dfa2008-03-11 20:10:21 +0000481int thread_enter_synchr(const DrdThreadId tid)
482{
483 tl_assert(IsValidDrdThreadId(tid));
484 return s_threadinfo[tid].synchr_nesting++;
485}
486
487int thread_leave_synchr(const DrdThreadId tid)
488{
489 tl_assert(IsValidDrdThreadId(tid));
490 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
491 return --s_threadinfo[tid].synchr_nesting;
492}
493
494int thread_get_synchr_nesting_count(const DrdThreadId tid)
495{
496 tl_assert(IsValidDrdThreadId(tid));
497 return s_threadinfo[tid].synchr_nesting;
498}
499
sewardjaf44c822007-11-25 14:01:38 +0000500/**
501 * Return a pointer to the latest segment for the specified thread.
502 */
503Segment* thread_get_segment(const DrdThreadId tid)
504{
505 tl_assert(0 <= tid && tid < DRD_N_THREADS
506 && tid != DRD_INVALID_THREADID);
507 if (s_threadinfo[tid].last == 0)
508 {
509 VG_(message)(Vg_DebugMsg, "threadid = %d", tid);
510 thread_print_all();
511 }
512 tl_assert(s_threadinfo[tid].last);
513 return s_threadinfo[tid].last;
514}
515
bart26f73e12008-02-24 18:37:08 +0000516/** Append a new segment at the end of the segment list.
sewardjaf44c822007-11-25 14:01:38 +0000517 */
bart26f73e12008-02-24 18:37:08 +0000518static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000519{
520 tl_assert(0 <= tid && tid < DRD_N_THREADS
521 && tid != DRD_INVALID_THREADID);
522 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
523 sg->prev = s_threadinfo[tid].last;
524 sg->next = 0;
525 if (s_threadinfo[tid].last)
526 s_threadinfo[tid].last->next = sg;
527 s_threadinfo[tid].last = sg;
528 if (s_threadinfo[tid].first == 0)
529 s_threadinfo[tid].first = sg;
530 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
531}
532
bart26f73e12008-02-24 18:37:08 +0000533/** Remove a segment from the segment list of thread threadid, and free the
534 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000535 */
bart26f73e12008-02-24 18:37:08 +0000536static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000537{
538 tl_assert(0 <= tid && tid < DRD_N_THREADS
539 && tid != DRD_INVALID_THREADID);
540 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000541
sewardjaf44c822007-11-25 14:01:38 +0000542 if (sg->prev)
543 sg->prev->next = sg->next;
544 if (sg->next)
545 sg->next->prev = sg->prev;
546 if (sg == s_threadinfo[tid].first)
547 s_threadinfo[tid].first = sg->next;
548 if (sg == s_threadinfo[tid].last)
549 s_threadinfo[tid].last = sg->prev;
550 sg_delete(sg);
551 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
552}
553
554VectorClock* thread_get_vc(const DrdThreadId tid)
555{
556 tl_assert(0 <= tid && tid < DRD_N_THREADS
557 && tid != DRD_INVALID_THREADID);
558 tl_assert(s_threadinfo[tid].last);
559 return &s_threadinfo[tid].last->vc;
560}
561
562/**
563 * Compute the minimum of all latest vector clocks of all threads
564 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
565 * @param vc pointer to a vectorclock, holds result upon return.
566 */
567static void thread_compute_minimum_vc(VectorClock* vc)
568{
bart2cf220a2008-03-01 07:35:52 +0000569 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000570 Bool first;
571 Segment* latest_sg;
572
573 first = True;
574 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
575 {
576 latest_sg = s_threadinfo[i].last;
577 if (latest_sg)
578 {
579 if (first)
bart26f73e12008-02-24 18:37:08 +0000580 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000581 else
582 vc_min(vc, &latest_sg->vc);
583 first = False;
584 }
585 }
586}
587
588static void thread_compute_maximum_vc(VectorClock* vc)
589{
bart2cf220a2008-03-01 07:35:52 +0000590 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000591 Bool first;
592 Segment* latest_sg;
593
594 first = True;
595 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
596 {
597 latest_sg = s_threadinfo[i].last;
598 if (latest_sg)
599 {
600 if (first)
bart26f73e12008-02-24 18:37:08 +0000601 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000602 else
603 vc_combine(vc, &latest_sg->vc);
604 first = False;
605 }
606 }
607}
608
609/**
bart5bd9f2d2008-03-03 20:31:58 +0000610 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000611 * clock of every thread -- these segments can no longer be involved in a
612 * data race.
613 */
614static void thread_discard_ordered_segments(void)
615{
bart2cf220a2008-03-01 07:35:52 +0000616 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000617 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000618
619 s_discard_ordered_segments_count++;
620
621 vc_init(&thread_vc_min, 0, 0);
622 thread_compute_minimum_vc(&thread_vc_min);
623 if (sg_get_trace())
624 {
625 char msg[256];
626 VectorClock thread_vc_max;
627
628 vc_init(&thread_vc_max, 0, 0);
629 thread_compute_maximum_vc(&thread_vc_max);
630 VG_(snprintf)(msg, sizeof(msg),
631 "Discarding ordered segments -- min vc is ");
632 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
633 &thread_vc_min);
634 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
635 ", max vc is ");
636 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
637 &thread_vc_max);
638 VG_(message)(Vg_DebugMsg, "%s", msg);
639 vc_cleanup(&thread_vc_max);
640 }
641
642 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
643 {
644 Segment* sg;
645 Segment* sg_next;
646 for (sg = s_threadinfo[i].first;
647 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
648 sg = sg_next)
649 {
sewardjaf44c822007-11-25 14:01:38 +0000650 thread_discard_segment(i, sg);
651 }
652 }
653 vc_cleanup(&thread_vc_min);
654}
655
656/**
657 * Create a new segment for the specified thread, and report all data races
658 * of the most recent thread segment with other threads.
659 */
660void thread_new_segment(const DrdThreadId tid)
661{
sewardjaf44c822007-11-25 14:01:38 +0000662 Segment* sg;
663
664 tl_assert(0 <= tid && tid < DRD_N_THREADS
665 && tid != DRD_INVALID_THREADID);
666
sewardjaf44c822007-11-25 14:01:38 +0000667 sg = sg_new(tid, tid);
668 thread_append_segment(tid, sg);
669
670 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000671
672 if (tid == s_drd_running_tid)
673 {
674 /* Every change in the vector clock of the current thread may cause */
675 /* segments that were previously ordered to this thread to become */
676 /* unordered. Hence, recalculate the danger set if the vector clock */
677 /* of the current thread is updated. */
678 thread_update_danger_set(tid);
679 }
sewardjaf44c822007-11-25 14:01:38 +0000680}
681
bart26f73e12008-02-24 18:37:08 +0000682/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000683void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
684{
685 tl_assert(joiner != joinee);
686 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
687 && joiner != DRD_INVALID_THREADID);
688 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
689 && joinee != DRD_INVALID_THREADID);
690 tl_assert(s_threadinfo[joiner].last);
691 tl_assert(s_threadinfo[joinee].last);
692 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
693 thread_discard_ordered_segments();
694
sewardj8b09d4f2007-12-04 21:27:18 +0000695 if (joiner == s_drd_running_tid)
sewardjaf44c822007-11-25 14:01:38 +0000696 {
697 thread_update_danger_set(joiner);
698 }
699}
700
bart26f73e12008-02-24 18:37:08 +0000701/** Call this function after thread 'tid' had to wait because of thread
702 * synchronization until the memory accesses in the segment with vector clock
703 * 'vc' finished.
704 */
sewardjaf44c822007-11-25 14:01:38 +0000705void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
706{
707 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
708 tl_assert(s_threadinfo[tid].last);
709 tl_assert(vc);
710 vc_combine(&s_threadinfo[tid].last->vc, vc);
711 thread_discard_ordered_segments();
712}
713
bart26f73e12008-02-24 18:37:08 +0000714/** Call this function whenever a thread is no longer using the memory
715 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
716 * increase.
717 */
sewardjaf44c822007-11-25 14:01:38 +0000718void thread_stop_using_mem(const Addr a1, const Addr a2)
719{
720 DrdThreadId other_user = DRD_INVALID_THREADID;
721
bart26f73e12008-02-24 18:37:08 +0000722 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
sewardjaf44c822007-11-25 14:01:38 +0000723
724 unsigned i;
725 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
726 {
727 Segment* p;
728 for (p = s_threadinfo[i].first; p; p = p->next)
729 {
730 if (other_user == DRD_INVALID_THREADID
sewardj8b09d4f2007-12-04 21:27:18 +0000731 && i != s_drd_running_tid
sewardjaf44c822007-11-25 14:01:38 +0000732 && bm_has_any_access(p->bm, a1, a2))
733 {
734 other_user = i;
735 }
736 bm_clear(p->bm, a1, a2);
737 }
738 }
739
bart26f73e12008-02-24 18:37:08 +0000740 /* If any other thread had accessed memory in [ a1, a2 [, update the */
sewardjaf44c822007-11-25 14:01:38 +0000741 /* danger set. */
742 if (other_user != DRD_INVALID_THREADID
743 && bm_has_any_access(s_danger_set, a1, a2))
744 {
sewardjaf44c822007-11-25 14:01:38 +0000745 thread_update_danger_set(thread_get_running_tid());
746 }
747}
748
bart0268dfa2008-03-11 20:10:21 +0000749void thread_start_recording(const DrdThreadId tid)
750{
751 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
752 tl_assert(! s_threadinfo[tid].is_recording);
753 s_threadinfo[tid].is_recording = True;
754}
755
756void thread_stop_recording(const DrdThreadId tid)
757{
758 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
759 tl_assert(s_threadinfo[tid].is_recording);
760 s_threadinfo[tid].is_recording = False;
761}
762
763Bool thread_is_recording(const DrdThreadId tid)
764{
765 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
766 return (s_threadinfo[tid].synchr_nesting == 0
767 && s_threadinfo[tid].is_recording);
768}
769
sewardjaf44c822007-11-25 14:01:38 +0000770void thread_print_all(void)
771{
772 unsigned i;
773 Segment* p;
774
775 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
776 {
777 if (s_threadinfo[i].first)
778 {
779 VG_(printf)("**************\n"
780 "* thread %3d (%d/%d/%d/0x%x/%d/%s) *\n"
781 "**************\n",
782 i,
783 s_threadinfo[i].vg_thread_exists,
784 s_threadinfo[i].vg_threadid,
785 s_threadinfo[i].posix_thread_exists,
786 s_threadinfo[i].pt_threadid,
787 s_threadinfo[i].detached_posix_thread,
788 s_threadinfo[i].name);
789 for (p = s_threadinfo[i].first; p; p = p->next)
790 {
791 sg_print(p);
792 }
793 }
794 }
795}
796
797static void show_call_stack(const DrdThreadId tid,
798 const Char* const msg,
799 ExeContext* const callstack)
800{
801 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
802
803 VG_(message)(Vg_UserMsg,
804 "%s (%s)",
805 msg,
806 thread_get_name(tid));
807
808 if (vg_tid != VG_INVALID_THREADID)
809 {
810 if (callstack)
811 {
812 VG_(pp_ExeContext)(callstack);
813 }
814 else
815 {
816 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
817 }
818 }
819 else
820 {
821 VG_(message)(Vg_UserMsg,
822 " (thread finished, call stack no longer available)");
823 }
824}
825
sewardjaf44c822007-11-25 14:01:38 +0000826static void
827thread_report_conflicting_segments_segment(const DrdThreadId tid,
828 const Addr addr,
829 const SizeT size,
830 const BmAccessTypeT access_type,
831 const Segment* const p)
832{
833 unsigned i;
834
835 tl_assert(0 <= tid && tid < DRD_N_THREADS
836 && tid != DRD_INVALID_THREADID);
837 tl_assert(p);
838
839 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
840 {
841 if (i != tid)
842 {
843 Segment* q;
844 for (q = s_threadinfo[i].last; q; q = q->prev)
845 {
846 // Since q iterates over the segments of thread i in order of
847 // decreasing vector clocks, if q->vc <= p->vc, then
848 // q->next->vc <= p->vc will also hold. Hence, break out of the
849 // loop once this condition is met.
850 if (vc_lte(&q->vc, &p->vc))
851 break;
852 if (! vc_lte(&p->vc, &q->vc))
853 {
854 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
855 {
856 tl_assert(q->stacktrace);
857 show_call_stack(i, "Other segment start",
858 q->stacktrace);
859 show_call_stack(i, "Other segment end",
860 q->next ? q->next->stacktrace : 0);
861 }
862 }
863 }
864 }
865 }
866}
867
868void thread_report_conflicting_segments(const DrdThreadId tid,
869 const Addr addr,
870 const SizeT size,
871 const BmAccessTypeT access_type)
872{
873 Segment* p;
874
875 tl_assert(0 <= tid && tid < DRD_N_THREADS
876 && tid != DRD_INVALID_THREADID);
877
878 for (p = s_threadinfo[tid].first; p; p = p->next)
879 {
880 if (bm_has(p->bm, addr, addr + size, access_type))
881 {
882 thread_report_conflicting_segments_segment(tid, addr, size,
883 access_type, p);
884 }
885 }
886}
sewardjaf44c822007-11-25 14:01:38 +0000887
bart26f73e12008-02-24 18:37:08 +0000888/** Compute a bitmap that represents the union of all memory accesses of all
889 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000890 */
891static void thread_update_danger_set(const DrdThreadId tid)
892{
893 Segment* p;
894
bart26f73e12008-02-24 18:37:08 +0000895 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000896 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000897
898 s_update_danger_set_count++;
899 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
900 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
901
sewardjaf44c822007-11-25 14:01:38 +0000902 if (s_danger_set)
903 {
904 bm_clear_all(s_danger_set);
905 }
906 else
907 {
908 s_danger_set = bm_new();
909 }
bart26f73e12008-02-24 18:37:08 +0000910
911 if (s_trace_danger_set)
912 {
913 char msg[256];
914
915 VG_(snprintf)(msg, sizeof(msg),
916 "computing danger set for thread %d with vc ",
917 tid);
918 vc_snprint(msg + VG_(strlen)(msg),
919 sizeof(msg) - VG_(strlen)(msg),
920 &s_threadinfo[tid].last->vc);
921 VG_(message)(Vg_DebugMsg, "%s", msg);
922 }
sewardjaf44c822007-11-25 14:01:38 +0000923
bart5bd9f2d2008-03-03 20:31:58 +0000924 p = s_threadinfo[tid].last;
sewardjaf44c822007-11-25 14:01:38 +0000925 {
926 unsigned j;
927
bart26f73e12008-02-24 18:37:08 +0000928 if (s_trace_danger_set)
929 {
930 char msg[256];
931
932 VG_(snprintf)(msg, sizeof(msg),
933 "danger set: thread [%d] at vc ",
934 tid);
935 vc_snprint(msg + VG_(strlen)(msg),
936 sizeof(msg) - VG_(strlen)(msg),
937 &p->vc);
938 VG_(message)(Vg_DebugMsg, "%s", msg);
939 }
940
sewardjaf44c822007-11-25 14:01:38 +0000941 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
942 {
943 if (IsValidDrdThreadId(j))
944 {
bart5bd9f2d2008-03-03 20:31:58 +0000945 const Segment* q;
946 for (q = s_threadinfo[j].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000947 if (j != tid && q != 0
948 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
949 {
bart26f73e12008-02-24 18:37:08 +0000950 if (s_trace_danger_set)
951 {
952 char msg[256];
953 VG_(snprintf)(msg, sizeof(msg),
954 "danger set: [%d] merging segment ", j);
955 vc_snprint(msg + VG_(strlen)(msg),
956 sizeof(msg) - VG_(strlen)(msg),
957 &q->vc);
958 VG_(message)(Vg_DebugMsg, "%s", msg);
959 }
sewardjaf44c822007-11-25 14:01:38 +0000960 bm_merge2(s_danger_set, q->bm);
961 }
bart26f73e12008-02-24 18:37:08 +0000962 else
963 {
964 if (s_trace_danger_set)
965 {
966 char msg[256];
967 VG_(snprintf)(msg, sizeof(msg),
968 "danger set: [%d] ignoring segment ", j);
969 vc_snprint(msg + VG_(strlen)(msg),
970 sizeof(msg) - VG_(strlen)(msg),
971 &q->vc);
972 VG_(message)(Vg_DebugMsg, "%s", msg);
973 }
974 }
sewardjaf44c822007-11-25 14:01:38 +0000975 }
976 }
977
978 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
979 {
980 if (IsValidDrdThreadId(j))
981 {
982 // NPTL hack: don't report data races on sizeof(struct pthread)
983 // bytes at the top of the stack, since the NPTL functions access
984 // this data without locking.
985 if (s_threadinfo[j].stack_min != 0)
986 {
987 tl_assert(s_threadinfo[j].stack_startup != 0);
988 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
989 {
990 bm_clear(s_danger_set,
991 s_threadinfo[j].stack_min,
992 s_threadinfo[j].stack_startup);
993 }
994 }
995 }
996 }
997 }
998
999 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
1000 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
1001
bart26f73e12008-02-24 18:37:08 +00001002 if (0 && s_trace_danger_set)
1003 {
1004 VG_(message)(Vg_DebugMsg, "[%d] new danger set:", tid);
1005 bm_print(s_danger_set);
1006 VG_(message)(Vg_DebugMsg, "[%d] end of new danger set.", tid);
1007 }
sewardjaf44c822007-11-25 14:01:38 +00001008}
1009
1010Bool thread_conflicting_access(const Addr a,
1011 const SizeT size,
1012 const BmAccessTypeT access_type)
1013{
1014 tl_assert(s_danger_set);
1015 return (bm_has_conflict_with(s_danger_set, a, a + size, access_type)
1016 && ! drd_is_suppressed(a, a + size));
1017}
1018
1019ULong thread_get_context_switch_count(void)
1020{
1021 return s_context_switch_count;
1022}
1023
sewardjaf44c822007-11-25 14:01:38 +00001024ULong thread_get_discard_ordered_segments_count(void)
1025{
1026 return s_discard_ordered_segments_count;
1027}
1028
1029ULong thread_get_update_danger_set_count(void)
1030{
1031 return s_update_danger_set_count;
1032}
1033
1034ULong thread_get_danger_set_bitmap_creation_count(void)
1035{
1036 return s_danger_set_bitmap_creation_count;
1037}
1038
1039ULong thread_get_danger_set_bitmap2_creation_count(void)
1040{
1041 return s_danger_set_bitmap2_creation_count;
1042}
1043
1044/*
1045 * Local variables:
1046 * c-basic-offset: 3
1047 * End:
1048 */