blob: fe68c45e98e590b1a81c6959c58e91f32bf23c11 [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);
barta2b6e1b2008-03-17 18:32:39 +000045static void thread_discard_segment(const DrdThreadId tid, Segment* const sg);
sewardjaf44c822007-11-25 14:01:38 +000046static void thread_update_danger_set(const DrdThreadId tid);
47
48
49// Local variables.
50
51static ULong s_context_switch_count;
52static ULong s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +000053static ULong s_update_danger_set_count;
54static ULong s_danger_set_bitmap_creation_count;
55static ULong s_danger_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000056static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
bartf00a85b2008-03-13 18:49:23 +000057DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
58ThreadInfo s_threadinfo[DRD_N_THREADS];
bart1a473c72008-03-13 19:03:38 +000059struct bitmap* s_danger_set;
bart26f73e12008-02-24 18:37:08 +000060static Bool s_trace_context_switches = False;
61static Bool s_trace_danger_set = False;
sewardjaf44c822007-11-25 14:01:38 +000062
63
64// Function definitions.
65
bart26f73e12008-02-24 18:37:08 +000066void thread_trace_context_switches(const Bool t)
67{
bart3772a982008-03-15 08:11:03 +000068 s_trace_context_switches = t;
bart26f73e12008-02-24 18:37:08 +000069}
70
71void thread_trace_danger_set(const Bool t)
72{
bart3772a982008-03-15 08:11:03 +000073 s_trace_danger_set = t;
bart26f73e12008-02-24 18:37:08 +000074}
75
sewardjaf44c822007-11-25 14:01:38 +000076__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
77{
bart3772a982008-03-15 08:11:03 +000078 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
79 && ! (s_threadinfo[tid].vg_thread_exists == False
80 && s_threadinfo[tid].posix_thread_exists == False
81 && s_threadinfo[tid].detached_posix_thread == False));
sewardjaf44c822007-11-25 14:01:38 +000082}
83
84/**
85 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
86 * Valgrind's ThreadId does not yet exist.
87 **/
88DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
89{
bart3772a982008-03-15 08:11:03 +000090 int i;
sewardjaf44c822007-11-25 14:01:38 +000091
bart3772a982008-03-15 08:11:03 +000092 if (tid == VG_INVALID_THREADID)
93 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +000094
bart3772a982008-03-15 08:11:03 +000095 for (i = 1; i < DRD_N_THREADS; i++)
96 {
97 if (s_threadinfo[i].vg_thread_exists == True
98 && s_threadinfo[i].vg_threadid == tid)
99 {
100 return i;
101 }
102 }
sewardjaf44c822007-11-25 14:01:38 +0000103
bart3772a982008-03-15 08:11:03 +0000104 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000105}
106
107static
108DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
109{
bart3772a982008-03-15 08:11:03 +0000110 int i;
sewardjaf44c822007-11-25 14:01:38 +0000111
bart3772a982008-03-15 08:11:03 +0000112 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000113
bart3772a982008-03-15 08:11:03 +0000114 for (i = 1; i < DRD_N_THREADS; i++)
115 {
116 if (s_threadinfo[i].vg_thread_exists == False
117 && s_threadinfo[i].posix_thread_exists == False
118 && s_threadinfo[i].detached_posix_thread == False)
119 {
120 s_threadinfo[i].vg_thread_exists = True;
121 s_threadinfo[i].vg_threadid = tid;
122 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
bart3772a982008-03-15 08:11:03 +0000123 s_threadinfo[i].stack_min = 0;
124 s_threadinfo[i].stack_startup = 0;
125 s_threadinfo[i].stack_max = 0;
bart3772a982008-03-15 08:11:03 +0000126 s_threadinfo[i].is_recording = True;
127 s_threadinfo[i].synchr_nesting = 0;
128 if (s_threadinfo[i].first != 0)
129 VG_(printf)("drd thread id = %d\n", i);
130 tl_assert(s_threadinfo[i].first == 0);
131 tl_assert(s_threadinfo[i].last == 0);
132 return i;
133 }
134 }
sewardjaf44c822007-11-25 14:01:38 +0000135
bart3772a982008-03-15 08:11:03 +0000136 tl_assert(False);
sewardjaf44c822007-11-25 14:01:38 +0000137
bart3772a982008-03-15 08:11:03 +0000138 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000139}
140
141DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
142{
bart3772a982008-03-15 08:11:03 +0000143 int i;
sewardjaf44c822007-11-25 14:01:38 +0000144
bart3772a982008-03-15 08:11:03 +0000145 tl_assert(tid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000146
bart3772a982008-03-15 08:11:03 +0000147 for (i = 1; i < DRD_N_THREADS; i++)
148 {
149 if (s_threadinfo[i].posix_thread_exists
150 && s_threadinfo[i].pt_threadid == tid)
151 {
152 return i;
153 }
154 }
155 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000156}
157
158ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
159{
bart3772a982008-03-15 08:11:03 +0000160 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
161 return (s_threadinfo[tid].vg_thread_exists
162 ? s_threadinfo[tid].vg_threadid
163 : VG_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000164}
165
bart26f73e12008-02-24 18:37:08 +0000166/** Sanity check of the doubly linked list of segments referenced by a
167 * ThreadInfo struct.
168 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000169 */
170static Bool sane_ThreadInfo(const ThreadInfo* const ti)
171{
bart3772a982008-03-15 08:11:03 +0000172 Segment* p;
173 for (p = ti->first; p; p = p->next) {
174 if (p->next && p->next->prev != p)
175 return False;
176 if (p->next == 0 && p != ti->last)
177 return False;
178 }
179 for (p = ti->last; p; p = p->prev) {
180 if (p->prev && p->prev->next != p)
181 return False;
182 if (p->prev == 0 && p != ti->first)
183 return False;
184 }
185 return True;
sewardjaf44c822007-11-25 14:01:38 +0000186}
187
188DrdThreadId thread_pre_create(const DrdThreadId creator,
189 const ThreadId vg_created)
190{
bart3772a982008-03-15 08:11:03 +0000191 DrdThreadId created;
sewardjaf44c822007-11-25 14:01:38 +0000192
bart3772a982008-03-15 08:11:03 +0000193 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
194 created = VgThreadIdToNewDrdThreadId(vg_created);
195 tl_assert(0 <= created && created < DRD_N_THREADS
196 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000197
bart3772a982008-03-15 08:11:03 +0000198 tl_assert(s_threadinfo[created].first == 0);
199 tl_assert(s_threadinfo[created].last == 0);
200 thread_append_segment(created, sg_new(creator, created));
sewardjaf44c822007-11-25 14:01:38 +0000201
bart3772a982008-03-15 08:11:03 +0000202 return created;
sewardjaf44c822007-11-25 14:01:38 +0000203}
204
bart26f73e12008-02-24 18:37:08 +0000205/** Allocate the first segment for a thread. Call this just after
206 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000207 */
208DrdThreadId thread_post_create(const ThreadId vg_created)
209{
bart3772a982008-03-15 08:11:03 +0000210 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
sewardjaf44c822007-11-25 14:01:38 +0000211
bart3772a982008-03-15 08:11:03 +0000212 tl_assert(0 <= created && created < DRD_N_THREADS
213 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000214
bart3772a982008-03-15 08:11:03 +0000215 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
216 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
217 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
bart3772a982008-03-15 08:11:03 +0000218 tl_assert(s_threadinfo[created].stack_max != 0);
sewardjaf44c822007-11-25 14:01:38 +0000219
bart3772a982008-03-15 08:11:03 +0000220 return created;
sewardjaf44c822007-11-25 14:01:38 +0000221}
222
223/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
224/* and accesses this data structure from multiple threads without locking. */
225/* Any conflicting accesses in the range stack_startup..stack_max will be */
226/* ignored. */
227void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
228{
bart3772a982008-03-15 08:11:03 +0000229 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
230 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
231 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
232 s_threadinfo[tid].stack_startup = stack_startup;
sewardjaf44c822007-11-25 14:01:38 +0000233}
234
235Addr thread_get_stack_min(const DrdThreadId tid)
236{
bart3772a982008-03-15 08:11:03 +0000237 tl_assert(0 <= tid && tid < DRD_N_THREADS
238 && tid != DRD_INVALID_THREADID);
239 return s_threadinfo[tid].stack_min;
sewardjaf44c822007-11-25 14:01:38 +0000240}
241
bartd43f8d32008-03-16 17:29:20 +0000242Addr thread_get_stack_max(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000243{
bartd43f8d32008-03-16 17:29:20 +0000244 tl_assert(0 <= tid && tid < DRD_N_THREADS
245 && tid != DRD_INVALID_THREADID);
246 return s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000247}
248
barta2b6e1b2008-03-17 18:32:39 +0000249/** Clean up thread-specific data structures. Call this just after
250 * pthread_join().
sewardjaf44c822007-11-25 14:01:38 +0000251 */
252void thread_delete(const DrdThreadId tid)
253{
bart3772a982008-03-15 08:11:03 +0000254 Segment* sg;
255 Segment* sg_prev;
sewardjaf44c822007-11-25 14:01:38 +0000256
bart3772a982008-03-15 08:11:03 +0000257 tl_assert(0 <= tid && tid < DRD_N_THREADS
258 && tid != DRD_INVALID_THREADID);
259 tl_assert(s_threadinfo[tid].synchr_nesting == 0);
260 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
261 {
262 sg_prev = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000263 sg->prev = 0;
264 sg->next = 0;
265 sg_put(sg);
bart3772a982008-03-15 08:11:03 +0000266 }
267 s_threadinfo[tid].vg_thread_exists = False;
268 s_threadinfo[tid].posix_thread_exists = False;
269 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
270 s_threadinfo[tid].first = 0;
271 s_threadinfo[tid].last = 0;
sewardjaf44c822007-11-25 14:01:38 +0000272}
273
274/* Called after a thread performed its last memory access and before */
275/* thread_delete() is called. Note: thread_delete() is only called for */
276/* joinable threads, not for detached threads. */
277void thread_finished(const DrdThreadId tid)
278{
bart3772a982008-03-15 08:11:03 +0000279 tl_assert(0 <= tid && tid < DRD_N_THREADS
280 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000281
bart3772a982008-03-15 08:11:03 +0000282 s_threadinfo[tid].vg_thread_exists = False;
sewardjaf44c822007-11-25 14:01:38 +0000283
bart3772a982008-03-15 08:11:03 +0000284 if (s_threadinfo[tid].detached_posix_thread)
285 {
286 /* Once a detached thread has finished, its stack is deallocated and */
287 /* should no longer be taken into account when computing the danger set*/
288 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000289
bart3772a982008-03-15 08:11:03 +0000290 /* For a detached thread, calling pthread_exit() invalidates the */
291 /* POSIX thread ID associated with the detached thread. For joinable */
292 /* POSIX threads however, the POSIX thread ID remains live after the */
293 /* pthread_exit() call until pthread_join() is called. */
294 s_threadinfo[tid].posix_thread_exists = False;
295 }
sewardjaf44c822007-11-25 14:01:38 +0000296}
297
298void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
299{
bart3772a982008-03-15 08:11:03 +0000300 tl_assert(0 <= tid && tid < DRD_N_THREADS
301 && tid != DRD_INVALID_THREADID);
302 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
303 tl_assert(ptid != INVALID_POSIX_THREADID);
304 s_threadinfo[tid].posix_thread_exists = True;
305 s_threadinfo[tid].pt_threadid = ptid;
sewardjaf44c822007-11-25 14:01:38 +0000306}
307
308Bool thread_get_joinable(const DrdThreadId tid)
309{
bart3772a982008-03-15 08:11:03 +0000310 tl_assert(0 <= tid && tid < DRD_N_THREADS
311 && tid != DRD_INVALID_THREADID);
312 return ! s_threadinfo[tid].detached_posix_thread;
sewardjaf44c822007-11-25 14:01:38 +0000313}
314
315void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
316{
bart3772a982008-03-15 08:11:03 +0000317 tl_assert(0 <= tid && tid < DRD_N_THREADS
318 && tid != DRD_INVALID_THREADID);
319 tl_assert(!! joinable == joinable);
320 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000321#if 0
bart3772a982008-03-15 08:11:03 +0000322 VG_(message)(Vg_DebugMsg,
323 "thread_set_joinable(%d/%d, %s)",
324 tid,
325 s_threadinfo[tid].vg_threadid,
326 joinable ? "joinable" : "detached");
sewardjaf44c822007-11-25 14:01:38 +0000327#endif
bart3772a982008-03-15 08:11:03 +0000328 s_threadinfo[tid].detached_posix_thread = ! joinable;
sewardjaf44c822007-11-25 14:01:38 +0000329}
330
sewardj8b09d4f2007-12-04 21:27:18 +0000331void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000332{
bart3772a982008-03-15 08:11:03 +0000333 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000334
bart3772a982008-03-15 08:11:03 +0000335 if (vg_tid != s_vg_running_tid)
336 {
337 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
338 }
sewardj8b09d4f2007-12-04 21:27:18 +0000339
bart3772a982008-03-15 08:11:03 +0000340 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
341 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000342}
343
344void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
345{
bart3772a982008-03-15 08:11:03 +0000346 tl_assert(vg_tid != VG_INVALID_THREADID);
347 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000348
bart3772a982008-03-15 08:11:03 +0000349 if (vg_tid != s_vg_running_tid)
350 {
351 if (s_trace_context_switches
352 && s_drd_running_tid != DRD_INVALID_THREADID)
353 {
354 VG_(message)(Vg_DebugMsg,
barta2b6e1b2008-03-17 18:32:39 +0000355 "Context switch from thread %d/%d to thread %d/%d;"
356 " segments: %llu",
bartaa97a542008-03-16 17:57:01 +0000357 s_vg_running_tid, s_drd_running_tid,
barta2b6e1b2008-03-17 18:32:39 +0000358 DrdThreadIdToVgThreadId(drd_tid), drd_tid,
359 sg_get_alive_segments_count());
bart3772a982008-03-15 08:11:03 +0000360 }
361 s_vg_running_tid = vg_tid;
362 s_drd_running_tid = drd_tid;
363 thread_update_danger_set(drd_tid);
364 s_context_switch_count++;
365 }
sewardj8b09d4f2007-12-04 21:27:18 +0000366
bart3772a982008-03-15 08:11:03 +0000367 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
368 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000369}
370
bart0268dfa2008-03-11 20:10:21 +0000371int thread_enter_synchr(const DrdThreadId tid)
372{
bart3772a982008-03-15 08:11:03 +0000373 tl_assert(IsValidDrdThreadId(tid));
374 return s_threadinfo[tid].synchr_nesting++;
bart0268dfa2008-03-11 20:10:21 +0000375}
376
377int thread_leave_synchr(const DrdThreadId tid)
378{
bart3772a982008-03-15 08:11:03 +0000379 tl_assert(IsValidDrdThreadId(tid));
380 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
381 return --s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000382}
383
384int thread_get_synchr_nesting_count(const DrdThreadId tid)
385{
bart3772a982008-03-15 08:11:03 +0000386 tl_assert(IsValidDrdThreadId(tid));
387 return s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000388}
389
bart1a473c72008-03-13 19:03:38 +0000390/** Append a new segment at the end of the segment list. */
bart26f73e12008-02-24 18:37:08 +0000391static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000392{
bart3772a982008-03-15 08:11:03 +0000393 tl_assert(0 <= tid && tid < DRD_N_THREADS
394 && tid != DRD_INVALID_THREADID);
395 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
396 sg->prev = s_threadinfo[tid].last;
397 sg->next = 0;
398 if (s_threadinfo[tid].last)
399 s_threadinfo[tid].last->next = sg;
400 s_threadinfo[tid].last = sg;
401 if (s_threadinfo[tid].first == 0)
402 s_threadinfo[tid].first = sg;
403 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000404}
405
bart26f73e12008-02-24 18:37:08 +0000406/** Remove a segment from the segment list of thread threadid, and free the
407 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000408 */
bart26f73e12008-02-24 18:37:08 +0000409static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000410{
bart3772a982008-03-15 08:11:03 +0000411 tl_assert(0 <= tid && tid < DRD_N_THREADS
412 && tid != DRD_INVALID_THREADID);
413 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000414
bart3772a982008-03-15 08:11:03 +0000415 if (sg->prev)
416 sg->prev->next = sg->next;
417 if (sg->next)
418 sg->next->prev = sg->prev;
419 if (sg == s_threadinfo[tid].first)
420 s_threadinfo[tid].first = sg->next;
421 if (sg == s_threadinfo[tid].last)
422 s_threadinfo[tid].last = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000423 sg_put(sg);
bart3772a982008-03-15 08:11:03 +0000424 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000425}
426
427VectorClock* thread_get_vc(const DrdThreadId tid)
428{
barta2b6e1b2008-03-17 18:32:39 +0000429 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000430 tl_assert(s_threadinfo[tid].last);
431 return &s_threadinfo[tid].last->vc;
sewardjaf44c822007-11-25 14:01:38 +0000432}
433
barta2b6e1b2008-03-17 18:32:39 +0000434/** Return the latest segment of thread 'tid' and increment its reference
435 * count.
436 */
437void thread_get_latest_segment(Segment** sg, const DrdThreadId tid)
438{
439 tl_assert(sg);
440 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
441 tl_assert(s_threadinfo[tid].last);
442
443 sg_put(*sg);
444 *sg = sg_get(s_threadinfo[tid].last);
445}
446
sewardjaf44c822007-11-25 14:01:38 +0000447/**
448 * Compute the minimum of all latest vector clocks of all threads
449 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
450 * @param vc pointer to a vectorclock, holds result upon return.
451 */
452static void thread_compute_minimum_vc(VectorClock* vc)
453{
bart3772a982008-03-15 08:11:03 +0000454 unsigned i;
455 Bool first;
456 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000457
bart3772a982008-03-15 08:11:03 +0000458 first = True;
459 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
460 {
461 latest_sg = s_threadinfo[i].last;
462 if (latest_sg)
463 {
464 if (first)
465 vc_assign(vc, &latest_sg->vc);
466 else
467 vc_min(vc, &latest_sg->vc);
468 first = False;
469 }
470 }
sewardjaf44c822007-11-25 14:01:38 +0000471}
472
473static void thread_compute_maximum_vc(VectorClock* vc)
474{
bart3772a982008-03-15 08:11:03 +0000475 unsigned i;
476 Bool first;
477 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000478
bart3772a982008-03-15 08:11:03 +0000479 first = True;
480 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
481 {
482 latest_sg = s_threadinfo[i].last;
483 if (latest_sg)
484 {
485 if (first)
486 vc_assign(vc, &latest_sg->vc);
487 else
488 vc_combine(vc, &latest_sg->vc);
489 first = False;
490 }
491 }
sewardjaf44c822007-11-25 14:01:38 +0000492}
493
494/**
bart5bd9f2d2008-03-03 20:31:58 +0000495 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000496 * clock of every thread -- these segments can no longer be involved in a
497 * data race.
498 */
499static void thread_discard_ordered_segments(void)
500{
bart3772a982008-03-15 08:11:03 +0000501 unsigned i;
502 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000503
bart3772a982008-03-15 08:11:03 +0000504 s_discard_ordered_segments_count++;
sewardjaf44c822007-11-25 14:01:38 +0000505
bart3772a982008-03-15 08:11:03 +0000506 vc_init(&thread_vc_min, 0, 0);
507 thread_compute_minimum_vc(&thread_vc_min);
508 if (sg_get_trace())
509 {
510 char msg[256];
511 VectorClock thread_vc_max;
sewardjaf44c822007-11-25 14:01:38 +0000512
bart3772a982008-03-15 08:11:03 +0000513 vc_init(&thread_vc_max, 0, 0);
514 thread_compute_maximum_vc(&thread_vc_max);
515 VG_(snprintf)(msg, sizeof(msg),
516 "Discarding ordered segments -- min vc is ");
517 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
518 &thread_vc_min);
519 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
520 ", max vc is ");
521 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
522 &thread_vc_max);
barta2b6e1b2008-03-17 18:32:39 +0000523 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000524 vc_cleanup(&thread_vc_max);
525 }
sewardjaf44c822007-11-25 14:01:38 +0000526
bart3772a982008-03-15 08:11:03 +0000527 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
528 {
529 Segment* sg;
530 Segment* sg_next;
531 for (sg = s_threadinfo[i].first;
532 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
533 sg = sg_next)
534 {
535 thread_discard_segment(i, sg);
536 }
537 }
538 vc_cleanup(&thread_vc_min);
sewardjaf44c822007-11-25 14:01:38 +0000539}
540
barta2b6e1b2008-03-17 18:32:39 +0000541/** Create a new segment for the specified thread, and discard any segments
542 * that cannot cause races anymore.
sewardjaf44c822007-11-25 14:01:38 +0000543 */
544void thread_new_segment(const DrdThreadId tid)
545{
barta2b6e1b2008-03-17 18:32:39 +0000546 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000547
barta2b6e1b2008-03-17 18:32:39 +0000548 thread_append_segment(tid, sg_new(tid, tid));
sewardjaf44c822007-11-25 14:01:38 +0000549
bart3772a982008-03-15 08:11:03 +0000550 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000551
bart3772a982008-03-15 08:11:03 +0000552 if (tid == s_drd_running_tid)
553 {
554 /* Every change in the vector clock of the current thread may cause */
555 /* segments that were previously ordered to this thread to become */
556 /* unordered. Hence, recalculate the danger set if the vector clock */
557 /* of the current thread is updated. */
558 thread_update_danger_set(tid);
559 }
sewardjaf44c822007-11-25 14:01:38 +0000560}
561
bart26f73e12008-02-24 18:37:08 +0000562/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000563void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
564{
bart3772a982008-03-15 08:11:03 +0000565 tl_assert(joiner != joinee);
566 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
567 && joiner != DRD_INVALID_THREADID);
568 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
569 && joinee != DRD_INVALID_THREADID);
570 tl_assert(s_threadinfo[joiner].last);
571 tl_assert(s_threadinfo[joinee].last);
572 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
573 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000574
bart3772a982008-03-15 08:11:03 +0000575 if (joiner == s_drd_running_tid)
576 {
577 thread_update_danger_set(joiner);
578 }
sewardjaf44c822007-11-25 14:01:38 +0000579}
580
bart26f73e12008-02-24 18:37:08 +0000581/** Call this function after thread 'tid' had to wait because of thread
582 * synchronization until the memory accesses in the segment with vector clock
583 * 'vc' finished.
584 */
sewardjaf44c822007-11-25 14:01:38 +0000585void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
586{
bart3772a982008-03-15 08:11:03 +0000587 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
588 tl_assert(s_threadinfo[tid].last);
589 tl_assert(vc);
590 vc_combine(&s_threadinfo[tid].last->vc, vc);
591 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000592}
593
bart26f73e12008-02-24 18:37:08 +0000594/** Call this function whenever a thread is no longer using the memory
595 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
596 * increase.
597 */
sewardjaf44c822007-11-25 14:01:38 +0000598void thread_stop_using_mem(const Addr a1, const Addr a2)
599{
bartd43f8d32008-03-16 17:29:20 +0000600 DrdThreadId other_user;
601 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000602
bart3772a982008-03-15 08:11:03 +0000603 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
bartd43f8d32008-03-16 17:29:20 +0000604 other_user = DRD_INVALID_THREADID;
bart3772a982008-03-15 08:11:03 +0000605 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
606 {
607 Segment* p;
608 for (p = s_threadinfo[i].first; p; p = p->next)
609 {
610 if (other_user == DRD_INVALID_THREADID
611 && i != s_drd_running_tid
612 && bm_has_any_access(p->bm, a1, a2))
sewardjaf44c822007-11-25 14:01:38 +0000613 {
bart3772a982008-03-15 08:11:03 +0000614 other_user = i;
sewardjaf44c822007-11-25 14:01:38 +0000615 }
bart3772a982008-03-15 08:11:03 +0000616 bm_clear(p->bm, a1, a2);
617 }
618 }
sewardjaf44c822007-11-25 14:01:38 +0000619
bart3772a982008-03-15 08:11:03 +0000620 /* If any other thread had accessed memory in [ a1, a2 [, update the */
621 /* danger set. */
622 if (other_user != DRD_INVALID_THREADID
623 && bm_has_any_access(s_danger_set, a1, a2))
624 {
625 thread_update_danger_set(thread_get_running_tid());
626 }
sewardjaf44c822007-11-25 14:01:38 +0000627}
628
bart0268dfa2008-03-11 20:10:21 +0000629void thread_start_recording(const DrdThreadId tid)
630{
bart3772a982008-03-15 08:11:03 +0000631 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
632 tl_assert(! s_threadinfo[tid].is_recording);
633 s_threadinfo[tid].is_recording = True;
bart0268dfa2008-03-11 20:10:21 +0000634}
635
636void thread_stop_recording(const DrdThreadId tid)
637{
bart3772a982008-03-15 08:11:03 +0000638 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
639 tl_assert(s_threadinfo[tid].is_recording);
640 s_threadinfo[tid].is_recording = False;
bart0268dfa2008-03-11 20:10:21 +0000641}
642
sewardjaf44c822007-11-25 14:01:38 +0000643void thread_print_all(void)
644{
bart3772a982008-03-15 08:11:03 +0000645 unsigned i;
646 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000647
bart3772a982008-03-15 08:11:03 +0000648 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
649 {
650 if (s_threadinfo[i].first)
651 {
652 VG_(printf)("**************\n"
barta2b6e1b2008-03-17 18:32:39 +0000653 "* thread %3d (%d/%d/%d/0x%lx/%d) *\n"
bart3772a982008-03-15 08:11:03 +0000654 "**************\n",
655 i,
656 s_threadinfo[i].vg_thread_exists,
657 s_threadinfo[i].vg_threadid,
658 s_threadinfo[i].posix_thread_exists,
659 s_threadinfo[i].pt_threadid,
bart354009c2008-03-16 10:42:33 +0000660 s_threadinfo[i].detached_posix_thread);
bart3772a982008-03-15 08:11:03 +0000661 for (p = s_threadinfo[i].first; p; p = p->next)
sewardjaf44c822007-11-25 14:01:38 +0000662 {
bart3772a982008-03-15 08:11:03 +0000663 sg_print(p);
sewardjaf44c822007-11-25 14:01:38 +0000664 }
bart3772a982008-03-15 08:11:03 +0000665 }
666 }
sewardjaf44c822007-11-25 14:01:38 +0000667}
668
669static void show_call_stack(const DrdThreadId tid,
670 const Char* const msg,
671 ExeContext* const callstack)
672{
bart3772a982008-03-15 08:11:03 +0000673 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000674
bartaa97a542008-03-16 17:57:01 +0000675 VG_(message)(Vg_UserMsg, "%s (thread %d/%d)", msg, vg_tid, tid);
sewardjaf44c822007-11-25 14:01:38 +0000676
bart3772a982008-03-15 08:11:03 +0000677 if (vg_tid != VG_INVALID_THREADID)
678 {
679 if (callstack)
680 {
681 VG_(pp_ExeContext)(callstack);
682 }
683 else
684 {
685 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
686 }
687 }
688 else
689 {
690 VG_(message)(Vg_UserMsg,
691 " (thread finished, call stack no longer available)");
692 }
sewardjaf44c822007-11-25 14:01:38 +0000693}
694
sewardjaf44c822007-11-25 14:01:38 +0000695static void
696thread_report_conflicting_segments_segment(const DrdThreadId tid,
697 const Addr addr,
698 const SizeT size,
699 const BmAccessTypeT access_type,
700 const Segment* const p)
701{
bart3772a982008-03-15 08:11:03 +0000702 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000703
bart3772a982008-03-15 08:11:03 +0000704 tl_assert(0 <= tid && tid < DRD_N_THREADS
705 && tid != DRD_INVALID_THREADID);
706 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000707
bart3772a982008-03-15 08:11:03 +0000708 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
709 {
710 if (i != tid)
711 {
712 Segment* q;
713 for (q = s_threadinfo[i].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000714 {
bart3772a982008-03-15 08:11:03 +0000715 // Since q iterates over the segments of thread i in order of
716 // decreasing vector clocks, if q->vc <= p->vc, then
717 // q->next->vc <= p->vc will also hold. Hence, break out of the
718 // loop once this condition is met.
719 if (vc_lte(&q->vc, &p->vc))
720 break;
721 if (! vc_lte(&p->vc, &q->vc))
722 {
723 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
724 {
725 tl_assert(q->stacktrace);
726 show_call_stack(i, "Other segment start",
727 q->stacktrace);
728 show_call_stack(i, "Other segment end",
729 q->next ? q->next->stacktrace : 0);
730 }
731 }
sewardjaf44c822007-11-25 14:01:38 +0000732 }
bart3772a982008-03-15 08:11:03 +0000733 }
734 }
sewardjaf44c822007-11-25 14:01:38 +0000735}
736
737void thread_report_conflicting_segments(const DrdThreadId tid,
738 const Addr addr,
739 const SizeT size,
740 const BmAccessTypeT access_type)
741{
bart3772a982008-03-15 08:11:03 +0000742 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000743
bart3772a982008-03-15 08:11:03 +0000744 tl_assert(0 <= tid && tid < DRD_N_THREADS
745 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000746
bart3772a982008-03-15 08:11:03 +0000747 for (p = s_threadinfo[tid].first; p; p = p->next)
748 {
749 if (bm_has(p->bm, addr, addr + size, access_type))
750 {
751 thread_report_conflicting_segments_segment(tid, addr, size,
752 access_type, p);
753 }
754 }
sewardjaf44c822007-11-25 14:01:38 +0000755}
sewardjaf44c822007-11-25 14:01:38 +0000756
bart26f73e12008-02-24 18:37:08 +0000757/** Compute a bitmap that represents the union of all memory accesses of all
758 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000759 */
760static void thread_update_danger_set(const DrdThreadId tid)
761{
bart3772a982008-03-15 08:11:03 +0000762 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000763
bart3772a982008-03-15 08:11:03 +0000764 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
765 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000766
bart3772a982008-03-15 08:11:03 +0000767 s_update_danger_set_count++;
768 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
769 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000770
bart3772a982008-03-15 08:11:03 +0000771 if (s_danger_set)
772 {
bart1ea5fff2008-03-16 08:36:23 +0000773 bm_delete(s_danger_set);
bart3772a982008-03-15 08:11:03 +0000774 }
bart1ea5fff2008-03-16 08:36:23 +0000775 s_danger_set = bm_new();
bart26f73e12008-02-24 18:37:08 +0000776
bart3772a982008-03-15 08:11:03 +0000777 if (s_trace_danger_set)
778 {
779 char msg[256];
780
781 VG_(snprintf)(msg, sizeof(msg),
bartaa97a542008-03-16 17:57:01 +0000782 "computing danger set for thread %d/%d with vc ",
783 DrdThreadIdToVgThreadId(tid), tid);
bart3772a982008-03-15 08:11:03 +0000784 vc_snprint(msg + VG_(strlen)(msg),
785 sizeof(msg) - VG_(strlen)(msg),
786 &s_threadinfo[tid].last->vc);
barta2b6e1b2008-03-17 18:32:39 +0000787 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000788 }
789
790 p = s_threadinfo[tid].last;
791 {
792 unsigned j;
793
794 if (s_trace_danger_set)
795 {
bart26f73e12008-02-24 18:37:08 +0000796 char msg[256];
797
798 VG_(snprintf)(msg, sizeof(msg),
bart3772a982008-03-15 08:11:03 +0000799 "danger set: thread [%d] at vc ",
bart26f73e12008-02-24 18:37:08 +0000800 tid);
801 vc_snprint(msg + VG_(strlen)(msg),
802 sizeof(msg) - VG_(strlen)(msg),
bart3772a982008-03-15 08:11:03 +0000803 &p->vc);
barta2b6e1b2008-03-17 18:32:39 +0000804 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000805 }
sewardjaf44c822007-11-25 14:01:38 +0000806
bart3772a982008-03-15 08:11:03 +0000807 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
808 {
809 if (IsValidDrdThreadId(j))
bart26f73e12008-02-24 18:37:08 +0000810 {
bart3772a982008-03-15 08:11:03 +0000811 const Segment* q;
812 for (q = s_threadinfo[j].last; q; q = q->prev)
813 if (j != tid && q != 0
814 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
815 {
816 if (s_trace_danger_set)
817 {
818 char msg[256];
819 VG_(snprintf)(msg, sizeof(msg),
820 "danger set: [%d] merging segment ", j);
821 vc_snprint(msg + VG_(strlen)(msg),
822 sizeof(msg) - VG_(strlen)(msg),
823 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +0000824 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000825 }
826 bm_merge2(s_danger_set, q->bm);
827 }
828 else
829 {
830 if (s_trace_danger_set)
831 {
832 char msg[256];
833 VG_(snprintf)(msg, sizeof(msg),
834 "danger set: [%d] ignoring segment ", j);
835 vc_snprint(msg + VG_(strlen)(msg),
836 sizeof(msg) - VG_(strlen)(msg),
837 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +0000838 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000839 }
840 }
bart26f73e12008-02-24 18:37:08 +0000841 }
bart3772a982008-03-15 08:11:03 +0000842 }
bart26f73e12008-02-24 18:37:08 +0000843
bart3772a982008-03-15 08:11:03 +0000844 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
845 {
846 if (IsValidDrdThreadId(j))
sewardjaf44c822007-11-25 14:01:38 +0000847 {
bart3772a982008-03-15 08:11:03 +0000848 // NPTL hack: don't report data races on sizeof(struct pthread)
849 // bytes at the top of the stack, since the NPTL functions access
850 // this data without locking.
851 if (s_threadinfo[j].stack_min != 0)
852 {
853 tl_assert(s_threadinfo[j].stack_startup != 0);
854 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
855 {
856 bm_clear(s_danger_set,
857 s_threadinfo[j].stack_min,
858 s_threadinfo[j].stack_startup);
859 }
860 }
sewardjaf44c822007-11-25 14:01:38 +0000861 }
bart3772a982008-03-15 08:11:03 +0000862 }
863 }
sewardjaf44c822007-11-25 14:01:38 +0000864
bart3772a982008-03-15 08:11:03 +0000865 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
866 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000867
bart3772a982008-03-15 08:11:03 +0000868 if (0 && s_trace_danger_set)
869 {
barta2b6e1b2008-03-17 18:32:39 +0000870 VG_(message)(Vg_UserMsg, "[%d] new danger set:", tid);
bart3772a982008-03-15 08:11:03 +0000871 bm_print(s_danger_set);
barta2b6e1b2008-03-17 18:32:39 +0000872 VG_(message)(Vg_UserMsg, "[%d] end of new danger set.", tid);
bart3772a982008-03-15 08:11:03 +0000873 }
sewardjaf44c822007-11-25 14:01:38 +0000874}
875
sewardjaf44c822007-11-25 14:01:38 +0000876ULong thread_get_context_switch_count(void)
877{
bart3772a982008-03-15 08:11:03 +0000878 return s_context_switch_count;
sewardjaf44c822007-11-25 14:01:38 +0000879}
880
sewardjaf44c822007-11-25 14:01:38 +0000881ULong thread_get_discard_ordered_segments_count(void)
882{
bart3772a982008-03-15 08:11:03 +0000883 return s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +0000884}
885
886ULong thread_get_update_danger_set_count(void)
887{
bart3772a982008-03-15 08:11:03 +0000888 return s_update_danger_set_count;
sewardjaf44c822007-11-25 14:01:38 +0000889}
890
891ULong thread_get_danger_set_bitmap_creation_count(void)
892{
bart3772a982008-03-15 08:11:03 +0000893 return s_danger_set_bitmap_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000894}
895
896ULong thread_get_danger_set_bitmap2_creation_count(void)
897{
bart3772a982008-03-15 08:11:03 +0000898 return s_danger_set_bitmap2_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000899}