blob: 8807117baec5cfedf2fd8a81817446a35481dade [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;
sewardjaf44c822007-11-25 14:01:38 +000066} ThreadInfo;
67
68
69// Local functions.
70
71static void thread_append_segment(const DrdThreadId tid,
72 Segment* const sg);
73static void thread_update_danger_set(const DrdThreadId tid);
74
75
76// Local variables.
77
78static ULong s_context_switch_count;
79static ULong s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +000080static ULong s_update_danger_set_count;
81static ULong s_danger_set_bitmap_creation_count;
82static ULong s_danger_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000083static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
84static DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +000085static ThreadInfo s_threadinfo[DRD_N_THREADS];
86static struct bitmap* s_danger_set;
bart26f73e12008-02-24 18:37:08 +000087static Bool s_trace_context_switches = False;
88static Bool s_trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000089
90
91// Function definitions.
92
bart26f73e12008-02-24 18:37:08 +000093void thread_trace_context_switches(const Bool t)
94{
95 s_trace_context_switches = t;
96}
97
98void thread_trace_danger_set(const Bool t)
99{
100 s_trace_danger_set = t;
101}
102
sewardjaf44c822007-11-25 14:01:38 +0000103__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
104{
105 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
106 && ! (s_threadinfo[tid].vg_thread_exists == False
107 && s_threadinfo[tid].posix_thread_exists == False
108 && s_threadinfo[tid].detached_posix_thread == False));
109}
110
111/**
112 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
113 * Valgrind's ThreadId does not yet exist.
114 **/
115DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
116{
117 int i;
118
119 if (tid == VG_INVALID_THREADID)
120 return DRD_INVALID_THREADID;
121
122 for (i = 1; i < DRD_N_THREADS; i++)
123 {
124 if (s_threadinfo[i].vg_thread_exists == True
125 && s_threadinfo[i].vg_threadid == tid)
126 {
127 return i;
128 }
129 }
130
131 return DRD_INVALID_THREADID;
132}
133
134static
135DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
136{
137 int i;
138
139 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
140
141 for (i = 1; i < DRD_N_THREADS; i++)
142 {
143 if (s_threadinfo[i].vg_thread_exists == False
144 && s_threadinfo[i].posix_thread_exists == False
145 && s_threadinfo[i].detached_posix_thread == False)
146 {
147 s_threadinfo[i].vg_thread_exists = True;
148 s_threadinfo[i].vg_threadid = tid;
149 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
150 s_threadinfo[i].stack_min_min = 0;
151 s_threadinfo[i].stack_min = 0;
152 s_threadinfo[i].stack_startup = 0;
153 s_threadinfo[i].stack_max = 0;
154 VG_(snprintf)(s_threadinfo[i].name, sizeof(s_threadinfo[i].name),
155 "thread %d", tid);
156 s_threadinfo[i].name[sizeof(s_threadinfo[i].name) - 1] = 0;
sewardjaf44c822007-11-25 14:01:38 +0000157 if (s_threadinfo[i].first != 0)
158 VG_(printf)("drd thread id = %d\n", i);
159 tl_assert(s_threadinfo[i].first == 0);
160 tl_assert(s_threadinfo[i].last == 0);
161 return i;
162 }
163 }
164
165 tl_assert(False);
166
167 return DRD_INVALID_THREADID;
168}
169
170DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
171{
172 int i;
173
174 tl_assert(tid != INVALID_POSIX_THREADID);
175
176 for (i = 1; i < DRD_N_THREADS; i++)
177 {
178 if (s_threadinfo[i].posix_thread_exists
179 && s_threadinfo[i].pt_threadid == tid)
180 {
181 return i;
182 }
183 }
184 return DRD_INVALID_THREADID;
185}
186
187ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
188{
189 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
190 return (s_threadinfo[tid].vg_thread_exists
191 ? s_threadinfo[tid].vg_threadid
192 : VG_INVALID_THREADID);
193}
194
bart26f73e12008-02-24 18:37:08 +0000195/** Sanity check of the doubly linked list of segments referenced by a
196 * ThreadInfo struct.
197 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000198 */
199static Bool sane_ThreadInfo(const ThreadInfo* const ti)
200{
201 Segment* p;
202 for (p = ti->first; p; p = p->next) {
203 if (p->next && p->next->prev != p)
204 return False;
205 if (p->next == 0 && p != ti->last)
206 return False;
207 }
208 for (p = ti->last; p; p = p->prev) {
209 if (p->prev && p->prev->next != p)
210 return False;
211 if (p->prev == 0 && p != ti->first)
212 return False;
213 }
214 return True;
215}
216
217DrdThreadId thread_pre_create(const DrdThreadId creator,
218 const ThreadId vg_created)
219{
220 DrdThreadId created;
221
222 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
223 created = VgThreadIdToNewDrdThreadId(vg_created);
224 tl_assert(0 <= created && created < DRD_N_THREADS
225 && created != DRD_INVALID_THREADID);
226
227 tl_assert(s_threadinfo[created].first == 0);
228 tl_assert(s_threadinfo[created].last == 0);
229 thread_append_segment(created, sg_new(creator, created));
230
231 return created;
232}
233
bart26f73e12008-02-24 18:37:08 +0000234/** Allocate the first segment for a thread. Call this just after
235 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000236 */
237DrdThreadId thread_post_create(const ThreadId vg_created)
238{
239 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
240
241 tl_assert(0 <= created && created < DRD_N_THREADS
242 && created != DRD_INVALID_THREADID);
243
244 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
245 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
246 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
247 s_threadinfo[created].stack_min_min = s_threadinfo[created].stack_max;
248 tl_assert(s_threadinfo[created].stack_max != 0);
249
250 return created;
251}
252
253/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
254/* and accesses this data structure from multiple threads without locking. */
255/* Any conflicting accesses in the range stack_startup..stack_max will be */
256/* ignored. */
257void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
258{
259#if 0
260 VG_(message)(Vg_DebugMsg, "thread_set_stack_startup: thread %d (%d)"
261 " stack 0x%x .. 0x%lx (size %d)",
262 s_threadinfo[tid].vg_threadid, tid,
263 stack_startup,
264 s_threadinfo[tid].stack_max,
265 s_threadinfo[tid].stack_max - stack_startup);
266#endif
267 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
268 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
269 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
270 s_threadinfo[tid].stack_startup = stack_startup;
271}
272
273Addr thread_get_stack_min(const DrdThreadId tid)
274{
275 tl_assert(0 <= tid && tid < DRD_N_THREADS
276 && tid != DRD_INVALID_THREADID);
277 return s_threadinfo[tid].stack_min;
278}
279
280void thread_set_stack_min(const DrdThreadId tid, const Addr stack_min)
281{
282#if 0
283 VG_(message)(Vg_DebugMsg, "thread %d (%d) stack_min = 0x%x"
284 " (size %d, max %d, delta %d)",
285 s_threadinfo[tid].vg_threadid, tid,
286 stack_min,
287 s_threadinfo[tid].stack_max - stack_min,
288 s_threadinfo[tid].stack_max - s_threadinfo[tid].stack_min_min,
289 s_threadinfo[tid].stack_min - stack_min);
290#endif
291 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
292 if (s_threadinfo[tid].stack_max)
293 {
294 s_threadinfo[tid].stack_min = stack_min;
295 if (stack_min < s_threadinfo[tid].stack_min_min)
296 {
297 s_threadinfo[tid].stack_min_min = stack_min;
298 }
299 tl_assert(s_threadinfo[tid].stack_min_min
300 <= s_threadinfo[tid].stack_min);
301 tl_assert(s_threadinfo[tid].stack_min < s_threadinfo[tid].stack_max);
302 }
303}
304
305DrdThreadId thread_lookup_stackaddr(const Addr a,
306 Addr* const stack_min,
307 Addr* const stack_max)
308{
309 unsigned i;
310 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
311 {
312 if (s_threadinfo[i].stack_min <= a && a <= s_threadinfo[i].stack_max)
313 {
314 *stack_min = s_threadinfo[i].stack_min;
315 *stack_max = s_threadinfo[i].stack_max;
316 return i;
317 }
318 }
319 return DRD_INVALID_THREADID;
320}
321
322/**
323 * Clean up thread-specific data structures. Call this just after
324 * pthread_join().
325 */
326void thread_delete(const DrdThreadId tid)
327{
328 Segment* sg;
329 Segment* sg_prev;
330
331 tl_assert(0 <= tid && tid < DRD_N_THREADS
332 && tid != DRD_INVALID_THREADID);
333 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
334 {
335 sg_prev = sg->prev;
336 sg_delete(sg);
337 }
338 s_threadinfo[tid].vg_thread_exists = False;
339 s_threadinfo[tid].posix_thread_exists = False;
340 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
341 s_threadinfo[tid].first = 0;
342 s_threadinfo[tid].last = 0;
343}
344
345/* Called after a thread performed its last memory access and before */
346/* thread_delete() is called. Note: thread_delete() is only called for */
347/* joinable threads, not for detached threads. */
348void thread_finished(const DrdThreadId tid)
349{
350 tl_assert(0 <= tid && tid < DRD_N_THREADS
351 && tid != DRD_INVALID_THREADID);
352
353 thread_stop_using_mem(s_threadinfo[tid].stack_min,
354 s_threadinfo[tid].stack_max);
355
356 s_threadinfo[tid].vg_thread_exists = False;
357
358 if (s_threadinfo[tid].detached_posix_thread)
359 {
360 /* Once a detached thread has finished, its stack is deallocated and */
361 /* should no longer be taken into account when computing the danger set*/
362 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
363
364 /* For a detached thread, calling pthread_exit() invalidates the */
365 /* POSIX thread ID associated with the detached thread. For joinable */
366 /* POSIX threads however, the POSIX thread ID remains live after the */
367 /* pthread_exit() call until pthread_join() is called. */
368 s_threadinfo[tid].posix_thread_exists = False;
369 }
370}
371
372void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
373{
374 tl_assert(0 <= tid && tid < DRD_N_THREADS
375 && tid != DRD_INVALID_THREADID);
376 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
377 tl_assert(ptid != INVALID_POSIX_THREADID);
378 s_threadinfo[tid].posix_thread_exists = True;
379 s_threadinfo[tid].pt_threadid = ptid;
380}
381
382Bool thread_get_joinable(const DrdThreadId tid)
383{
384 tl_assert(0 <= tid && tid < DRD_N_THREADS
385 && tid != DRD_INVALID_THREADID);
386 return ! s_threadinfo[tid].detached_posix_thread;
387}
388
389void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
390{
391 tl_assert(0 <= tid && tid < DRD_N_THREADS
392 && tid != DRD_INVALID_THREADID);
393 tl_assert(!! joinable == joinable);
394 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
395#if 0
396 VG_(message)(Vg_DebugMsg,
397 "thread_set_joinable(%d/%d, %s)",
398 tid,
399 s_threadinfo[tid].vg_threadid,
400 joinable ? "joinable" : "detached");
401#endif
402 s_threadinfo[tid].detached_posix_thread = ! joinable;
403}
404
405const char* thread_get_name(const DrdThreadId tid)
406{
407 tl_assert(0 <= tid && tid < DRD_N_THREADS
408 && tid != DRD_INVALID_THREADID);
409 return s_threadinfo[tid].name;
410}
411
412void thread_set_name(const DrdThreadId tid, const char* const name)
413{
414 tl_assert(0 <= tid && tid < DRD_N_THREADS
415 && tid != DRD_INVALID_THREADID);
416 VG_(strncpy)(s_threadinfo[tid].name, name,
417 sizeof(s_threadinfo[tid].name));
418 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
419}
420
421void thread_set_name_fmt(const DrdThreadId tid, const char* const fmt,
422 const UWord arg)
423{
424 tl_assert(0 <= tid && tid < DRD_N_THREADS
425 && tid != DRD_INVALID_THREADID);
426 VG_(snprintf)(s_threadinfo[tid].name, sizeof(s_threadinfo[tid].name),
427 fmt, arg);
428 s_threadinfo[tid].name[sizeof(s_threadinfo[tid].name) - 1] = 0;
429}
sewardj8b09d4f2007-12-04 21:27:18 +0000430
sewardjaf44c822007-11-25 14:01:38 +0000431DrdThreadId thread_get_running_tid(void)
432{
tom7c1a19a2008-01-02 10:13:04 +0000433 tl_assert(VG_(get_running_tid)() == s_vg_running_tid);
sewardj8b09d4f2007-12-04 21:27:18 +0000434 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
435 return s_drd_running_tid;
sewardjaf44c822007-11-25 14:01:38 +0000436}
437
sewardj8b09d4f2007-12-04 21:27:18 +0000438void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000439{
tom7c1a19a2008-01-02 10:13:04 +0000440 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000441
442 if (vg_tid != s_vg_running_tid)
443 {
444 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
445 }
446
447 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
448 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
449}
450
451void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
452{
sewardj8b09d4f2007-12-04 21:27:18 +0000453 tl_assert(vg_tid != VG_INVALID_THREADID);
454 tl_assert(drd_tid != DRD_INVALID_THREADID);
455
456 if (vg_tid != s_vg_running_tid)
457 {
bart26f73e12008-02-24 18:37:08 +0000458 if (s_trace_context_switches
459 && s_drd_running_tid != DRD_INVALID_THREADID)
460 {
461 VG_(message)(Vg_DebugMsg,
462 "Context switch from thread %d to thread %d",
463 s_drd_running_tid, drd_tid);
464 }
sewardj8b09d4f2007-12-04 21:27:18 +0000465 s_vg_running_tid = vg_tid;
466 s_drd_running_tid = drd_tid;
467 thread_update_danger_set(drd_tid);
468 s_context_switch_count++;
469 }
470
471 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
472 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000473}
474
475/**
476 * Return a pointer to the latest segment for the specified thread.
477 */
478Segment* thread_get_segment(const DrdThreadId tid)
479{
480 tl_assert(0 <= tid && tid < DRD_N_THREADS
481 && tid != DRD_INVALID_THREADID);
482 if (s_threadinfo[tid].last == 0)
483 {
484 VG_(message)(Vg_DebugMsg, "threadid = %d", tid);
485 thread_print_all();
486 }
487 tl_assert(s_threadinfo[tid].last);
488 return s_threadinfo[tid].last;
489}
490
bart26f73e12008-02-24 18:37:08 +0000491/** Append a new segment at the end of the segment list.
sewardjaf44c822007-11-25 14:01:38 +0000492 */
bart26f73e12008-02-24 18:37:08 +0000493static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000494{
495 tl_assert(0 <= tid && tid < DRD_N_THREADS
496 && tid != DRD_INVALID_THREADID);
497 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
498 sg->prev = s_threadinfo[tid].last;
499 sg->next = 0;
500 if (s_threadinfo[tid].last)
501 s_threadinfo[tid].last->next = sg;
502 s_threadinfo[tid].last = sg;
503 if (s_threadinfo[tid].first == 0)
504 s_threadinfo[tid].first = sg;
505 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
506}
507
bart26f73e12008-02-24 18:37:08 +0000508/** Remove a segment from the segment list of thread threadid, and free the
509 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000510 */
bart26f73e12008-02-24 18:37:08 +0000511static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000512{
513 tl_assert(0 <= tid && tid < DRD_N_THREADS
514 && tid != DRD_INVALID_THREADID);
515 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000516
sewardjaf44c822007-11-25 14:01:38 +0000517 if (sg->prev)
518 sg->prev->next = sg->next;
519 if (sg->next)
520 sg->next->prev = sg->prev;
521 if (sg == s_threadinfo[tid].first)
522 s_threadinfo[tid].first = sg->next;
523 if (sg == s_threadinfo[tid].last)
524 s_threadinfo[tid].last = sg->prev;
525 sg_delete(sg);
526 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
527}
528
529VectorClock* thread_get_vc(const DrdThreadId tid)
530{
531 tl_assert(0 <= tid && tid < DRD_N_THREADS
532 && tid != DRD_INVALID_THREADID);
533 tl_assert(s_threadinfo[tid].last);
534 return &s_threadinfo[tid].last->vc;
535}
536
537/**
538 * Compute the minimum of all latest vector clocks of all threads
539 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
540 * @param vc pointer to a vectorclock, holds result upon return.
541 */
542static void thread_compute_minimum_vc(VectorClock* vc)
543{
bart2cf220a2008-03-01 07:35:52 +0000544 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000545 Bool first;
546 Segment* latest_sg;
547
548 first = True;
549 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
550 {
551 latest_sg = s_threadinfo[i].last;
552 if (latest_sg)
553 {
554 if (first)
bart26f73e12008-02-24 18:37:08 +0000555 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000556 else
557 vc_min(vc, &latest_sg->vc);
558 first = False;
559 }
560 }
561}
562
563static void thread_compute_maximum_vc(VectorClock* vc)
564{
bart2cf220a2008-03-01 07:35:52 +0000565 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000566 Bool first;
567 Segment* latest_sg;
568
569 first = True;
570 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
571 {
572 latest_sg = s_threadinfo[i].last;
573 if (latest_sg)
574 {
575 if (first)
bart26f73e12008-02-24 18:37:08 +0000576 vc_assign(vc, &latest_sg->vc);
sewardjaf44c822007-11-25 14:01:38 +0000577 else
578 vc_combine(vc, &latest_sg->vc);
579 first = False;
580 }
581 }
582}
583
584/**
bart5bd9f2d2008-03-03 20:31:58 +0000585 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000586 * clock of every thread -- these segments can no longer be involved in a
587 * data race.
588 */
589static void thread_discard_ordered_segments(void)
590{
bart2cf220a2008-03-01 07:35:52 +0000591 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000592 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000593
594 s_discard_ordered_segments_count++;
595
596 vc_init(&thread_vc_min, 0, 0);
597 thread_compute_minimum_vc(&thread_vc_min);
598 if (sg_get_trace())
599 {
600 char msg[256];
601 VectorClock thread_vc_max;
602
603 vc_init(&thread_vc_max, 0, 0);
604 thread_compute_maximum_vc(&thread_vc_max);
605 VG_(snprintf)(msg, sizeof(msg),
606 "Discarding ordered segments -- min vc is ");
607 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
608 &thread_vc_min);
609 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
610 ", max vc is ");
611 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
612 &thread_vc_max);
613 VG_(message)(Vg_DebugMsg, "%s", msg);
614 vc_cleanup(&thread_vc_max);
615 }
616
617 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
618 {
619 Segment* sg;
620 Segment* sg_next;
621 for (sg = s_threadinfo[i].first;
622 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
623 sg = sg_next)
624 {
sewardjaf44c822007-11-25 14:01:38 +0000625 thread_discard_segment(i, sg);
626 }
627 }
628 vc_cleanup(&thread_vc_min);
629}
630
631/**
632 * Create a new segment for the specified thread, and report all data races
633 * of the most recent thread segment with other threads.
634 */
635void thread_new_segment(const DrdThreadId tid)
636{
sewardjaf44c822007-11-25 14:01:38 +0000637 Segment* sg;
638
639 tl_assert(0 <= tid && tid < DRD_N_THREADS
640 && tid != DRD_INVALID_THREADID);
641
sewardjaf44c822007-11-25 14:01:38 +0000642 sg = sg_new(tid, tid);
643 thread_append_segment(tid, sg);
644
645 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000646
647 if (tid == s_drd_running_tid)
648 {
649 /* Every change in the vector clock of the current thread may cause */
650 /* segments that were previously ordered to this thread to become */
651 /* unordered. Hence, recalculate the danger set if the vector clock */
652 /* of the current thread is updated. */
653 thread_update_danger_set(tid);
654 }
sewardjaf44c822007-11-25 14:01:38 +0000655}
656
bart26f73e12008-02-24 18:37:08 +0000657/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000658void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
659{
660 tl_assert(joiner != joinee);
661 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
662 && joiner != DRD_INVALID_THREADID);
663 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
664 && joinee != DRD_INVALID_THREADID);
665 tl_assert(s_threadinfo[joiner].last);
666 tl_assert(s_threadinfo[joinee].last);
667 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
668 thread_discard_ordered_segments();
669
sewardj8b09d4f2007-12-04 21:27:18 +0000670 if (joiner == s_drd_running_tid)
sewardjaf44c822007-11-25 14:01:38 +0000671 {
672 thread_update_danger_set(joiner);
673 }
674}
675
bart26f73e12008-02-24 18:37:08 +0000676/** Call this function after thread 'tid' had to wait because of thread
677 * synchronization until the memory accesses in the segment with vector clock
678 * 'vc' finished.
679 */
sewardjaf44c822007-11-25 14:01:38 +0000680void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
681{
682 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
683 tl_assert(s_threadinfo[tid].last);
684 tl_assert(vc);
685 vc_combine(&s_threadinfo[tid].last->vc, vc);
686 thread_discard_ordered_segments();
687}
688
bart26f73e12008-02-24 18:37:08 +0000689/** Call this function whenever a thread is no longer using the memory
690 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
691 * increase.
692 */
sewardjaf44c822007-11-25 14:01:38 +0000693void thread_stop_using_mem(const Addr a1, const Addr a2)
694{
695 DrdThreadId other_user = DRD_INVALID_THREADID;
696
bart26f73e12008-02-24 18:37:08 +0000697 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
sewardjaf44c822007-11-25 14:01:38 +0000698
699 unsigned i;
700 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
701 {
702 Segment* p;
703 for (p = s_threadinfo[i].first; p; p = p->next)
704 {
705 if (other_user == DRD_INVALID_THREADID
sewardj8b09d4f2007-12-04 21:27:18 +0000706 && i != s_drd_running_tid
sewardjaf44c822007-11-25 14:01:38 +0000707 && bm_has_any_access(p->bm, a1, a2))
708 {
709 other_user = i;
710 }
711 bm_clear(p->bm, a1, a2);
712 }
713 }
714
bart26f73e12008-02-24 18:37:08 +0000715 /* If any other thread had accessed memory in [ a1, a2 [, update the */
sewardjaf44c822007-11-25 14:01:38 +0000716 /* danger set. */
717 if (other_user != DRD_INVALID_THREADID
718 && bm_has_any_access(s_danger_set, a1, a2))
719 {
sewardjaf44c822007-11-25 14:01:38 +0000720 thread_update_danger_set(thread_get_running_tid());
721 }
722}
723
sewardjaf44c822007-11-25 14:01:38 +0000724void thread_print_all(void)
725{
726 unsigned i;
727 Segment* p;
728
729 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
730 {
731 if (s_threadinfo[i].first)
732 {
733 VG_(printf)("**************\n"
734 "* thread %3d (%d/%d/%d/0x%x/%d/%s) *\n"
735 "**************\n",
736 i,
737 s_threadinfo[i].vg_thread_exists,
738 s_threadinfo[i].vg_threadid,
739 s_threadinfo[i].posix_thread_exists,
740 s_threadinfo[i].pt_threadid,
741 s_threadinfo[i].detached_posix_thread,
742 s_threadinfo[i].name);
743 for (p = s_threadinfo[i].first; p; p = p->next)
744 {
745 sg_print(p);
746 }
747 }
748 }
749}
750
751static void show_call_stack(const DrdThreadId tid,
752 const Char* const msg,
753 ExeContext* const callstack)
754{
755 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
756
757 VG_(message)(Vg_UserMsg,
758 "%s (%s)",
759 msg,
760 thread_get_name(tid));
761
762 if (vg_tid != VG_INVALID_THREADID)
763 {
764 if (callstack)
765 {
766 VG_(pp_ExeContext)(callstack);
767 }
768 else
769 {
770 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
771 }
772 }
773 else
774 {
775 VG_(message)(Vg_UserMsg,
776 " (thread finished, call stack no longer available)");
777 }
778}
779
sewardjaf44c822007-11-25 14:01:38 +0000780static void
781thread_report_conflicting_segments_segment(const DrdThreadId tid,
782 const Addr addr,
783 const SizeT size,
784 const BmAccessTypeT access_type,
785 const Segment* const p)
786{
787 unsigned i;
788
789 tl_assert(0 <= tid && tid < DRD_N_THREADS
790 && tid != DRD_INVALID_THREADID);
791 tl_assert(p);
792
793 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
794 {
795 if (i != tid)
796 {
797 Segment* q;
798 for (q = s_threadinfo[i].last; q; q = q->prev)
799 {
800 // Since q iterates over the segments of thread i in order of
801 // decreasing vector clocks, if q->vc <= p->vc, then
802 // q->next->vc <= p->vc will also hold. Hence, break out of the
803 // loop once this condition is met.
804 if (vc_lte(&q->vc, &p->vc))
805 break;
806 if (! vc_lte(&p->vc, &q->vc))
807 {
808 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
809 {
810 tl_assert(q->stacktrace);
811 show_call_stack(i, "Other segment start",
812 q->stacktrace);
813 show_call_stack(i, "Other segment end",
814 q->next ? q->next->stacktrace : 0);
815 }
816 }
817 }
818 }
819 }
820}
821
822void thread_report_conflicting_segments(const DrdThreadId tid,
823 const Addr addr,
824 const SizeT size,
825 const BmAccessTypeT access_type)
826{
827 Segment* p;
828
829 tl_assert(0 <= tid && tid < DRD_N_THREADS
830 && tid != DRD_INVALID_THREADID);
831
832 for (p = s_threadinfo[tid].first; p; p = p->next)
833 {
834 if (bm_has(p->bm, addr, addr + size, access_type))
835 {
836 thread_report_conflicting_segments_segment(tid, addr, size,
837 access_type, p);
838 }
839 }
840}
sewardjaf44c822007-11-25 14:01:38 +0000841
bart26f73e12008-02-24 18:37:08 +0000842/** Compute a bitmap that represents the union of all memory accesses of all
843 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000844 */
845static void thread_update_danger_set(const DrdThreadId tid)
846{
847 Segment* p;
848
bart26f73e12008-02-24 18:37:08 +0000849 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000850 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000851
852 s_update_danger_set_count++;
853 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
854 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
855
sewardjaf44c822007-11-25 14:01:38 +0000856 if (s_danger_set)
857 {
858 bm_clear_all(s_danger_set);
859 }
860 else
861 {
862 s_danger_set = bm_new();
863 }
bart26f73e12008-02-24 18:37:08 +0000864
865 if (s_trace_danger_set)
866 {
867 char msg[256];
868
869 VG_(snprintf)(msg, sizeof(msg),
870 "computing danger set for thread %d with vc ",
871 tid);
872 vc_snprint(msg + VG_(strlen)(msg),
873 sizeof(msg) - VG_(strlen)(msg),
874 &s_threadinfo[tid].last->vc);
875 VG_(message)(Vg_DebugMsg, "%s", msg);
876 }
sewardjaf44c822007-11-25 14:01:38 +0000877
bart5bd9f2d2008-03-03 20:31:58 +0000878 p = s_threadinfo[tid].last;
sewardjaf44c822007-11-25 14:01:38 +0000879 {
880 unsigned j;
881
bart26f73e12008-02-24 18:37:08 +0000882 if (s_trace_danger_set)
883 {
884 char msg[256];
885
886 VG_(snprintf)(msg, sizeof(msg),
887 "danger set: thread [%d] at vc ",
888 tid);
889 vc_snprint(msg + VG_(strlen)(msg),
890 sizeof(msg) - VG_(strlen)(msg),
891 &p->vc);
892 VG_(message)(Vg_DebugMsg, "%s", msg);
893 }
894
sewardjaf44c822007-11-25 14:01:38 +0000895 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
896 {
897 if (IsValidDrdThreadId(j))
898 {
bart5bd9f2d2008-03-03 20:31:58 +0000899 const Segment* q;
900 for (q = s_threadinfo[j].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000901 if (j != tid && q != 0
902 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
903 {
bart26f73e12008-02-24 18:37:08 +0000904 if (s_trace_danger_set)
905 {
906 char msg[256];
907 VG_(snprintf)(msg, sizeof(msg),
908 "danger set: [%d] merging segment ", j);
909 vc_snprint(msg + VG_(strlen)(msg),
910 sizeof(msg) - VG_(strlen)(msg),
911 &q->vc);
912 VG_(message)(Vg_DebugMsg, "%s", msg);
913 }
sewardjaf44c822007-11-25 14:01:38 +0000914 bm_merge2(s_danger_set, q->bm);
915 }
bart26f73e12008-02-24 18:37:08 +0000916 else
917 {
918 if (s_trace_danger_set)
919 {
920 char msg[256];
921 VG_(snprintf)(msg, sizeof(msg),
922 "danger set: [%d] ignoring segment ", j);
923 vc_snprint(msg + VG_(strlen)(msg),
924 sizeof(msg) - VG_(strlen)(msg),
925 &q->vc);
926 VG_(message)(Vg_DebugMsg, "%s", msg);
927 }
928 }
sewardjaf44c822007-11-25 14:01:38 +0000929 }
930 }
931
932 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
933 {
934 if (IsValidDrdThreadId(j))
935 {
936 // NPTL hack: don't report data races on sizeof(struct pthread)
937 // bytes at the top of the stack, since the NPTL functions access
938 // this data without locking.
939 if (s_threadinfo[j].stack_min != 0)
940 {
941 tl_assert(s_threadinfo[j].stack_startup != 0);
942 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
943 {
944 bm_clear(s_danger_set,
945 s_threadinfo[j].stack_min,
946 s_threadinfo[j].stack_startup);
947 }
948 }
949 }
950 }
951 }
952
953 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
954 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
955
bart26f73e12008-02-24 18:37:08 +0000956 if (0 && s_trace_danger_set)
957 {
958 VG_(message)(Vg_DebugMsg, "[%d] new danger set:", tid);
959 bm_print(s_danger_set);
960 VG_(message)(Vg_DebugMsg, "[%d] end of new danger set.", tid);
961 }
sewardjaf44c822007-11-25 14:01:38 +0000962}
963
964Bool thread_conflicting_access(const Addr a,
965 const SizeT size,
966 const BmAccessTypeT access_type)
967{
968 tl_assert(s_danger_set);
969 return (bm_has_conflict_with(s_danger_set, a, a + size, access_type)
970 && ! drd_is_suppressed(a, a + size));
971}
972
973ULong thread_get_context_switch_count(void)
974{
975 return s_context_switch_count;
976}
977
sewardjaf44c822007-11-25 14:01:38 +0000978ULong thread_get_discard_ordered_segments_count(void)
979{
980 return s_discard_ordered_segments_count;
981}
982
983ULong thread_get_update_danger_set_count(void)
984{
985 return s_update_danger_set_count;
986}
987
988ULong thread_get_danger_set_bitmap_creation_count(void)
989{
990 return s_danger_set_bitmap_creation_count;
991}
992
993ULong thread_get_danger_set_bitmap2_creation_count(void)
994{
995 return s_danger_set_bitmap2_creation_count;
996}
997
998/*
999 * Local variables:
1000 * c-basic-offset: 3
1001 * End:
1002 */