blob: dc598183521856b7fec8e16c91241cdfcaf30c01 [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
sewardjaf44c822007-11-25 14:01:38 +000041// Local functions.
42
43static void thread_append_segment(const DrdThreadId tid,
44 Segment* const sg);
45static void thread_update_danger_set(const DrdThreadId tid);
46
47
48// Local variables.
49
50static ULong s_context_switch_count;
51static ULong s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +000052static ULong s_update_danger_set_count;
53static ULong s_danger_set_bitmap_creation_count;
54static ULong s_danger_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000055static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
bartf00a85b2008-03-13 18:49:23 +000056DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
57ThreadInfo s_threadinfo[DRD_N_THREADS];
bart1a473c72008-03-13 19:03:38 +000058struct bitmap* s_danger_set;
bart26f73e12008-02-24 18:37:08 +000059static Bool s_trace_context_switches = False;
60static Bool s_trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000061
62
63// Function definitions.
64
bart26f73e12008-02-24 18:37:08 +000065void thread_trace_context_switches(const Bool t)
66{
bart3772a982008-03-15 08:11:03 +000067 s_trace_context_switches = t;
bart26f73e12008-02-24 18:37:08 +000068}
69
70void thread_trace_danger_set(const Bool t)
71{
bart3772a982008-03-15 08:11:03 +000072 s_trace_danger_set = t;
bart26f73e12008-02-24 18:37:08 +000073}
74
sewardjaf44c822007-11-25 14:01:38 +000075__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
76{
bart3772a982008-03-15 08:11:03 +000077 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
78 && ! (s_threadinfo[tid].vg_thread_exists == False
79 && s_threadinfo[tid].posix_thread_exists == False
80 && s_threadinfo[tid].detached_posix_thread == False));
sewardjaf44c822007-11-25 14:01:38 +000081}
82
83/**
84 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
85 * Valgrind's ThreadId does not yet exist.
86 **/
87DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
88{
bart3772a982008-03-15 08:11:03 +000089 int i;
sewardjaf44c822007-11-25 14:01:38 +000090
bart3772a982008-03-15 08:11:03 +000091 if (tid == VG_INVALID_THREADID)
92 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +000093
bart3772a982008-03-15 08:11:03 +000094 for (i = 1; i < DRD_N_THREADS; i++)
95 {
96 if (s_threadinfo[i].vg_thread_exists == True
97 && s_threadinfo[i].vg_threadid == tid)
98 {
99 return i;
100 }
101 }
sewardjaf44c822007-11-25 14:01:38 +0000102
bart3772a982008-03-15 08:11:03 +0000103 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000104}
105
106static
107DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
108{
bart3772a982008-03-15 08:11:03 +0000109 int i;
sewardjaf44c822007-11-25 14:01:38 +0000110
bart3772a982008-03-15 08:11:03 +0000111 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000112
bart3772a982008-03-15 08:11:03 +0000113 for (i = 1; i < DRD_N_THREADS; i++)
114 {
115 if (s_threadinfo[i].vg_thread_exists == False
116 && s_threadinfo[i].posix_thread_exists == False
117 && s_threadinfo[i].detached_posix_thread == False)
118 {
119 s_threadinfo[i].vg_thread_exists = True;
120 s_threadinfo[i].vg_threadid = tid;
121 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
bart3772a982008-03-15 08:11:03 +0000122 s_threadinfo[i].stack_min = 0;
123 s_threadinfo[i].stack_startup = 0;
124 s_threadinfo[i].stack_max = 0;
bart3772a982008-03-15 08:11:03 +0000125 s_threadinfo[i].is_recording = True;
126 s_threadinfo[i].synchr_nesting = 0;
127 if (s_threadinfo[i].first != 0)
128 VG_(printf)("drd thread id = %d\n", i);
129 tl_assert(s_threadinfo[i].first == 0);
130 tl_assert(s_threadinfo[i].last == 0);
131 return i;
132 }
133 }
sewardjaf44c822007-11-25 14:01:38 +0000134
bart3772a982008-03-15 08:11:03 +0000135 tl_assert(False);
sewardjaf44c822007-11-25 14:01:38 +0000136
bart3772a982008-03-15 08:11:03 +0000137 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000138}
139
140DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
141{
bart3772a982008-03-15 08:11:03 +0000142 int i;
sewardjaf44c822007-11-25 14:01:38 +0000143
bart3772a982008-03-15 08:11:03 +0000144 tl_assert(tid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000145
bart3772a982008-03-15 08:11:03 +0000146 for (i = 1; i < DRD_N_THREADS; i++)
147 {
148 if (s_threadinfo[i].posix_thread_exists
149 && s_threadinfo[i].pt_threadid == tid)
150 {
151 return i;
152 }
153 }
154 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000155}
156
157ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
158{
bart3772a982008-03-15 08:11:03 +0000159 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
160 return (s_threadinfo[tid].vg_thread_exists
161 ? s_threadinfo[tid].vg_threadid
162 : VG_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000163}
164
bart26f73e12008-02-24 18:37:08 +0000165/** Sanity check of the doubly linked list of segments referenced by a
166 * ThreadInfo struct.
167 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000168 */
169static Bool sane_ThreadInfo(const ThreadInfo* const ti)
170{
bart3772a982008-03-15 08:11:03 +0000171 Segment* p;
172 for (p = ti->first; p; p = p->next) {
173 if (p->next && p->next->prev != p)
174 return False;
175 if (p->next == 0 && p != ti->last)
176 return False;
177 }
178 for (p = ti->last; p; p = p->prev) {
179 if (p->prev && p->prev->next != p)
180 return False;
181 if (p->prev == 0 && p != ti->first)
182 return False;
183 }
184 return True;
sewardjaf44c822007-11-25 14:01:38 +0000185}
186
187DrdThreadId thread_pre_create(const DrdThreadId creator,
188 const ThreadId vg_created)
189{
bart3772a982008-03-15 08:11:03 +0000190 DrdThreadId created;
sewardjaf44c822007-11-25 14:01:38 +0000191
bart3772a982008-03-15 08:11:03 +0000192 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
193 created = VgThreadIdToNewDrdThreadId(vg_created);
194 tl_assert(0 <= created && created < DRD_N_THREADS
195 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000196
bart3772a982008-03-15 08:11:03 +0000197 tl_assert(s_threadinfo[created].first == 0);
198 tl_assert(s_threadinfo[created].last == 0);
199 thread_append_segment(created, sg_new(creator, created));
sewardjaf44c822007-11-25 14:01:38 +0000200
bart3772a982008-03-15 08:11:03 +0000201 return created;
sewardjaf44c822007-11-25 14:01:38 +0000202}
203
bart26f73e12008-02-24 18:37:08 +0000204/** Allocate the first segment for a thread. Call this just after
205 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000206 */
207DrdThreadId thread_post_create(const ThreadId vg_created)
208{
bart3772a982008-03-15 08:11:03 +0000209 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
sewardjaf44c822007-11-25 14:01:38 +0000210
bart3772a982008-03-15 08:11:03 +0000211 tl_assert(0 <= created && created < DRD_N_THREADS
212 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000213
bart3772a982008-03-15 08:11:03 +0000214 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
215 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
216 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
bart3772a982008-03-15 08:11:03 +0000217 tl_assert(s_threadinfo[created].stack_max != 0);
sewardjaf44c822007-11-25 14:01:38 +0000218
bart3772a982008-03-15 08:11:03 +0000219 return created;
sewardjaf44c822007-11-25 14:01:38 +0000220}
221
222/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
223/* and accesses this data structure from multiple threads without locking. */
224/* Any conflicting accesses in the range stack_startup..stack_max will be */
225/* ignored. */
226void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
227{
228#if 0
bart3772a982008-03-15 08:11:03 +0000229 VG_(message)(Vg_DebugMsg, "thread_set_stack_startup: thread %d (%d)"
230 " stack 0x%x .. 0x%lx (size %d)",
231 s_threadinfo[tid].vg_threadid, tid,
232 stack_startup,
233 s_threadinfo[tid].stack_max,
234 s_threadinfo[tid].stack_max - stack_startup);
sewardjaf44c822007-11-25 14:01:38 +0000235#endif
bart3772a982008-03-15 08:11:03 +0000236 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
237 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
238 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
239 s_threadinfo[tid].stack_startup = stack_startup;
sewardjaf44c822007-11-25 14:01:38 +0000240}
241
242Addr thread_get_stack_min(const DrdThreadId tid)
243{
bart3772a982008-03-15 08:11:03 +0000244 tl_assert(0 <= tid && tid < DRD_N_THREADS
245 && tid != DRD_INVALID_THREADID);
246 return s_threadinfo[tid].stack_min;
sewardjaf44c822007-11-25 14:01:38 +0000247}
248
sewardjaf44c822007-11-25 14:01:38 +0000249DrdThreadId thread_lookup_stackaddr(const Addr a,
250 Addr* const stack_min,
251 Addr* const stack_max)
252{
bart3772a982008-03-15 08:11:03 +0000253 unsigned i;
254 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
255 {
256 if (s_threadinfo[i].stack_min <= a && a <= s_threadinfo[i].stack_max)
257 {
258 *stack_min = s_threadinfo[i].stack_min;
259 *stack_max = s_threadinfo[i].stack_max;
260 return i;
261 }
262 }
263 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000264}
265
266/**
267 * Clean up thread-specific data structures. Call this just after
268 * pthread_join().
269 */
270void thread_delete(const DrdThreadId tid)
271{
bart3772a982008-03-15 08:11:03 +0000272 Segment* sg;
273 Segment* sg_prev;
sewardjaf44c822007-11-25 14:01:38 +0000274
bart3772a982008-03-15 08:11:03 +0000275 tl_assert(0 <= tid && tid < DRD_N_THREADS
276 && tid != DRD_INVALID_THREADID);
277 tl_assert(s_threadinfo[tid].synchr_nesting == 0);
278 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
279 {
280 sg_prev = sg->prev;
281 sg_delete(sg);
282 }
283 s_threadinfo[tid].vg_thread_exists = False;
284 s_threadinfo[tid].posix_thread_exists = False;
285 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
286 s_threadinfo[tid].first = 0;
287 s_threadinfo[tid].last = 0;
sewardjaf44c822007-11-25 14:01:38 +0000288}
289
290/* Called after a thread performed its last memory access and before */
291/* thread_delete() is called. Note: thread_delete() is only called for */
292/* joinable threads, not for detached threads. */
293void thread_finished(const DrdThreadId tid)
294{
bart3772a982008-03-15 08:11:03 +0000295 tl_assert(0 <= tid && tid < DRD_N_THREADS
296 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000297
bart3772a982008-03-15 08:11:03 +0000298 thread_stop_using_mem(s_threadinfo[tid].stack_min,
299 s_threadinfo[tid].stack_max);
sewardjaf44c822007-11-25 14:01:38 +0000300
bart3772a982008-03-15 08:11:03 +0000301 s_threadinfo[tid].vg_thread_exists = False;
sewardjaf44c822007-11-25 14:01:38 +0000302
bart3772a982008-03-15 08:11:03 +0000303 if (s_threadinfo[tid].detached_posix_thread)
304 {
305 /* Once a detached thread has finished, its stack is deallocated and */
306 /* should no longer be taken into account when computing the danger set*/
307 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000308
bart3772a982008-03-15 08:11:03 +0000309 /* For a detached thread, calling pthread_exit() invalidates the */
310 /* POSIX thread ID associated with the detached thread. For joinable */
311 /* POSIX threads however, the POSIX thread ID remains live after the */
312 /* pthread_exit() call until pthread_join() is called. */
313 s_threadinfo[tid].posix_thread_exists = False;
314 }
sewardjaf44c822007-11-25 14:01:38 +0000315}
316
317void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
318{
bart3772a982008-03-15 08:11:03 +0000319 tl_assert(0 <= tid && tid < DRD_N_THREADS
320 && tid != DRD_INVALID_THREADID);
321 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
322 tl_assert(ptid != INVALID_POSIX_THREADID);
323 s_threadinfo[tid].posix_thread_exists = True;
324 s_threadinfo[tid].pt_threadid = ptid;
sewardjaf44c822007-11-25 14:01:38 +0000325}
326
327Bool thread_get_joinable(const DrdThreadId tid)
328{
bart3772a982008-03-15 08:11:03 +0000329 tl_assert(0 <= tid && tid < DRD_N_THREADS
330 && tid != DRD_INVALID_THREADID);
331 return ! s_threadinfo[tid].detached_posix_thread;
sewardjaf44c822007-11-25 14:01:38 +0000332}
333
334void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
335{
bart3772a982008-03-15 08:11:03 +0000336 tl_assert(0 <= tid && tid < DRD_N_THREADS
337 && tid != DRD_INVALID_THREADID);
338 tl_assert(!! joinable == joinable);
339 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000340#if 0
bart3772a982008-03-15 08:11:03 +0000341 VG_(message)(Vg_DebugMsg,
342 "thread_set_joinable(%d/%d, %s)",
343 tid,
344 s_threadinfo[tid].vg_threadid,
345 joinable ? "joinable" : "detached");
sewardjaf44c822007-11-25 14:01:38 +0000346#endif
bart3772a982008-03-15 08:11:03 +0000347 s_threadinfo[tid].detached_posix_thread = ! joinable;
sewardjaf44c822007-11-25 14:01:38 +0000348}
349
sewardj8b09d4f2007-12-04 21:27:18 +0000350void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000351{
bart3772a982008-03-15 08:11:03 +0000352 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000353
bart3772a982008-03-15 08:11:03 +0000354 if (vg_tid != s_vg_running_tid)
355 {
356 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
357 }
sewardj8b09d4f2007-12-04 21:27:18 +0000358
bart3772a982008-03-15 08:11:03 +0000359 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
360 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000361}
362
363void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
364{
bart3772a982008-03-15 08:11:03 +0000365 tl_assert(vg_tid != VG_INVALID_THREADID);
366 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000367
bart3772a982008-03-15 08:11:03 +0000368 if (vg_tid != s_vg_running_tid)
369 {
370 if (s_trace_context_switches
371 && s_drd_running_tid != DRD_INVALID_THREADID)
372 {
373 VG_(message)(Vg_DebugMsg,
374 "Context switch from thread %d to thread %d",
375 s_drd_running_tid, drd_tid);
376 }
377 s_vg_running_tid = vg_tid;
378 s_drd_running_tid = drd_tid;
379 thread_update_danger_set(drd_tid);
380 s_context_switch_count++;
381 }
sewardj8b09d4f2007-12-04 21:27:18 +0000382
bart3772a982008-03-15 08:11:03 +0000383 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
384 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000385}
386
bart0268dfa2008-03-11 20:10:21 +0000387int thread_enter_synchr(const DrdThreadId tid)
388{
bart3772a982008-03-15 08:11:03 +0000389 tl_assert(IsValidDrdThreadId(tid));
390 return s_threadinfo[tid].synchr_nesting++;
bart0268dfa2008-03-11 20:10:21 +0000391}
392
393int thread_leave_synchr(const DrdThreadId tid)
394{
bart3772a982008-03-15 08:11:03 +0000395 tl_assert(IsValidDrdThreadId(tid));
396 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
397 return --s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000398}
399
400int thread_get_synchr_nesting_count(const DrdThreadId tid)
401{
bart3772a982008-03-15 08:11:03 +0000402 tl_assert(IsValidDrdThreadId(tid));
403 return s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000404}
405
bart1a473c72008-03-13 19:03:38 +0000406/** Append a new segment at the end of the segment list. */
bart26f73e12008-02-24 18:37:08 +0000407static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000408{
bart3772a982008-03-15 08:11:03 +0000409 tl_assert(0 <= tid && tid < DRD_N_THREADS
410 && tid != DRD_INVALID_THREADID);
411 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
412 sg->prev = s_threadinfo[tid].last;
413 sg->next = 0;
414 if (s_threadinfo[tid].last)
415 s_threadinfo[tid].last->next = sg;
416 s_threadinfo[tid].last = sg;
417 if (s_threadinfo[tid].first == 0)
418 s_threadinfo[tid].first = sg;
419 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000420}
421
bart26f73e12008-02-24 18:37:08 +0000422/** Remove a segment from the segment list of thread threadid, and free the
423 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000424 */
bart26f73e12008-02-24 18:37:08 +0000425static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000426{
bart3772a982008-03-15 08:11:03 +0000427 tl_assert(0 <= tid && tid < DRD_N_THREADS
428 && tid != DRD_INVALID_THREADID);
429 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000430
bart3772a982008-03-15 08:11:03 +0000431 if (sg->prev)
432 sg->prev->next = sg->next;
433 if (sg->next)
434 sg->next->prev = sg->prev;
435 if (sg == s_threadinfo[tid].first)
436 s_threadinfo[tid].first = sg->next;
437 if (sg == s_threadinfo[tid].last)
438 s_threadinfo[tid].last = sg->prev;
439 sg_delete(sg);
440 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000441}
442
443VectorClock* thread_get_vc(const DrdThreadId tid)
444{
bart3772a982008-03-15 08:11:03 +0000445 tl_assert(0 <= tid && tid < DRD_N_THREADS
446 && tid != DRD_INVALID_THREADID);
447 tl_assert(s_threadinfo[tid].last);
448 return &s_threadinfo[tid].last->vc;
sewardjaf44c822007-11-25 14:01:38 +0000449}
450
451/**
452 * Compute the minimum of all latest vector clocks of all threads
453 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
454 * @param vc pointer to a vectorclock, holds result upon return.
455 */
456static void thread_compute_minimum_vc(VectorClock* vc)
457{
bart3772a982008-03-15 08:11:03 +0000458 unsigned i;
459 Bool first;
460 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000461
bart3772a982008-03-15 08:11:03 +0000462 first = True;
463 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
464 {
465 latest_sg = s_threadinfo[i].last;
466 if (latest_sg)
467 {
468 if (first)
469 vc_assign(vc, &latest_sg->vc);
470 else
471 vc_min(vc, &latest_sg->vc);
472 first = False;
473 }
474 }
sewardjaf44c822007-11-25 14:01:38 +0000475}
476
477static void thread_compute_maximum_vc(VectorClock* vc)
478{
bart3772a982008-03-15 08:11:03 +0000479 unsigned i;
480 Bool first;
481 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000482
bart3772a982008-03-15 08:11:03 +0000483 first = True;
484 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
485 {
486 latest_sg = s_threadinfo[i].last;
487 if (latest_sg)
488 {
489 if (first)
490 vc_assign(vc, &latest_sg->vc);
491 else
492 vc_combine(vc, &latest_sg->vc);
493 first = False;
494 }
495 }
sewardjaf44c822007-11-25 14:01:38 +0000496}
497
498/**
bart5bd9f2d2008-03-03 20:31:58 +0000499 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000500 * clock of every thread -- these segments can no longer be involved in a
501 * data race.
502 */
503static void thread_discard_ordered_segments(void)
504{
bart3772a982008-03-15 08:11:03 +0000505 unsigned i;
506 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000507
bart3772a982008-03-15 08:11:03 +0000508 s_discard_ordered_segments_count++;
sewardjaf44c822007-11-25 14:01:38 +0000509
bart3772a982008-03-15 08:11:03 +0000510 vc_init(&thread_vc_min, 0, 0);
511 thread_compute_minimum_vc(&thread_vc_min);
512 if (sg_get_trace())
513 {
514 char msg[256];
515 VectorClock thread_vc_max;
sewardjaf44c822007-11-25 14:01:38 +0000516
bart3772a982008-03-15 08:11:03 +0000517 vc_init(&thread_vc_max, 0, 0);
518 thread_compute_maximum_vc(&thread_vc_max);
519 VG_(snprintf)(msg, sizeof(msg),
520 "Discarding ordered segments -- min vc is ");
521 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
522 &thread_vc_min);
523 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
524 ", max vc is ");
525 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
526 &thread_vc_max);
527 VG_(message)(Vg_DebugMsg, "%s", msg);
528 vc_cleanup(&thread_vc_max);
529 }
sewardjaf44c822007-11-25 14:01:38 +0000530
bart3772a982008-03-15 08:11:03 +0000531 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
532 {
533 Segment* sg;
534 Segment* sg_next;
535 for (sg = s_threadinfo[i].first;
536 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
537 sg = sg_next)
538 {
539 thread_discard_segment(i, sg);
540 }
541 }
542 vc_cleanup(&thread_vc_min);
sewardjaf44c822007-11-25 14:01:38 +0000543}
544
545/**
546 * Create a new segment for the specified thread, and report all data races
547 * of the most recent thread segment with other threads.
548 */
549void thread_new_segment(const DrdThreadId tid)
550{
bart3772a982008-03-15 08:11:03 +0000551 Segment* sg;
sewardjaf44c822007-11-25 14:01:38 +0000552
bart3772a982008-03-15 08:11:03 +0000553 tl_assert(0 <= tid && tid < DRD_N_THREADS
554 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000555
bart3772a982008-03-15 08:11:03 +0000556 sg = sg_new(tid, tid);
557 thread_append_segment(tid, sg);
sewardjaf44c822007-11-25 14:01:38 +0000558
bart3772a982008-03-15 08:11:03 +0000559 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000560
bart3772a982008-03-15 08:11:03 +0000561 if (tid == s_drd_running_tid)
562 {
563 /* Every change in the vector clock of the current thread may cause */
564 /* segments that were previously ordered to this thread to become */
565 /* unordered. Hence, recalculate the danger set if the vector clock */
566 /* of the current thread is updated. */
567 thread_update_danger_set(tid);
568 }
sewardjaf44c822007-11-25 14:01:38 +0000569}
570
bart26f73e12008-02-24 18:37:08 +0000571/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000572void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
573{
bart3772a982008-03-15 08:11:03 +0000574 tl_assert(joiner != joinee);
575 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
576 && joiner != DRD_INVALID_THREADID);
577 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
578 && joinee != DRD_INVALID_THREADID);
579 tl_assert(s_threadinfo[joiner].last);
580 tl_assert(s_threadinfo[joinee].last);
581 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
582 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000583
bart3772a982008-03-15 08:11:03 +0000584 if (joiner == s_drd_running_tid)
585 {
586 thread_update_danger_set(joiner);
587 }
sewardjaf44c822007-11-25 14:01:38 +0000588}
589
bart26f73e12008-02-24 18:37:08 +0000590/** Call this function after thread 'tid' had to wait because of thread
591 * synchronization until the memory accesses in the segment with vector clock
592 * 'vc' finished.
593 */
sewardjaf44c822007-11-25 14:01:38 +0000594void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
595{
bart3772a982008-03-15 08:11:03 +0000596 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
597 tl_assert(s_threadinfo[tid].last);
598 tl_assert(vc);
599 vc_combine(&s_threadinfo[tid].last->vc, vc);
600 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000601}
602
bart26f73e12008-02-24 18:37:08 +0000603/** Call this function whenever a thread is no longer using the memory
604 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
605 * increase.
606 */
sewardjaf44c822007-11-25 14:01:38 +0000607void thread_stop_using_mem(const Addr a1, const Addr a2)
608{
bart3772a982008-03-15 08:11:03 +0000609 DrdThreadId other_user = DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000610
bart3772a982008-03-15 08:11:03 +0000611 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
sewardjaf44c822007-11-25 14:01:38 +0000612
bart3772a982008-03-15 08:11:03 +0000613 unsigned i;
614 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
615 {
616 Segment* p;
617 for (p = s_threadinfo[i].first; p; p = p->next)
618 {
619 if (other_user == DRD_INVALID_THREADID
620 && i != s_drd_running_tid
621 && bm_has_any_access(p->bm, a1, a2))
sewardjaf44c822007-11-25 14:01:38 +0000622 {
bart3772a982008-03-15 08:11:03 +0000623 other_user = i;
sewardjaf44c822007-11-25 14:01:38 +0000624 }
bart3772a982008-03-15 08:11:03 +0000625 bm_clear(p->bm, a1, a2);
626 }
627 }
sewardjaf44c822007-11-25 14:01:38 +0000628
bart3772a982008-03-15 08:11:03 +0000629 /* If any other thread had accessed memory in [ a1, a2 [, update the */
630 /* danger set. */
631 if (other_user != DRD_INVALID_THREADID
632 && bm_has_any_access(s_danger_set, a1, a2))
633 {
634 thread_update_danger_set(thread_get_running_tid());
635 }
sewardjaf44c822007-11-25 14:01:38 +0000636}
637
bart0268dfa2008-03-11 20:10:21 +0000638void thread_start_recording(const DrdThreadId tid)
639{
bart3772a982008-03-15 08:11:03 +0000640 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
641 tl_assert(! s_threadinfo[tid].is_recording);
642 s_threadinfo[tid].is_recording = True;
bart0268dfa2008-03-11 20:10:21 +0000643}
644
645void thread_stop_recording(const DrdThreadId tid)
646{
bart3772a982008-03-15 08:11:03 +0000647 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
648 tl_assert(s_threadinfo[tid].is_recording);
649 s_threadinfo[tid].is_recording = False;
bart0268dfa2008-03-11 20:10:21 +0000650}
651
sewardjaf44c822007-11-25 14:01:38 +0000652void thread_print_all(void)
653{
bart3772a982008-03-15 08:11:03 +0000654 unsigned i;
655 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000656
bart3772a982008-03-15 08:11:03 +0000657 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
658 {
659 if (s_threadinfo[i].first)
660 {
661 VG_(printf)("**************\n"
bart354009c2008-03-16 10:42:33 +0000662 "* thread %3d (%d/%d/%d/0x%x/%d) *\n"
bart3772a982008-03-15 08:11:03 +0000663 "**************\n",
664 i,
665 s_threadinfo[i].vg_thread_exists,
666 s_threadinfo[i].vg_threadid,
667 s_threadinfo[i].posix_thread_exists,
668 s_threadinfo[i].pt_threadid,
bart354009c2008-03-16 10:42:33 +0000669 s_threadinfo[i].detached_posix_thread);
bart3772a982008-03-15 08:11:03 +0000670 for (p = s_threadinfo[i].first; p; p = p->next)
sewardjaf44c822007-11-25 14:01:38 +0000671 {
bart3772a982008-03-15 08:11:03 +0000672 sg_print(p);
sewardjaf44c822007-11-25 14:01:38 +0000673 }
bart3772a982008-03-15 08:11:03 +0000674 }
675 }
sewardjaf44c822007-11-25 14:01:38 +0000676}
677
678static void show_call_stack(const DrdThreadId tid,
679 const Char* const msg,
680 ExeContext* const callstack)
681{
bart3772a982008-03-15 08:11:03 +0000682 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000683
bart354009c2008-03-16 10:42:33 +0000684 VG_(message)(Vg_UserMsg, "%s (thread %d)", msg, tid);
sewardjaf44c822007-11-25 14:01:38 +0000685
bart3772a982008-03-15 08:11:03 +0000686 if (vg_tid != VG_INVALID_THREADID)
687 {
688 if (callstack)
689 {
690 VG_(pp_ExeContext)(callstack);
691 }
692 else
693 {
694 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
695 }
696 }
697 else
698 {
699 VG_(message)(Vg_UserMsg,
700 " (thread finished, call stack no longer available)");
701 }
sewardjaf44c822007-11-25 14:01:38 +0000702}
703
sewardjaf44c822007-11-25 14:01:38 +0000704static void
705thread_report_conflicting_segments_segment(const DrdThreadId tid,
706 const Addr addr,
707 const SizeT size,
708 const BmAccessTypeT access_type,
709 const Segment* const p)
710{
bart3772a982008-03-15 08:11:03 +0000711 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000712
bart3772a982008-03-15 08:11:03 +0000713 tl_assert(0 <= tid && tid < DRD_N_THREADS
714 && tid != DRD_INVALID_THREADID);
715 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000716
bart3772a982008-03-15 08:11:03 +0000717 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
718 {
719 if (i != tid)
720 {
721 Segment* q;
722 for (q = s_threadinfo[i].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000723 {
bart3772a982008-03-15 08:11:03 +0000724 // Since q iterates over the segments of thread i in order of
725 // decreasing vector clocks, if q->vc <= p->vc, then
726 // q->next->vc <= p->vc will also hold. Hence, break out of the
727 // loop once this condition is met.
728 if (vc_lte(&q->vc, &p->vc))
729 break;
730 if (! vc_lte(&p->vc, &q->vc))
731 {
732 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
733 {
734 tl_assert(q->stacktrace);
735 show_call_stack(i, "Other segment start",
736 q->stacktrace);
737 show_call_stack(i, "Other segment end",
738 q->next ? q->next->stacktrace : 0);
739 }
740 }
sewardjaf44c822007-11-25 14:01:38 +0000741 }
bart3772a982008-03-15 08:11:03 +0000742 }
743 }
sewardjaf44c822007-11-25 14:01:38 +0000744}
745
746void thread_report_conflicting_segments(const DrdThreadId tid,
747 const Addr addr,
748 const SizeT size,
749 const BmAccessTypeT access_type)
750{
bart3772a982008-03-15 08:11:03 +0000751 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000752
bart3772a982008-03-15 08:11:03 +0000753 tl_assert(0 <= tid && tid < DRD_N_THREADS
754 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000755
bart3772a982008-03-15 08:11:03 +0000756 for (p = s_threadinfo[tid].first; p; p = p->next)
757 {
758 if (bm_has(p->bm, addr, addr + size, access_type))
759 {
760 thread_report_conflicting_segments_segment(tid, addr, size,
761 access_type, p);
762 }
763 }
sewardjaf44c822007-11-25 14:01:38 +0000764}
sewardjaf44c822007-11-25 14:01:38 +0000765
bart26f73e12008-02-24 18:37:08 +0000766/** Compute a bitmap that represents the union of all memory accesses of all
767 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000768 */
769static void thread_update_danger_set(const DrdThreadId tid)
770{
bart3772a982008-03-15 08:11:03 +0000771 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000772
bart3772a982008-03-15 08:11:03 +0000773 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
774 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000775
bart3772a982008-03-15 08:11:03 +0000776 s_update_danger_set_count++;
777 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
778 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000779
bart3772a982008-03-15 08:11:03 +0000780 if (s_danger_set)
781 {
bart1ea5fff2008-03-16 08:36:23 +0000782 bm_delete(s_danger_set);
bart3772a982008-03-15 08:11:03 +0000783 }
bart1ea5fff2008-03-16 08:36:23 +0000784 s_danger_set = bm_new();
bart26f73e12008-02-24 18:37:08 +0000785
bart3772a982008-03-15 08:11:03 +0000786 if (s_trace_danger_set)
787 {
788 char msg[256];
789
790 VG_(snprintf)(msg, sizeof(msg),
791 "computing danger set for thread %d with vc ",
792 tid);
793 vc_snprint(msg + VG_(strlen)(msg),
794 sizeof(msg) - VG_(strlen)(msg),
795 &s_threadinfo[tid].last->vc);
796 VG_(message)(Vg_DebugMsg, "%s", msg);
797 }
798
799 p = s_threadinfo[tid].last;
800 {
801 unsigned j;
802
803 if (s_trace_danger_set)
804 {
bart26f73e12008-02-24 18:37:08 +0000805 char msg[256];
806
807 VG_(snprintf)(msg, sizeof(msg),
bart3772a982008-03-15 08:11:03 +0000808 "danger set: thread [%d] at vc ",
bart26f73e12008-02-24 18:37:08 +0000809 tid);
810 vc_snprint(msg + VG_(strlen)(msg),
811 sizeof(msg) - VG_(strlen)(msg),
bart3772a982008-03-15 08:11:03 +0000812 &p->vc);
bart26f73e12008-02-24 18:37:08 +0000813 VG_(message)(Vg_DebugMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000814 }
sewardjaf44c822007-11-25 14:01:38 +0000815
bart3772a982008-03-15 08:11:03 +0000816 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
817 {
818 if (IsValidDrdThreadId(j))
bart26f73e12008-02-24 18:37:08 +0000819 {
bart3772a982008-03-15 08:11:03 +0000820 const Segment* q;
821 for (q = s_threadinfo[j].last; q; q = q->prev)
822 if (j != tid && q != 0
823 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
824 {
825 if (s_trace_danger_set)
826 {
827 char msg[256];
828 VG_(snprintf)(msg, sizeof(msg),
829 "danger set: [%d] merging segment ", j);
830 vc_snprint(msg + VG_(strlen)(msg),
831 sizeof(msg) - VG_(strlen)(msg),
832 &q->vc);
833 VG_(message)(Vg_DebugMsg, "%s", msg);
834 }
835 bm_merge2(s_danger_set, q->bm);
836 }
837 else
838 {
839 if (s_trace_danger_set)
840 {
841 char msg[256];
842 VG_(snprintf)(msg, sizeof(msg),
843 "danger set: [%d] ignoring segment ", j);
844 vc_snprint(msg + VG_(strlen)(msg),
845 sizeof(msg) - VG_(strlen)(msg),
846 &q->vc);
847 VG_(message)(Vg_DebugMsg, "%s", msg);
848 }
849 }
bart26f73e12008-02-24 18:37:08 +0000850 }
bart3772a982008-03-15 08:11:03 +0000851 }
bart26f73e12008-02-24 18:37:08 +0000852
bart3772a982008-03-15 08:11:03 +0000853 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
854 {
855 if (IsValidDrdThreadId(j))
sewardjaf44c822007-11-25 14:01:38 +0000856 {
bart3772a982008-03-15 08:11:03 +0000857 // NPTL hack: don't report data races on sizeof(struct pthread)
858 // bytes at the top of the stack, since the NPTL functions access
859 // this data without locking.
860 if (s_threadinfo[j].stack_min != 0)
861 {
862 tl_assert(s_threadinfo[j].stack_startup != 0);
863 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
864 {
865 bm_clear(s_danger_set,
866 s_threadinfo[j].stack_min,
867 s_threadinfo[j].stack_startup);
868 }
869 }
sewardjaf44c822007-11-25 14:01:38 +0000870 }
bart3772a982008-03-15 08:11:03 +0000871 }
872 }
sewardjaf44c822007-11-25 14:01:38 +0000873
bart3772a982008-03-15 08:11:03 +0000874 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
875 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000876
bart3772a982008-03-15 08:11:03 +0000877 if (0 && s_trace_danger_set)
878 {
879 VG_(message)(Vg_DebugMsg, "[%d] new danger set:", tid);
880 bm_print(s_danger_set);
881 VG_(message)(Vg_DebugMsg, "[%d] end of new danger set.", tid);
882 }
sewardjaf44c822007-11-25 14:01:38 +0000883}
884
sewardjaf44c822007-11-25 14:01:38 +0000885ULong thread_get_context_switch_count(void)
886{
bart3772a982008-03-15 08:11:03 +0000887 return s_context_switch_count;
sewardjaf44c822007-11-25 14:01:38 +0000888}
889
sewardjaf44c822007-11-25 14:01:38 +0000890ULong thread_get_discard_ordered_segments_count(void)
891{
bart3772a982008-03-15 08:11:03 +0000892 return s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +0000893}
894
895ULong thread_get_update_danger_set_count(void)
896{
bart3772a982008-03-15 08:11:03 +0000897 return s_update_danger_set_count;
sewardjaf44c822007-11-25 14:01:38 +0000898}
899
900ULong thread_get_danger_set_bitmap_creation_count(void)
901{
bart3772a982008-03-15 08:11:03 +0000902 return s_danger_set_bitmap_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000903}
904
905ULong thread_get_danger_set_bitmap2_creation_count(void)
906{
bart3772a982008-03-15 08:11:03 +0000907 return s_danger_set_bitmap2_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000908}