blob: 031a02f876ca2ee75820de7ebdc3eeecc785057c [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;
66 Bool is_recording;
67} ThreadInfo;
68
69
70// Local functions.
71
72static void thread_append_segment(const DrdThreadId tid,
73 Segment* const sg);
74static void thread_update_danger_set(const DrdThreadId tid);
75
76
77// Local variables.
78
79static ULong s_context_switch_count;
80static ULong s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +000081static ULong s_update_danger_set_count;
82static ULong s_danger_set_bitmap_creation_count;
83static ULong s_danger_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000084static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
85static DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +000086static ThreadInfo s_threadinfo[DRD_N_THREADS];
87static struct bitmap* s_danger_set;
bart26f73e12008-02-24 18:37:08 +000088static Bool s_trace_context_switches = False;
89static Bool s_trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000090
91
92// Function definitions.
93
bart26f73e12008-02-24 18:37:08 +000094void thread_trace_context_switches(const Bool t)
95{
96 s_trace_context_switches = t;
97}
98
99void thread_trace_danger_set(const Bool t)
100{
101 s_trace_danger_set = t;
102}
103
sewardjaf44c822007-11-25 14:01:38 +0000104__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
105{
106 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
107 && ! (s_threadinfo[tid].vg_thread_exists == False
108 && s_threadinfo[tid].posix_thread_exists == False
109 && s_threadinfo[tid].detached_posix_thread == False));
110}
111
112/**
113 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
114 * Valgrind's ThreadId does not yet exist.
115 **/
116DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
117{
118 int i;
119
120 if (tid == VG_INVALID_THREADID)
121 return DRD_INVALID_THREADID;
122
123 for (i = 1; i < DRD_N_THREADS; i++)
124 {
125 if (s_threadinfo[i].vg_thread_exists == True
126 && s_threadinfo[i].vg_threadid == tid)
127 {
128 return i;
129 }
130 }
131
132 return DRD_INVALID_THREADID;
133}
134
135static
136DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
137{
138 int i;
139
140 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
141
142 for (i = 1; i < DRD_N_THREADS; i++)
143 {
144 if (s_threadinfo[i].vg_thread_exists == False
145 && s_threadinfo[i].posix_thread_exists == False
146 && s_threadinfo[i].detached_posix_thread == False)
147 {
148 s_threadinfo[i].vg_thread_exists = True;
149 s_threadinfo[i].vg_threadid = tid;
150 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
151 s_threadinfo[i].stack_min_min = 0;
152 s_threadinfo[i].stack_min = 0;
153 s_threadinfo[i].stack_startup = 0;
154 s_threadinfo[i].stack_max = 0;
155 VG_(snprintf)(s_threadinfo[i].name, sizeof(s_threadinfo[i].name),
156 "thread %d", tid);
157 s_threadinfo[i].name[sizeof(s_threadinfo[i].name) - 1] = 0;
158 s_threadinfo[i].is_recording = True;
159 if (s_threadinfo[i].first != 0)
160 VG_(printf)("drd thread id = %d\n", i);
161 tl_assert(s_threadinfo[i].first == 0);
162 tl_assert(s_threadinfo[i].last == 0);
163 return i;
164 }
165 }
166
167 tl_assert(False);
168
169 return DRD_INVALID_THREADID;
170}
171
172DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
173{
174 int i;
175
176 tl_assert(tid != INVALID_POSIX_THREADID);
177
178 for (i = 1; i < DRD_N_THREADS; i++)
179 {
180 if (s_threadinfo[i].posix_thread_exists
181 && s_threadinfo[i].pt_threadid == tid)
182 {
183 return i;
184 }
185 }
186 return DRD_INVALID_THREADID;
187}
188
189ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
190{
191 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
192 return (s_threadinfo[tid].vg_thread_exists
193 ? s_threadinfo[tid].vg_threadid
194 : VG_INVALID_THREADID);
195}
196
bart26f73e12008-02-24 18:37:08 +0000197/** Sanity check of the doubly linked list of segments referenced by a
198 * ThreadInfo struct.
199 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000200 */
201static Bool sane_ThreadInfo(const ThreadInfo* const ti)
202{
203 Segment* p;
204 for (p = ti->first; p; p = p->next) {
205 if (p->next && p->next->prev != p)
206 return False;
207 if (p->next == 0 && p != ti->last)
208 return False;
209 }
210 for (p = ti->last; p; p = p->prev) {
211 if (p->prev && p->prev->next != p)
212 return False;
213 if (p->prev == 0 && p != ti->first)
214 return False;
215 }
216 return True;
217}
218
219DrdThreadId thread_pre_create(const DrdThreadId creator,
220 const ThreadId vg_created)
221{
222 DrdThreadId created;
223
224 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
225 created = VgThreadIdToNewDrdThreadId(vg_created);
226 tl_assert(0 <= created && created < DRD_N_THREADS
227 && created != DRD_INVALID_THREADID);
228
229 tl_assert(s_threadinfo[created].first == 0);
230 tl_assert(s_threadinfo[created].last == 0);
231 thread_append_segment(created, sg_new(creator, created));
232
233 return created;
234}
235
bart26f73e12008-02-24 18:37:08 +0000236/** Allocate the first segment for a thread. Call this just after
237 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000238 */
239DrdThreadId thread_post_create(const ThreadId vg_created)
240{
241 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
242
243 tl_assert(0 <= created && created < DRD_N_THREADS
244 && created != DRD_INVALID_THREADID);
245
246 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
247 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
248 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
249 s_threadinfo[created].stack_min_min = s_threadinfo[created].stack_max;
250 tl_assert(s_threadinfo[created].stack_max != 0);
251
252 return created;
253}
254
255/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
256/* and accesses this data structure from multiple threads without locking. */
257/* Any conflicting accesses in the range stack_startup..stack_max will be */
258/* ignored. */
259void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
260{
261#if 0
262 VG_(message)(Vg_DebugMsg, "thread_set_stack_startup: thread %d (%d)"
263 " stack 0x%x .. 0x%lx (size %d)",
264 s_threadinfo[tid].vg_threadid, tid,
265 stack_startup,
266 s_threadinfo[tid].stack_max,
267 s_threadinfo[tid].stack_max - stack_startup);
268#endif
269 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
270 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
271 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
272 s_threadinfo[tid].stack_startup = stack_startup;
273}
274
275Addr thread_get_stack_min(const DrdThreadId tid)
276{
277 tl_assert(0 <= tid && tid < DRD_N_THREADS
278 && tid != DRD_INVALID_THREADID);
279 return s_threadinfo[tid].stack_min;
280}
281
282void thread_set_stack_min(const DrdThreadId tid, const Addr stack_min)
283{
284#if 0
285 VG_(message)(Vg_DebugMsg, "thread %d (%d) stack_min = 0x%x"
286 " (size %d, max %d, delta %d)",
287 s_threadinfo[tid].vg_threadid, tid,
288 stack_min,
289 s_threadinfo[tid].stack_max - stack_min,
290 s_threadinfo[tid].stack_max - s_threadinfo[tid].stack_min_min,
291 s_threadinfo[tid].stack_min - stack_min);
292#endif
293 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
294 if (s_threadinfo[tid].stack_max)
295 {
296 s_threadinfo[tid].stack_min = stack_min;
297 if (stack_min < s_threadinfo[tid].stack_min_min)
298 {
299 s_threadinfo[tid].stack_min_min = stack_min;
300 }
301 tl_assert(s_threadinfo[tid].stack_min_min
302 <= s_threadinfo[tid].stack_min);
303 tl_assert(s_threadinfo[tid].stack_min < s_threadinfo[tid].stack_max);
304 }
305}
306
307DrdThreadId thread_lookup_stackaddr(const Addr a,
308 Addr* const stack_min,
309 Addr* const stack_max)
310{
311 unsigned i;
312 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
313 {
314 if (s_threadinfo[i].stack_min <= a && a <= s_threadinfo[i].stack_max)
315 {
316 *stack_min = s_threadinfo[i].stack_min;
317 *stack_max = s_threadinfo[i].stack_max;
318 return i;
319 }
320 }
321 return DRD_INVALID_THREADID;
322}
323
324/**
325 * Clean up thread-specific data structures. Call this just after
326 * pthread_join().
327 */
328void thread_delete(const DrdThreadId tid)
329{
330 Segment* sg;
331 Segment* sg_prev;
332
333 tl_assert(0 <= tid && tid < DRD_N_THREADS
334 && tid != DRD_INVALID_THREADID);
335 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
336 {
337 sg_prev = sg->prev;
338 sg_delete(sg);
339 }
340 s_threadinfo[tid].vg_thread_exists = False;
341 s_threadinfo[tid].posix_thread_exists = False;
342 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
343 s_threadinfo[tid].first = 0;
344 s_threadinfo[tid].last = 0;
345}
346
347/* Called after a thread performed its last memory access and before */
348/* thread_delete() is called. Note: thread_delete() is only called for */
349/* joinable threads, not for detached threads. */
350void thread_finished(const DrdThreadId tid)
351{
352 tl_assert(0 <= tid && tid < DRD_N_THREADS
353 && tid != DRD_INVALID_THREADID);
354
355 thread_stop_using_mem(s_threadinfo[tid].stack_min,
356 s_threadinfo[tid].stack_max);
357
358 s_threadinfo[tid].vg_thread_exists = False;
359
360 if (s_threadinfo[tid].detached_posix_thread)
361 {
362 /* Once a detached thread has finished, its stack is deallocated and */
363 /* should no longer be taken into account when computing the danger set*/
364 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
365
366 /* For a detached thread, calling pthread_exit() invalidates the */
367 /* POSIX thread ID associated with the detached thread. For joinable */
368 /* POSIX threads however, the POSIX thread ID remains live after the */
369 /* pthread_exit() call until pthread_join() is called. */
370 s_threadinfo[tid].posix_thread_exists = False;
371 }
372}
373
374void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
375{
376 tl_assert(0 <= tid && tid < DRD_N_THREADS
377 && tid != DRD_INVALID_THREADID);
378 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
379 tl_assert(ptid != INVALID_POSIX_THREADID);
380 s_threadinfo[tid].posix_thread_exists = True;
381 s_threadinfo[tid].pt_threadid = ptid;
382}
383
384Bool thread_get_joinable(const DrdThreadId tid)
385{
386 tl_assert(0 <= tid && tid < DRD_N_THREADS
387 && tid != DRD_INVALID_THREADID);
388 return ! s_threadinfo[tid].detached_posix_thread;
389}
390
391void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
392{
393 tl_assert(0 <= tid && tid < DRD_N_THREADS
394 && tid != DRD_INVALID_THREADID);
395 tl_assert(!! joinable == joinable);
396 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
397#if 0
398 VG_(message)(Vg_DebugMsg,
399 "thread_set_joinable(%d/%d, %s)",
400 tid,
401 s_threadinfo[tid].vg_threadid,
402 joinable ? "joinable" : "detached");
403#endif
404 s_threadinfo[tid].detached_posix_thread = ! joinable;
405}
406
407const char* thread_get_name(const DrdThreadId tid)
408{
409 tl_assert(0 <= tid && tid < DRD_N_THREADS
410 && tid != DRD_INVALID_THREADID);
411 return s_threadinfo[tid].name;
412}
413
414void thread_set_name(const DrdThreadId tid, const char* const name)
415{
416 tl_assert(0 <= tid && tid < DRD_N_THREADS
417 && tid != DRD_INVALID_THREADID);
418 VG_(strncpy)(s_threadinfo[tid].name, name,
419 sizeof(s_threadinfo[tid].name));
420 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
421}
422
423void thread_set_name_fmt(const DrdThreadId tid, const char* const fmt,
424 const UWord arg)
425{
426 tl_assert(0 <= tid && tid < DRD_N_THREADS
427 && tid != DRD_INVALID_THREADID);
428 VG_(snprintf)(s_threadinfo[tid].name, sizeof(s_threadinfo[tid].name),
429 fmt, arg);
430 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
431}
sewardj8b09d4f2007-12-04 21:27:18 +0000432
sewardjaf44c822007-11-25 14:01:38 +0000433DrdThreadId thread_get_running_tid(void)
434{
tom7c1a19a2008-01-02 10:13:04 +0000435 tl_assert(VG_(get_running_tid)() == s_vg_running_tid);
sewardj8b09d4f2007-12-04 21:27:18 +0000436 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
437 return s_drd_running_tid;
sewardjaf44c822007-11-25 14:01:38 +0000438}
439
sewardj8b09d4f2007-12-04 21:27:18 +0000440void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000441{
tom7c1a19a2008-01-02 10:13:04 +0000442 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000443
444 if (vg_tid != s_vg_running_tid)
445 {
446 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
447 }
448
449 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
450 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
451}
452
453void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
454{
sewardj8b09d4f2007-12-04 21:27:18 +0000455 tl_assert(vg_tid != VG_INVALID_THREADID);
456 tl_assert(drd_tid != DRD_INVALID_THREADID);
457
458 if (vg_tid != s_vg_running_tid)
459 {
bart26f73e12008-02-24 18:37:08 +0000460 if (s_trace_context_switches
461 && s_drd_running_tid != DRD_INVALID_THREADID)
462 {
463 VG_(message)(Vg_DebugMsg,
464 "Context switch from thread %d to thread %d",
465 s_drd_running_tid, drd_tid);
466 }
sewardj8b09d4f2007-12-04 21:27:18 +0000467 s_vg_running_tid = vg_tid;
468 s_drd_running_tid = drd_tid;
469 thread_update_danger_set(drd_tid);
470 s_context_switch_count++;
471 }
472
473 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
474 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000475}
476
477/**
478 * Return a pointer to the latest segment for the specified thread.
479 */
480Segment* thread_get_segment(const DrdThreadId tid)
481{
482 tl_assert(0 <= tid && tid < DRD_N_THREADS
483 && tid != DRD_INVALID_THREADID);
484 if (s_threadinfo[tid].last == 0)
485 {
486 VG_(message)(Vg_DebugMsg, "threadid = %d", tid);
487 thread_print_all();
488 }
489 tl_assert(s_threadinfo[tid].last);
490 return s_threadinfo[tid].last;
491}
492
bart26f73e12008-02-24 18:37:08 +0000493/** Append a new segment at the end of the segment list.
sewardjaf44c822007-11-25 14:01:38 +0000494 */
bart26f73e12008-02-24 18:37:08 +0000495static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000496{
497 tl_assert(0 <= tid && tid < DRD_N_THREADS
498 && tid != DRD_INVALID_THREADID);
499 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
500 sg->prev = s_threadinfo[tid].last;
501 sg->next = 0;
502 if (s_threadinfo[tid].last)
503 s_threadinfo[tid].last->next = sg;
504 s_threadinfo[tid].last = sg;
505 if (s_threadinfo[tid].first == 0)
506 s_threadinfo[tid].first = sg;
507 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
508}
509
bart26f73e12008-02-24 18:37:08 +0000510/** Remove a segment from the segment list of thread threadid, and free the
511 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000512 */
bart26f73e12008-02-24 18:37:08 +0000513static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000514{
515 tl_assert(0 <= tid && tid < DRD_N_THREADS
516 && tid != DRD_INVALID_THREADID);
517 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000518
sewardjaf44c822007-11-25 14:01:38 +0000519 if (sg->prev)
520 sg->prev->next = sg->next;
521 if (sg->next)
522 sg->next->prev = sg->prev;
523 if (sg == s_threadinfo[tid].first)
524 s_threadinfo[tid].first = sg->next;
525 if (sg == s_threadinfo[tid].last)
526 s_threadinfo[tid].last = sg->prev;
527 sg_delete(sg);
528 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
529}
530
531VectorClock* thread_get_vc(const DrdThreadId tid)
532{
533 tl_assert(0 <= tid && tid < DRD_N_THREADS
534 && tid != DRD_INVALID_THREADID);
535 tl_assert(s_threadinfo[tid].last);
536 return &s_threadinfo[tid].last->vc;
537}
538
539/**
540 * Compute the minimum of all latest vector clocks of all threads
541 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
542 * @param vc pointer to a vectorclock, holds result upon return.
543 */
544static void thread_compute_minimum_vc(VectorClock* vc)
545{
546 int i;
547 Bool first;
548 Segment* latest_sg;
549
550 first = True;
551 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
552 {
553 latest_sg = s_threadinfo[i].last;
554 if (latest_sg)
555 {
556 if (first)
bart26f73e12008-02-24 18:37:08 +0000557 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000558 else
559 vc_min(vc, &latest_sg->vc);
560 first = False;
561 }
562 }
563}
564
565static void thread_compute_maximum_vc(VectorClock* vc)
566{
567 int i;
568 Bool first;
569 Segment* latest_sg;
570
571 first = True;
572 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
573 {
574 latest_sg = s_threadinfo[i].last;
575 if (latest_sg)
576 {
577 if (first)
bart26f73e12008-02-24 18:37:08 +0000578 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000579 else
580 vc_combine(vc, &latest_sg->vc);
581 first = False;
582 }
583 }
584}
585
586/**
587 * Discard all segments that have a defined ordered against the latest vector
588 * clock of every thread -- these segments can no longer be involved in a
589 * data race.
590 */
591static void thread_discard_ordered_segments(void)
592{
593 VectorClock thread_vc_min;
594 int i;
595
596 s_discard_ordered_segments_count++;
597
598 vc_init(&thread_vc_min, 0, 0);
599 thread_compute_minimum_vc(&thread_vc_min);
600 if (sg_get_trace())
601 {
602 char msg[256];
603 VectorClock thread_vc_max;
604
605 vc_init(&thread_vc_max, 0, 0);
606 thread_compute_maximum_vc(&thread_vc_max);
607 VG_(snprintf)(msg, sizeof(msg),
608 "Discarding ordered segments -- min vc is ");
609 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
610 &thread_vc_min);
611 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
612 ", max vc is ");
613 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
614 &thread_vc_max);
615 VG_(message)(Vg_DebugMsg, "%s", msg);
616 vc_cleanup(&thread_vc_max);
617 }
618
619 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
620 {
621 Segment* sg;
622 Segment* sg_next;
623 for (sg = s_threadinfo[i].first;
624 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
625 sg = sg_next)
626 {
sewardjaf44c822007-11-25 14:01:38 +0000627 thread_discard_segment(i, sg);
628 }
629 }
630 vc_cleanup(&thread_vc_min);
631}
632
633/**
634 * Create a new segment for the specified thread, and report all data races
635 * of the most recent thread segment with other threads.
636 */
637void thread_new_segment(const DrdThreadId tid)
638{
sewardjaf44c822007-11-25 14:01:38 +0000639 Segment* sg;
640
641 tl_assert(0 <= tid && tid < DRD_N_THREADS
642 && tid != DRD_INVALID_THREADID);
643
sewardjaf44c822007-11-25 14:01:38 +0000644 sg = sg_new(tid, tid);
645 thread_append_segment(tid, sg);
646
647 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000648
649 if (tid == s_drd_running_tid)
650 {
651 /* Every change in the vector clock of the current thread may cause */
652 /* segments that were previously ordered to this thread to become */
653 /* unordered. Hence, recalculate the danger set if the vector clock */
654 /* of the current thread is updated. */
655 thread_update_danger_set(tid);
656 }
sewardjaf44c822007-11-25 14:01:38 +0000657}
658
bart26f73e12008-02-24 18:37:08 +0000659/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000660void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
661{
662 tl_assert(joiner != joinee);
663 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
664 && joiner != DRD_INVALID_THREADID);
665 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
666 && joinee != DRD_INVALID_THREADID);
667 tl_assert(s_threadinfo[joiner].last);
668 tl_assert(s_threadinfo[joinee].last);
669 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
670 thread_discard_ordered_segments();
671
sewardj8b09d4f2007-12-04 21:27:18 +0000672 if (joiner == s_drd_running_tid)
sewardjaf44c822007-11-25 14:01:38 +0000673 {
674 thread_update_danger_set(joiner);
675 }
676}
677
bart26f73e12008-02-24 18:37:08 +0000678/** Call this function after thread 'tid' had to wait because of thread
679 * synchronization until the memory accesses in the segment with vector clock
680 * 'vc' finished.
681 */
sewardjaf44c822007-11-25 14:01:38 +0000682void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
683{
684 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
685 tl_assert(s_threadinfo[tid].last);
686 tl_assert(vc);
687 vc_combine(&s_threadinfo[tid].last->vc, vc);
688 thread_discard_ordered_segments();
689}
690
bart26f73e12008-02-24 18:37:08 +0000691/** Call this function whenever a thread is no longer using the memory
692 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
693 * increase.
694 */
sewardjaf44c822007-11-25 14:01:38 +0000695void thread_stop_using_mem(const Addr a1, const Addr a2)
696{
697 DrdThreadId other_user = DRD_INVALID_THREADID;
698
bart26f73e12008-02-24 18:37:08 +0000699 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
sewardjaf44c822007-11-25 14:01:38 +0000700
701 unsigned i;
702 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
703 {
704 Segment* p;
705 for (p = s_threadinfo[i].first; p; p = p->next)
706 {
707 if (other_user == DRD_INVALID_THREADID
sewardj8b09d4f2007-12-04 21:27:18 +0000708 && i != s_drd_running_tid
sewardjaf44c822007-11-25 14:01:38 +0000709 && bm_has_any_access(p->bm, a1, a2))
710 {
711 other_user = i;
712 }
713 bm_clear(p->bm, a1, a2);
714 }
715 }
716
bart26f73e12008-02-24 18:37:08 +0000717 /* If any other thread had accessed memory in [ a1, a2 [, update the */
sewardjaf44c822007-11-25 14:01:38 +0000718 /* danger set. */
719 if (other_user != DRD_INVALID_THREADID
720 && bm_has_any_access(s_danger_set, a1, a2))
721 {
sewardjaf44c822007-11-25 14:01:38 +0000722 thread_update_danger_set(thread_get_running_tid());
723 }
724}
725
726void thread_start_recording(const DrdThreadId tid)
727{
728 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
729 tl_assert(! s_threadinfo[tid].is_recording);
730 s_threadinfo[tid].is_recording = True;
731}
732
733void thread_stop_recording(const DrdThreadId tid)
734{
735 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
736 tl_assert(s_threadinfo[tid].is_recording);
737 s_threadinfo[tid].is_recording = False;
738}
739
740Bool thread_is_recording(const DrdThreadId tid)
741{
742 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
743 return s_threadinfo[tid].is_recording;
744}
745
746void thread_print_all(void)
747{
748 unsigned i;
749 Segment* p;
750
751 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
752 {
753 if (s_threadinfo[i].first)
754 {
755 VG_(printf)("**************\n"
756 "* thread %3d (%d/%d/%d/0x%x/%d/%s) *\n"
757 "**************\n",
758 i,
759 s_threadinfo[i].vg_thread_exists,
760 s_threadinfo[i].vg_threadid,
761 s_threadinfo[i].posix_thread_exists,
762 s_threadinfo[i].pt_threadid,
763 s_threadinfo[i].detached_posix_thread,
764 s_threadinfo[i].name);
765 for (p = s_threadinfo[i].first; p; p = p->next)
766 {
767 sg_print(p);
768 }
769 }
770 }
771}
772
773static void show_call_stack(const DrdThreadId tid,
774 const Char* const msg,
775 ExeContext* const callstack)
776{
777 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
778
779 VG_(message)(Vg_UserMsg,
780 "%s (%s)",
781 msg,
782 thread_get_name(tid));
783
784 if (vg_tid != VG_INVALID_THREADID)
785 {
786 if (callstack)
787 {
788 VG_(pp_ExeContext)(callstack);
789 }
790 else
791 {
792 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
793 }
794 }
795 else
796 {
797 VG_(message)(Vg_UserMsg,
798 " (thread finished, call stack no longer available)");
799 }
800}
801
sewardjaf44c822007-11-25 14:01:38 +0000802static void
803thread_report_conflicting_segments_segment(const DrdThreadId tid,
804 const Addr addr,
805 const SizeT size,
806 const BmAccessTypeT access_type,
807 const Segment* const p)
808{
809 unsigned i;
810
811 tl_assert(0 <= tid && tid < DRD_N_THREADS
812 && tid != DRD_INVALID_THREADID);
813 tl_assert(p);
814
815 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
816 {
817 if (i != tid)
818 {
819 Segment* q;
820 for (q = s_threadinfo[i].last; q; q = q->prev)
821 {
822 // Since q iterates over the segments of thread i in order of
823 // decreasing vector clocks, if q->vc <= p->vc, then
824 // q->next->vc <= p->vc will also hold. Hence, break out of the
825 // loop once this condition is met.
826 if (vc_lte(&q->vc, &p->vc))
827 break;
828 if (! vc_lte(&p->vc, &q->vc))
829 {
830 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
831 {
832 tl_assert(q->stacktrace);
833 show_call_stack(i, "Other segment start",
834 q->stacktrace);
835 show_call_stack(i, "Other segment end",
836 q->next ? q->next->stacktrace : 0);
837 }
838 }
839 }
840 }
841 }
842}
843
844void thread_report_conflicting_segments(const DrdThreadId tid,
845 const Addr addr,
846 const SizeT size,
847 const BmAccessTypeT access_type)
848{
849 Segment* p;
850
851 tl_assert(0 <= tid && tid < DRD_N_THREADS
852 && tid != DRD_INVALID_THREADID);
853
854 for (p = s_threadinfo[tid].first; p; p = p->next)
855 {
856 if (bm_has(p->bm, addr, addr + size, access_type))
857 {
858 thread_report_conflicting_segments_segment(tid, addr, size,
859 access_type, p);
860 }
861 }
862}
sewardjaf44c822007-11-25 14:01:38 +0000863
bart26f73e12008-02-24 18:37:08 +0000864/** Compute a bitmap that represents the union of all memory accesses of all
865 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000866 */
867static void thread_update_danger_set(const DrdThreadId tid)
868{
869 Segment* p;
870
bart26f73e12008-02-24 18:37:08 +0000871 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000872 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000873
874 s_update_danger_set_count++;
875 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
876 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
877
sewardjaf44c822007-11-25 14:01:38 +0000878 if (s_danger_set)
879 {
880 bm_clear_all(s_danger_set);
881 }
882 else
883 {
884 s_danger_set = bm_new();
885 }
bart26f73e12008-02-24 18:37:08 +0000886
887 if (s_trace_danger_set)
888 {
889 char msg[256];
890
891 VG_(snprintf)(msg, sizeof(msg),
892 "computing danger set for thread %d with vc ",
893 tid);
894 vc_snprint(msg + VG_(strlen)(msg),
895 sizeof(msg) - VG_(strlen)(msg),
896 &s_threadinfo[tid].last->vc);
897 VG_(message)(Vg_DebugMsg, "%s", msg);
898 }
sewardjaf44c822007-11-25 14:01:38 +0000899
900 for (p = s_threadinfo[tid].first; p; p = p->next)
901 {
902 unsigned j;
903
bart26f73e12008-02-24 18:37:08 +0000904 if (s_trace_danger_set)
905 {
906 char msg[256];
907
908 VG_(snprintf)(msg, sizeof(msg),
909 "danger set: thread [%d] at vc ",
910 tid);
911 vc_snprint(msg + VG_(strlen)(msg),
912 sizeof(msg) - VG_(strlen)(msg),
913 &p->vc);
914 VG_(message)(Vg_DebugMsg, "%s", msg);
915 }
916
sewardjaf44c822007-11-25 14:01:38 +0000917 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
918 {
919 if (IsValidDrdThreadId(j))
920 {
921 const Segment* const q = s_threadinfo[j].last;
922 if (j != tid && q != 0
923 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
924 {
bart26f73e12008-02-24 18:37:08 +0000925 if (s_trace_danger_set)
926 {
927 char msg[256];
928 VG_(snprintf)(msg, sizeof(msg),
929 "danger set: [%d] merging segment ", j);
930 vc_snprint(msg + VG_(strlen)(msg),
931 sizeof(msg) - VG_(strlen)(msg),
932 &q->vc);
933 VG_(message)(Vg_DebugMsg, "%s", msg);
934 }
sewardjaf44c822007-11-25 14:01:38 +0000935 bm_merge2(s_danger_set, q->bm);
936 }
bart26f73e12008-02-24 18:37:08 +0000937 else
938 {
939 if (s_trace_danger_set)
940 {
941 char msg[256];
942 VG_(snprintf)(msg, sizeof(msg),
943 "danger set: [%d] ignoring segment ", j);
944 vc_snprint(msg + VG_(strlen)(msg),
945 sizeof(msg) - VG_(strlen)(msg),
946 &q->vc);
947 VG_(message)(Vg_DebugMsg, "%s", msg);
948 }
949 }
sewardjaf44c822007-11-25 14:01:38 +0000950 }
951 }
952
953 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
954 {
955 if (IsValidDrdThreadId(j))
956 {
957 // NPTL hack: don't report data races on sizeof(struct pthread)
958 // bytes at the top of the stack, since the NPTL functions access
959 // this data without locking.
960 if (s_threadinfo[j].stack_min != 0)
961 {
962 tl_assert(s_threadinfo[j].stack_startup != 0);
963 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
964 {
965 bm_clear(s_danger_set,
966 s_threadinfo[j].stack_min,
967 s_threadinfo[j].stack_startup);
968 }
969 }
970 }
971 }
972 }
973
974 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
975 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
976
bart26f73e12008-02-24 18:37:08 +0000977 if (0 && s_trace_danger_set)
978 {
979 VG_(message)(Vg_DebugMsg, "[%d] new danger set:", tid);
980 bm_print(s_danger_set);
981 VG_(message)(Vg_DebugMsg, "[%d] end of new danger set.", tid);
982 }
sewardjaf44c822007-11-25 14:01:38 +0000983}
984
985Bool thread_conflicting_access(const Addr a,
986 const SizeT size,
987 const BmAccessTypeT access_type)
988{
989 tl_assert(s_danger_set);
990 return (bm_has_conflict_with(s_danger_set, a, a + size, access_type)
991 && ! drd_is_suppressed(a, a + size));
992}
993
994ULong thread_get_context_switch_count(void)
995{
996 return s_context_switch_count;
997}
998
sewardjaf44c822007-11-25 14:01:38 +0000999ULong thread_get_discard_ordered_segments_count(void)
1000{
1001 return s_discard_ordered_segments_count;
1002}
1003
1004ULong thread_get_update_danger_set_count(void)
1005{
1006 return s_update_danger_set_count;
1007}
1008
1009ULong thread_get_danger_set_bitmap_creation_count(void)
1010{
1011 return s_danger_set_bitmap_creation_count;
1012}
1013
1014ULong thread_get_danger_set_bitmap2_creation_count(void)
1015{
1016 return s_danger_set_bitmap2_creation_count;
1017}
1018
1019/*
1020 * Local variables:
1021 * c-basic-offset: 3
1022 * End:
1023 */