blob: 62eb0f35a8917387a019c8f066493ce04be99352 [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;
barta9c37392008-03-22 09:38:48 +000062static Bool s_segment_merging = True;
sewardjaf44c822007-11-25 14:01:38 +000063
64
65// Function definitions.
66
bart26f73e12008-02-24 18:37:08 +000067void thread_trace_context_switches(const Bool t)
68{
bart3772a982008-03-15 08:11:03 +000069 s_trace_context_switches = t;
bart26f73e12008-02-24 18:37:08 +000070}
71
72void thread_trace_danger_set(const Bool t)
73{
bart3772a982008-03-15 08:11:03 +000074 s_trace_danger_set = t;
bart26f73e12008-02-24 18:37:08 +000075}
76
barta9c37392008-03-22 09:38:48 +000077void thread_set_segment_merging(const Bool m)
78{
79 s_segment_merging = m;
80}
81
sewardjaf44c822007-11-25 14:01:38 +000082__inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
83{
bart3772a982008-03-15 08:11:03 +000084 return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
85 && ! (s_threadinfo[tid].vg_thread_exists == False
86 && s_threadinfo[tid].posix_thread_exists == False
87 && s_threadinfo[tid].detached_posix_thread == False));
sewardjaf44c822007-11-25 14:01:38 +000088}
89
90/**
91 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
92 * Valgrind's ThreadId does not yet exist.
93 **/
94DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
95{
bart3772a982008-03-15 08:11:03 +000096 int i;
sewardjaf44c822007-11-25 14:01:38 +000097
bart3772a982008-03-15 08:11:03 +000098 if (tid == VG_INVALID_THREADID)
99 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000100
bart3772a982008-03-15 08:11:03 +0000101 for (i = 1; i < DRD_N_THREADS; i++)
102 {
103 if (s_threadinfo[i].vg_thread_exists == True
104 && s_threadinfo[i].vg_threadid == tid)
105 {
106 return i;
107 }
108 }
sewardjaf44c822007-11-25 14:01:38 +0000109
bart3772a982008-03-15 08:11:03 +0000110 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000111}
112
113static
114DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
115{
bart3772a982008-03-15 08:11:03 +0000116 int i;
sewardjaf44c822007-11-25 14:01:38 +0000117
bart3772a982008-03-15 08:11:03 +0000118 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000119
bart3772a982008-03-15 08:11:03 +0000120 for (i = 1; i < DRD_N_THREADS; i++)
121 {
122 if (s_threadinfo[i].vg_thread_exists == False
123 && s_threadinfo[i].posix_thread_exists == False
124 && s_threadinfo[i].detached_posix_thread == False)
125 {
126 s_threadinfo[i].vg_thread_exists = True;
127 s_threadinfo[i].vg_threadid = tid;
128 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
bart3772a982008-03-15 08:11:03 +0000129 s_threadinfo[i].stack_min = 0;
130 s_threadinfo[i].stack_startup = 0;
131 s_threadinfo[i].stack_max = 0;
bart3772a982008-03-15 08:11:03 +0000132 s_threadinfo[i].is_recording = True;
133 s_threadinfo[i].synchr_nesting = 0;
134 if (s_threadinfo[i].first != 0)
135 VG_(printf)("drd thread id = %d\n", i);
136 tl_assert(s_threadinfo[i].first == 0);
137 tl_assert(s_threadinfo[i].last == 0);
138 return i;
139 }
140 }
sewardjaf44c822007-11-25 14:01:38 +0000141
bart3772a982008-03-15 08:11:03 +0000142 tl_assert(False);
sewardjaf44c822007-11-25 14:01:38 +0000143
bart3772a982008-03-15 08:11:03 +0000144 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000145}
146
147DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
148{
bart3772a982008-03-15 08:11:03 +0000149 int i;
sewardjaf44c822007-11-25 14:01:38 +0000150
bart3772a982008-03-15 08:11:03 +0000151 tl_assert(tid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000152
bart3772a982008-03-15 08:11:03 +0000153 for (i = 1; i < DRD_N_THREADS; i++)
154 {
155 if (s_threadinfo[i].posix_thread_exists
156 && s_threadinfo[i].pt_threadid == tid)
157 {
158 return i;
159 }
160 }
161 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000162}
163
164ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
165{
bart3772a982008-03-15 08:11:03 +0000166 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
167 return (s_threadinfo[tid].vg_thread_exists
168 ? s_threadinfo[tid].vg_threadid
169 : VG_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000170}
171
bart26f73e12008-02-24 18:37:08 +0000172/** Sanity check of the doubly linked list of segments referenced by a
173 * ThreadInfo struct.
174 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000175 */
176static Bool sane_ThreadInfo(const ThreadInfo* const ti)
177{
bart3772a982008-03-15 08:11:03 +0000178 Segment* p;
179 for (p = ti->first; p; p = p->next) {
180 if (p->next && p->next->prev != p)
181 return False;
182 if (p->next == 0 && p != ti->last)
183 return False;
184 }
185 for (p = ti->last; p; p = p->prev) {
186 if (p->prev && p->prev->next != p)
187 return False;
188 if (p->prev == 0 && p != ti->first)
189 return False;
190 }
191 return True;
sewardjaf44c822007-11-25 14:01:38 +0000192}
193
194DrdThreadId thread_pre_create(const DrdThreadId creator,
195 const ThreadId vg_created)
196{
bart3772a982008-03-15 08:11:03 +0000197 DrdThreadId created;
sewardjaf44c822007-11-25 14:01:38 +0000198
bart3772a982008-03-15 08:11:03 +0000199 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
200 created = VgThreadIdToNewDrdThreadId(vg_created);
201 tl_assert(0 <= created && created < DRD_N_THREADS
202 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000203
bart3772a982008-03-15 08:11:03 +0000204 tl_assert(s_threadinfo[created].first == 0);
205 tl_assert(s_threadinfo[created].last == 0);
206 thread_append_segment(created, sg_new(creator, created));
sewardjaf44c822007-11-25 14:01:38 +0000207
bart3772a982008-03-15 08:11:03 +0000208 return created;
sewardjaf44c822007-11-25 14:01:38 +0000209}
210
bart26f73e12008-02-24 18:37:08 +0000211/** Allocate the first segment for a thread. Call this just after
212 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000213 */
214DrdThreadId thread_post_create(const ThreadId vg_created)
215{
bart3772a982008-03-15 08:11:03 +0000216 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
sewardjaf44c822007-11-25 14:01:38 +0000217
bart3772a982008-03-15 08:11:03 +0000218 tl_assert(0 <= created && created < DRD_N_THREADS
219 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000220
bart3772a982008-03-15 08:11:03 +0000221 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
222 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
223 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
bart3772a982008-03-15 08:11:03 +0000224 tl_assert(s_threadinfo[created].stack_max != 0);
sewardjaf44c822007-11-25 14:01:38 +0000225
bart3772a982008-03-15 08:11:03 +0000226 return created;
sewardjaf44c822007-11-25 14:01:38 +0000227}
228
229/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
230/* and accesses this data structure from multiple threads without locking. */
231/* Any conflicting accesses in the range stack_startup..stack_max will be */
232/* ignored. */
233void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
234{
bart3772a982008-03-15 08:11:03 +0000235 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
236 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
237 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
238 s_threadinfo[tid].stack_startup = stack_startup;
sewardjaf44c822007-11-25 14:01:38 +0000239}
240
241Addr thread_get_stack_min(const DrdThreadId tid)
242{
bart3772a982008-03-15 08:11:03 +0000243 tl_assert(0 <= tid && tid < DRD_N_THREADS
244 && tid != DRD_INVALID_THREADID);
245 return s_threadinfo[tid].stack_min;
sewardjaf44c822007-11-25 14:01:38 +0000246}
247
bartd43f8d32008-03-16 17:29:20 +0000248Addr thread_get_stack_max(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000249{
bartd43f8d32008-03-16 17:29:20 +0000250 tl_assert(0 <= tid && tid < DRD_N_THREADS
251 && tid != DRD_INVALID_THREADID);
252 return s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000253}
254
barta2b6e1b2008-03-17 18:32:39 +0000255/** Clean up thread-specific data structures. Call this just after
256 * pthread_join().
sewardjaf44c822007-11-25 14:01:38 +0000257 */
258void thread_delete(const DrdThreadId tid)
259{
bart3772a982008-03-15 08:11:03 +0000260 Segment* sg;
261 Segment* sg_prev;
sewardjaf44c822007-11-25 14:01:38 +0000262
bart3772a982008-03-15 08:11:03 +0000263 tl_assert(0 <= tid && tid < DRD_N_THREADS
264 && tid != DRD_INVALID_THREADID);
265 tl_assert(s_threadinfo[tid].synchr_nesting == 0);
266 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
267 {
268 sg_prev = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000269 sg->prev = 0;
270 sg->next = 0;
271 sg_put(sg);
bart3772a982008-03-15 08:11:03 +0000272 }
273 s_threadinfo[tid].vg_thread_exists = False;
274 s_threadinfo[tid].posix_thread_exists = False;
275 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
276 s_threadinfo[tid].first = 0;
277 s_threadinfo[tid].last = 0;
sewardjaf44c822007-11-25 14:01:38 +0000278}
279
280/* Called after a thread performed its last memory access and before */
281/* thread_delete() is called. Note: thread_delete() is only called for */
282/* joinable threads, not for detached threads. */
283void thread_finished(const DrdThreadId tid)
284{
bart3772a982008-03-15 08:11:03 +0000285 tl_assert(0 <= tid && tid < DRD_N_THREADS
286 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000287
bart3772a982008-03-15 08:11:03 +0000288 s_threadinfo[tid].vg_thread_exists = False;
sewardjaf44c822007-11-25 14:01:38 +0000289
bart3772a982008-03-15 08:11:03 +0000290 if (s_threadinfo[tid].detached_posix_thread)
291 {
292 /* Once a detached thread has finished, its stack is deallocated and */
293 /* should no longer be taken into account when computing the danger set*/
294 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000295
bart3772a982008-03-15 08:11:03 +0000296 /* For a detached thread, calling pthread_exit() invalidates the */
297 /* POSIX thread ID associated with the detached thread. For joinable */
298 /* POSIX threads however, the POSIX thread ID remains live after the */
299 /* pthread_exit() call until pthread_join() is called. */
300 s_threadinfo[tid].posix_thread_exists = False;
301 }
sewardjaf44c822007-11-25 14:01:38 +0000302}
303
304void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
305{
bart3772a982008-03-15 08:11:03 +0000306 tl_assert(0 <= tid && tid < DRD_N_THREADS
307 && tid != DRD_INVALID_THREADID);
308 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
309 tl_assert(ptid != INVALID_POSIX_THREADID);
310 s_threadinfo[tid].posix_thread_exists = True;
311 s_threadinfo[tid].pt_threadid = ptid;
sewardjaf44c822007-11-25 14:01:38 +0000312}
313
314Bool thread_get_joinable(const DrdThreadId tid)
315{
bart3772a982008-03-15 08:11:03 +0000316 tl_assert(0 <= tid && tid < DRD_N_THREADS
317 && tid != DRD_INVALID_THREADID);
318 return ! s_threadinfo[tid].detached_posix_thread;
sewardjaf44c822007-11-25 14:01:38 +0000319}
320
321void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
322{
bart3772a982008-03-15 08:11:03 +0000323 tl_assert(0 <= tid && tid < DRD_N_THREADS
324 && tid != DRD_INVALID_THREADID);
325 tl_assert(!! joinable == joinable);
326 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000327#if 0
bart3772a982008-03-15 08:11:03 +0000328 VG_(message)(Vg_DebugMsg,
329 "thread_set_joinable(%d/%d, %s)",
330 tid,
331 s_threadinfo[tid].vg_threadid,
332 joinable ? "joinable" : "detached");
sewardjaf44c822007-11-25 14:01:38 +0000333#endif
bart3772a982008-03-15 08:11:03 +0000334 s_threadinfo[tid].detached_posix_thread = ! joinable;
sewardjaf44c822007-11-25 14:01:38 +0000335}
336
sewardj8b09d4f2007-12-04 21:27:18 +0000337void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000338{
bart3772a982008-03-15 08:11:03 +0000339 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000340
bart3772a982008-03-15 08:11:03 +0000341 if (vg_tid != s_vg_running_tid)
342 {
343 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
344 }
sewardj8b09d4f2007-12-04 21:27:18 +0000345
bart3772a982008-03-15 08:11:03 +0000346 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
347 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000348}
349
350void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
351{
bart3772a982008-03-15 08:11:03 +0000352 tl_assert(vg_tid != VG_INVALID_THREADID);
353 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000354
bart3772a982008-03-15 08:11:03 +0000355 if (vg_tid != s_vg_running_tid)
356 {
357 if (s_trace_context_switches
358 && s_drd_running_tid != DRD_INVALID_THREADID)
359 {
360 VG_(message)(Vg_DebugMsg,
barta2b6e1b2008-03-17 18:32:39 +0000361 "Context switch from thread %d/%d to thread %d/%d;"
362 " segments: %llu",
bartaa97a542008-03-16 17:57:01 +0000363 s_vg_running_tid, s_drd_running_tid,
barta2b6e1b2008-03-17 18:32:39 +0000364 DrdThreadIdToVgThreadId(drd_tid), drd_tid,
365 sg_get_alive_segments_count());
bart3772a982008-03-15 08:11:03 +0000366 }
367 s_vg_running_tid = vg_tid;
368 s_drd_running_tid = drd_tid;
369 thread_update_danger_set(drd_tid);
370 s_context_switch_count++;
371 }
sewardj8b09d4f2007-12-04 21:27:18 +0000372
bart3772a982008-03-15 08:11:03 +0000373 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
374 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000375}
376
bart0268dfa2008-03-11 20:10:21 +0000377int thread_enter_synchr(const DrdThreadId tid)
378{
bart3772a982008-03-15 08:11:03 +0000379 tl_assert(IsValidDrdThreadId(tid));
380 return s_threadinfo[tid].synchr_nesting++;
bart0268dfa2008-03-11 20:10:21 +0000381}
382
383int thread_leave_synchr(const DrdThreadId tid)
384{
bart3772a982008-03-15 08:11:03 +0000385 tl_assert(IsValidDrdThreadId(tid));
386 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
387 return --s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000388}
389
390int thread_get_synchr_nesting_count(const DrdThreadId tid)
391{
bart3772a982008-03-15 08:11:03 +0000392 tl_assert(IsValidDrdThreadId(tid));
393 return s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000394}
395
bart1a473c72008-03-13 19:03:38 +0000396/** Append a new segment at the end of the segment list. */
bart26f73e12008-02-24 18:37:08 +0000397static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000398{
bart3772a982008-03-15 08:11:03 +0000399 tl_assert(0 <= tid && tid < DRD_N_THREADS
400 && tid != DRD_INVALID_THREADID);
401 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
402 sg->prev = s_threadinfo[tid].last;
403 sg->next = 0;
404 if (s_threadinfo[tid].last)
405 s_threadinfo[tid].last->next = sg;
406 s_threadinfo[tid].last = sg;
407 if (s_threadinfo[tid].first == 0)
408 s_threadinfo[tid].first = sg;
409 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000410}
411
bart26f73e12008-02-24 18:37:08 +0000412/** Remove a segment from the segment list of thread threadid, and free the
413 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000414 */
bart26f73e12008-02-24 18:37:08 +0000415static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000416{
bart3772a982008-03-15 08:11:03 +0000417 tl_assert(0 <= tid && tid < DRD_N_THREADS
418 && tid != DRD_INVALID_THREADID);
419 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000420
bart3772a982008-03-15 08:11:03 +0000421 if (sg->prev)
422 sg->prev->next = sg->next;
423 if (sg->next)
424 sg->next->prev = sg->prev;
425 if (sg == s_threadinfo[tid].first)
426 s_threadinfo[tid].first = sg->next;
427 if (sg == s_threadinfo[tid].last)
428 s_threadinfo[tid].last = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000429 sg_put(sg);
bart3772a982008-03-15 08:11:03 +0000430 tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000431}
432
433VectorClock* thread_get_vc(const DrdThreadId tid)
434{
barta2b6e1b2008-03-17 18:32:39 +0000435 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000436 tl_assert(s_threadinfo[tid].last);
437 return &s_threadinfo[tid].last->vc;
sewardjaf44c822007-11-25 14:01:38 +0000438}
439
barta2b6e1b2008-03-17 18:32:39 +0000440/** Return the latest segment of thread 'tid' and increment its reference
441 * count.
442 */
443void thread_get_latest_segment(Segment** sg, const DrdThreadId tid)
444{
445 tl_assert(sg);
446 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
447 tl_assert(s_threadinfo[tid].last);
448
449 sg_put(*sg);
450 *sg = sg_get(s_threadinfo[tid].last);
451}
452
sewardjaf44c822007-11-25 14:01:38 +0000453/**
454 * Compute the minimum of all latest vector clocks of all threads
455 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
456 * @param vc pointer to a vectorclock, holds result upon return.
457 */
458static void thread_compute_minimum_vc(VectorClock* vc)
459{
bart3772a982008-03-15 08:11:03 +0000460 unsigned i;
461 Bool first;
462 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000463
bart3772a982008-03-15 08:11:03 +0000464 first = True;
465 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
466 {
467 latest_sg = s_threadinfo[i].last;
468 if (latest_sg)
469 {
470 if (first)
471 vc_assign(vc, &latest_sg->vc);
472 else
473 vc_min(vc, &latest_sg->vc);
474 first = False;
475 }
476 }
sewardjaf44c822007-11-25 14:01:38 +0000477}
478
479static void thread_compute_maximum_vc(VectorClock* vc)
480{
bart3772a982008-03-15 08:11:03 +0000481 unsigned i;
482 Bool first;
483 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000484
bart3772a982008-03-15 08:11:03 +0000485 first = True;
486 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
487 {
488 latest_sg = s_threadinfo[i].last;
489 if (latest_sg)
490 {
491 if (first)
492 vc_assign(vc, &latest_sg->vc);
493 else
494 vc_combine(vc, &latest_sg->vc);
495 first = False;
496 }
497 }
sewardjaf44c822007-11-25 14:01:38 +0000498}
499
500/**
bart5bd9f2d2008-03-03 20:31:58 +0000501 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000502 * clock of every thread -- these segments can no longer be involved in a
503 * data race.
504 */
505static void thread_discard_ordered_segments(void)
506{
bart3772a982008-03-15 08:11:03 +0000507 unsigned i;
508 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000509
bart3772a982008-03-15 08:11:03 +0000510 s_discard_ordered_segments_count++;
sewardjaf44c822007-11-25 14:01:38 +0000511
bart3772a982008-03-15 08:11:03 +0000512 vc_init(&thread_vc_min, 0, 0);
513 thread_compute_minimum_vc(&thread_vc_min);
514 if (sg_get_trace())
515 {
516 char msg[256];
517 VectorClock thread_vc_max;
sewardjaf44c822007-11-25 14:01:38 +0000518
bart3772a982008-03-15 08:11:03 +0000519 vc_init(&thread_vc_max, 0, 0);
520 thread_compute_maximum_vc(&thread_vc_max);
521 VG_(snprintf)(msg, sizeof(msg),
522 "Discarding ordered segments -- min vc is ");
523 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
524 &thread_vc_min);
525 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
526 ", max vc is ");
527 vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
528 &thread_vc_max);
barta2b6e1b2008-03-17 18:32:39 +0000529 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000530 vc_cleanup(&thread_vc_max);
531 }
sewardjaf44c822007-11-25 14:01:38 +0000532
bart3772a982008-03-15 08:11:03 +0000533 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
534 {
535 Segment* sg;
536 Segment* sg_next;
537 for (sg = s_threadinfo[i].first;
538 sg && (sg_next = sg->next) && vc_lte(&sg->vc, &thread_vc_min);
539 sg = sg_next)
540 {
541 thread_discard_segment(i, sg);
542 }
543 }
544 vc_cleanup(&thread_vc_min);
sewardjaf44c822007-11-25 14:01:38 +0000545}
546
barta9c37392008-03-22 09:38:48 +0000547/** Merge all segments that may be merged without triggering false positives
548 * or discarding real data races. For the theoretical background of segment
549 * merging, see also the following paper:
550 * Mark Christiaens, Michiel Ronsse and Koen De Bosschere.
551 * Bounding the number of segment histories during data race detection.
552 * Parallel Computing archive, Volume 28, Issue 9, pp 1221-1238,
553 * September 2002.
554 */
555static void thread_merge_segments(void)
556{
557 unsigned i;
558
559 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
560 {
561 Segment* sg;
562
563 tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
564
565 for (sg = s_threadinfo[i].first; sg; sg = sg->next)
566 {
567 if (sg_get_refcnt(sg) == 1
568 && sg->next
569 && sg_get_refcnt(sg->next) == 1
570 && sg->next->next)
571 {
572 /* Merge sg and sg->next into sg. */
573 sg_merge(sg, sg->next);
574 thread_discard_segment(i, sg->next);
575 }
576 }
577
578 tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
579 }
580}
581
barta2b6e1b2008-03-17 18:32:39 +0000582/** Create a new segment for the specified thread, and discard any segments
583 * that cannot cause races anymore.
sewardjaf44c822007-11-25 14:01:38 +0000584 */
585void thread_new_segment(const DrdThreadId tid)
586{
barta2b6e1b2008-03-17 18:32:39 +0000587 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000588
barta2b6e1b2008-03-17 18:32:39 +0000589 thread_append_segment(tid, sg_new(tid, tid));
sewardjaf44c822007-11-25 14:01:38 +0000590
bart3772a982008-03-15 08:11:03 +0000591 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000592
barta9c37392008-03-22 09:38:48 +0000593 if (s_segment_merging)
594 thread_merge_segments();
595
bart3772a982008-03-15 08:11:03 +0000596 if (tid == s_drd_running_tid)
597 {
598 /* Every change in the vector clock of the current thread may cause */
599 /* segments that were previously ordered to this thread to become */
600 /* unordered. Hence, recalculate the danger set if the vector clock */
601 /* of the current thread is updated. */
602 thread_update_danger_set(tid);
603 }
sewardjaf44c822007-11-25 14:01:38 +0000604}
605
bart26f73e12008-02-24 18:37:08 +0000606/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000607void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
608{
bart3772a982008-03-15 08:11:03 +0000609 tl_assert(joiner != joinee);
610 tl_assert(0 <= joiner && joiner < DRD_N_THREADS
611 && joiner != DRD_INVALID_THREADID);
612 tl_assert(0 <= joinee && joinee < DRD_N_THREADS
613 && joinee != DRD_INVALID_THREADID);
614 tl_assert(s_threadinfo[joiner].last);
615 tl_assert(s_threadinfo[joinee].last);
616 vc_combine(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
617 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000618
bart3772a982008-03-15 08:11:03 +0000619 if (joiner == s_drd_running_tid)
620 {
621 thread_update_danger_set(joiner);
622 }
sewardjaf44c822007-11-25 14:01:38 +0000623}
624
bart26f73e12008-02-24 18:37:08 +0000625/** Call this function after thread 'tid' had to wait because of thread
626 * synchronization until the memory accesses in the segment with vector clock
627 * 'vc' finished.
628 */
sewardjaf44c822007-11-25 14:01:38 +0000629void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
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].last);
633 tl_assert(vc);
634 vc_combine(&s_threadinfo[tid].last->vc, vc);
635 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000636}
637
bart26f73e12008-02-24 18:37:08 +0000638/** Call this function whenever a thread is no longer using the memory
639 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
640 * increase.
641 */
sewardjaf44c822007-11-25 14:01:38 +0000642void thread_stop_using_mem(const Addr a1, const Addr a2)
643{
bartd43f8d32008-03-16 17:29:20 +0000644 DrdThreadId other_user;
645 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000646
bart3772a982008-03-15 08:11:03 +0000647 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
bartd43f8d32008-03-16 17:29:20 +0000648 other_user = DRD_INVALID_THREADID;
bart3772a982008-03-15 08:11:03 +0000649 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
650 {
651 Segment* p;
652 for (p = s_threadinfo[i].first; p; p = p->next)
653 {
654 if (other_user == DRD_INVALID_THREADID
655 && i != s_drd_running_tid
656 && bm_has_any_access(p->bm, a1, a2))
sewardjaf44c822007-11-25 14:01:38 +0000657 {
bart3772a982008-03-15 08:11:03 +0000658 other_user = i;
sewardjaf44c822007-11-25 14:01:38 +0000659 }
bart3772a982008-03-15 08:11:03 +0000660 bm_clear(p->bm, a1, a2);
661 }
662 }
sewardjaf44c822007-11-25 14:01:38 +0000663
bart3772a982008-03-15 08:11:03 +0000664 /* If any other thread had accessed memory in [ a1, a2 [, update the */
665 /* danger set. */
666 if (other_user != DRD_INVALID_THREADID
667 && bm_has_any_access(s_danger_set, a1, a2))
668 {
669 thread_update_danger_set(thread_get_running_tid());
670 }
sewardjaf44c822007-11-25 14:01:38 +0000671}
672
bart0268dfa2008-03-11 20:10:21 +0000673void thread_start_recording(const DrdThreadId tid)
674{
bart3772a982008-03-15 08:11:03 +0000675 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
676 tl_assert(! s_threadinfo[tid].is_recording);
677 s_threadinfo[tid].is_recording = True;
bart0268dfa2008-03-11 20:10:21 +0000678}
679
680void thread_stop_recording(const DrdThreadId tid)
681{
bart3772a982008-03-15 08:11:03 +0000682 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
683 tl_assert(s_threadinfo[tid].is_recording);
684 s_threadinfo[tid].is_recording = False;
bart0268dfa2008-03-11 20:10:21 +0000685}
686
sewardjaf44c822007-11-25 14:01:38 +0000687void thread_print_all(void)
688{
bart3772a982008-03-15 08:11:03 +0000689 unsigned i;
690 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000691
bart3772a982008-03-15 08:11:03 +0000692 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
693 {
694 if (s_threadinfo[i].first)
695 {
696 VG_(printf)("**************\n"
barta2b6e1b2008-03-17 18:32:39 +0000697 "* thread %3d (%d/%d/%d/0x%lx/%d) *\n"
bart3772a982008-03-15 08:11:03 +0000698 "**************\n",
699 i,
700 s_threadinfo[i].vg_thread_exists,
701 s_threadinfo[i].vg_threadid,
702 s_threadinfo[i].posix_thread_exists,
703 s_threadinfo[i].pt_threadid,
bart354009c2008-03-16 10:42:33 +0000704 s_threadinfo[i].detached_posix_thread);
bart3772a982008-03-15 08:11:03 +0000705 for (p = s_threadinfo[i].first; p; p = p->next)
sewardjaf44c822007-11-25 14:01:38 +0000706 {
bart3772a982008-03-15 08:11:03 +0000707 sg_print(p);
sewardjaf44c822007-11-25 14:01:38 +0000708 }
bart3772a982008-03-15 08:11:03 +0000709 }
710 }
sewardjaf44c822007-11-25 14:01:38 +0000711}
712
713static void show_call_stack(const DrdThreadId tid,
714 const Char* const msg,
715 ExeContext* const callstack)
716{
bart3772a982008-03-15 08:11:03 +0000717 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000718
bartaa97a542008-03-16 17:57:01 +0000719 VG_(message)(Vg_UserMsg, "%s (thread %d/%d)", msg, vg_tid, tid);
sewardjaf44c822007-11-25 14:01:38 +0000720
bart3772a982008-03-15 08:11:03 +0000721 if (vg_tid != VG_INVALID_THREADID)
722 {
723 if (callstack)
724 {
725 VG_(pp_ExeContext)(callstack);
726 }
727 else
728 {
729 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
730 }
731 }
732 else
733 {
734 VG_(message)(Vg_UserMsg,
735 " (thread finished, call stack no longer available)");
736 }
sewardjaf44c822007-11-25 14:01:38 +0000737}
738
sewardjaf44c822007-11-25 14:01:38 +0000739static void
740thread_report_conflicting_segments_segment(const DrdThreadId tid,
741 const Addr addr,
742 const SizeT size,
743 const BmAccessTypeT access_type,
744 const Segment* const p)
745{
bart3772a982008-03-15 08:11:03 +0000746 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000747
bart3772a982008-03-15 08:11:03 +0000748 tl_assert(0 <= tid && tid < DRD_N_THREADS
749 && tid != DRD_INVALID_THREADID);
750 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000751
bart3772a982008-03-15 08:11:03 +0000752 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
753 {
754 if (i != tid)
755 {
756 Segment* q;
757 for (q = s_threadinfo[i].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000758 {
bart3772a982008-03-15 08:11:03 +0000759 // Since q iterates over the segments of thread i in order of
760 // decreasing vector clocks, if q->vc <= p->vc, then
761 // q->next->vc <= p->vc will also hold. Hence, break out of the
762 // loop once this condition is met.
763 if (vc_lte(&q->vc, &p->vc))
764 break;
765 if (! vc_lte(&p->vc, &q->vc))
766 {
767 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
768 {
769 tl_assert(q->stacktrace);
770 show_call_stack(i, "Other segment start",
771 q->stacktrace);
772 show_call_stack(i, "Other segment end",
773 q->next ? q->next->stacktrace : 0);
774 }
775 }
sewardjaf44c822007-11-25 14:01:38 +0000776 }
bart3772a982008-03-15 08:11:03 +0000777 }
778 }
sewardjaf44c822007-11-25 14:01:38 +0000779}
780
781void thread_report_conflicting_segments(const DrdThreadId tid,
782 const Addr addr,
783 const SizeT size,
784 const BmAccessTypeT access_type)
785{
bart3772a982008-03-15 08:11:03 +0000786 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000787
bart3772a982008-03-15 08:11:03 +0000788 tl_assert(0 <= tid && tid < DRD_N_THREADS
789 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000790
bart3772a982008-03-15 08:11:03 +0000791 for (p = s_threadinfo[tid].first; p; p = p->next)
792 {
793 if (bm_has(p->bm, addr, addr + size, access_type))
794 {
795 thread_report_conflicting_segments_segment(tid, addr, size,
796 access_type, p);
797 }
798 }
sewardjaf44c822007-11-25 14:01:38 +0000799}
sewardjaf44c822007-11-25 14:01:38 +0000800
bart26f73e12008-02-24 18:37:08 +0000801/** Compute a bitmap that represents the union of all memory accesses of all
802 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +0000803 */
804static void thread_update_danger_set(const DrdThreadId tid)
805{
bart3772a982008-03-15 08:11:03 +0000806 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000807
bart3772a982008-03-15 08:11:03 +0000808 tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
809 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +0000810
bart3772a982008-03-15 08:11:03 +0000811 s_update_danger_set_count++;
812 s_danger_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
813 s_danger_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000814
bart3772a982008-03-15 08:11:03 +0000815 if (s_danger_set)
816 {
bart1ea5fff2008-03-16 08:36:23 +0000817 bm_delete(s_danger_set);
bart3772a982008-03-15 08:11:03 +0000818 }
bart1ea5fff2008-03-16 08:36:23 +0000819 s_danger_set = bm_new();
bart26f73e12008-02-24 18:37:08 +0000820
bart3772a982008-03-15 08:11:03 +0000821 if (s_trace_danger_set)
822 {
823 char msg[256];
824
825 VG_(snprintf)(msg, sizeof(msg),
bartaa97a542008-03-16 17:57:01 +0000826 "computing danger set for thread %d/%d with vc ",
827 DrdThreadIdToVgThreadId(tid), tid);
bart3772a982008-03-15 08:11:03 +0000828 vc_snprint(msg + VG_(strlen)(msg),
829 sizeof(msg) - VG_(strlen)(msg),
830 &s_threadinfo[tid].last->vc);
barta2b6e1b2008-03-17 18:32:39 +0000831 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000832 }
833
834 p = s_threadinfo[tid].last;
835 {
836 unsigned j;
837
838 if (s_trace_danger_set)
839 {
bart26f73e12008-02-24 18:37:08 +0000840 char msg[256];
841
842 VG_(snprintf)(msg, sizeof(msg),
bart3772a982008-03-15 08:11:03 +0000843 "danger set: thread [%d] at vc ",
bart26f73e12008-02-24 18:37:08 +0000844 tid);
845 vc_snprint(msg + VG_(strlen)(msg),
846 sizeof(msg) - VG_(strlen)(msg),
bart3772a982008-03-15 08:11:03 +0000847 &p->vc);
barta2b6e1b2008-03-17 18:32:39 +0000848 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000849 }
sewardjaf44c822007-11-25 14:01:38 +0000850
bart3772a982008-03-15 08:11:03 +0000851 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
852 {
853 if (IsValidDrdThreadId(j))
bart26f73e12008-02-24 18:37:08 +0000854 {
bart3772a982008-03-15 08:11:03 +0000855 const Segment* q;
856 for (q = s_threadinfo[j].last; q; q = q->prev)
857 if (j != tid && q != 0
858 && ! vc_lte(&q->vc, &p->vc) && ! vc_lte(&p->vc, &q->vc))
859 {
860 if (s_trace_danger_set)
861 {
862 char msg[256];
863 VG_(snprintf)(msg, sizeof(msg),
864 "danger set: [%d] merging segment ", j);
865 vc_snprint(msg + VG_(strlen)(msg),
866 sizeof(msg) - VG_(strlen)(msg),
867 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +0000868 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000869 }
870 bm_merge2(s_danger_set, q->bm);
871 }
872 else
873 {
874 if (s_trace_danger_set)
875 {
876 char msg[256];
877 VG_(snprintf)(msg, sizeof(msg),
878 "danger set: [%d] ignoring segment ", j);
879 vc_snprint(msg + VG_(strlen)(msg),
880 sizeof(msg) - VG_(strlen)(msg),
881 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +0000882 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +0000883 }
884 }
bart26f73e12008-02-24 18:37:08 +0000885 }
bart3772a982008-03-15 08:11:03 +0000886 }
bart26f73e12008-02-24 18:37:08 +0000887
bart3772a982008-03-15 08:11:03 +0000888 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
889 {
890 if (IsValidDrdThreadId(j))
sewardjaf44c822007-11-25 14:01:38 +0000891 {
bart3772a982008-03-15 08:11:03 +0000892 // NPTL hack: don't report data races on sizeof(struct pthread)
893 // bytes at the top of the stack, since the NPTL functions access
894 // this data without locking.
895 if (s_threadinfo[j].stack_min != 0)
896 {
897 tl_assert(s_threadinfo[j].stack_startup != 0);
898 if (s_threadinfo[j].stack_min < s_threadinfo[j].stack_startup)
899 {
900 bm_clear(s_danger_set,
901 s_threadinfo[j].stack_min,
902 s_threadinfo[j].stack_startup);
903 }
904 }
sewardjaf44c822007-11-25 14:01:38 +0000905 }
bart3772a982008-03-15 08:11:03 +0000906 }
907 }
sewardjaf44c822007-11-25 14:01:38 +0000908
bart3772a982008-03-15 08:11:03 +0000909 s_danger_set_bitmap_creation_count += bm_get_bitmap_creation_count();
910 s_danger_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +0000911
bart3772a982008-03-15 08:11:03 +0000912 if (0 && s_trace_danger_set)
913 {
barta2b6e1b2008-03-17 18:32:39 +0000914 VG_(message)(Vg_UserMsg, "[%d] new danger set:", tid);
bart3772a982008-03-15 08:11:03 +0000915 bm_print(s_danger_set);
barta2b6e1b2008-03-17 18:32:39 +0000916 VG_(message)(Vg_UserMsg, "[%d] end of new danger set.", tid);
bart3772a982008-03-15 08:11:03 +0000917 }
sewardjaf44c822007-11-25 14:01:38 +0000918}
919
sewardjaf44c822007-11-25 14:01:38 +0000920ULong thread_get_context_switch_count(void)
921{
bart3772a982008-03-15 08:11:03 +0000922 return s_context_switch_count;
sewardjaf44c822007-11-25 14:01:38 +0000923}
924
sewardjaf44c822007-11-25 14:01:38 +0000925ULong thread_get_discard_ordered_segments_count(void)
926{
bart3772a982008-03-15 08:11:03 +0000927 return s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +0000928}
929
930ULong thread_get_update_danger_set_count(void)
931{
bart3772a982008-03-15 08:11:03 +0000932 return s_update_danger_set_count;
sewardjaf44c822007-11-25 14:01:38 +0000933}
934
935ULong thread_get_danger_set_bitmap_creation_count(void)
936{
bart3772a982008-03-15 08:11:03 +0000937 return s_danger_set_bitmap_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000938}
939
940ULong thread_get_danger_set_bitmap2_creation_count(void)
941{
bart3772a982008-03-15 08:11:03 +0000942 return s_danger_set_bitmap2_creation_count;
sewardjaf44c822007-11-25 14:01:38 +0000943}