blob: 170b527aa9c8876958224706f5c4ab40c740e987 [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"
bart09dc13f2009-02-14 15:13:31 +000027#include "drd_barrier.h"
28#include "drd_cond.h"
29#include "drd_mutex.h"
sewardjaf44c822007-11-25 14:01:38 +000030#include "drd_segment.h"
bart09dc13f2009-02-14 15:13:31 +000031#include "drd_semaphore.h"
sewardjaf44c822007-11-25 14:01:38 +000032#include "drd_suppression.h"
33#include "drd_thread.h"
bart82195c12008-04-13 17:35:08 +000034#include "pub_tool_vki.h"
sewardjaf44c822007-11-25 14:01:38 +000035#include "pub_tool_basics.h" // Addr, SizeT
36#include "pub_tool_errormgr.h" // VG_(unique_error)()
37#include "pub_tool_libcassert.h" // tl_assert()
38#include "pub_tool_libcbase.h" // VG_(strlen)()
39#include "pub_tool_libcprint.h" // VG_(printf)()
bart82195c12008-04-13 17:35:08 +000040#include "pub_tool_libcproc.h" // VG_(getenv)()
sewardjaf44c822007-11-25 14:01:38 +000041#include "pub_tool_machine.h"
42#include "pub_tool_mallocfree.h" // VG_(malloc)(), VG_(free)()
sewardj85642922008-01-14 11:54:56 +000043#include "pub_tool_options.h" // VG_(clo_backtrace_size)
sewardjaf44c822007-11-25 14:01:38 +000044#include "pub_tool_threadstate.h" // VG_(get_pthread_id)()
45
bart32ba2082008-06-05 08:53:42 +000046
sewardjaf44c822007-11-25 14:01:38 +000047
sewardjaf44c822007-11-25 14:01:38 +000048// Local functions.
49
50static void thread_append_segment(const DrdThreadId tid,
51 Segment* const sg);
barta2b6e1b2008-03-17 18:32:39 +000052static void thread_discard_segment(const DrdThreadId tid, Segment* const sg);
barte73b0aa2008-06-28 07:19:56 +000053static Bool thread_conflict_set_up_to_date(const DrdThreadId tid);
54static void thread_compute_conflict_set(struct bitmap** conflict_set,
55 const DrdThreadId tid);
sewardjaf44c822007-11-25 14:01:38 +000056
57
58// Local variables.
59
60static ULong s_context_switch_count;
61static ULong s_discard_ordered_segments_count;
barte73b0aa2008-06-28 07:19:56 +000062static ULong s_update_conflict_set_count;
63static ULong s_conflict_set_new_segment_count;
64static ULong s_conflict_set_combine_vc_count;
65static ULong s_conflict_set_bitmap_creation_count;
66static ULong s_conflict_set_bitmap2_creation_count;
sewardj8b09d4f2007-12-04 21:27:18 +000067static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
bartf00a85b2008-03-13 18:49:23 +000068DrdThreadId s_drd_running_tid = DRD_INVALID_THREADID;
69ThreadInfo s_threadinfo[DRD_N_THREADS];
barte73b0aa2008-06-28 07:19:56 +000070struct bitmap* s_conflict_set;
bart26f73e12008-02-24 18:37:08 +000071static Bool s_trace_context_switches = False;
barte73b0aa2008-06-28 07:19:56 +000072static Bool s_trace_conflict_set = False;
bart09dc13f2009-02-14 15:13:31 +000073static Bool s_trace_fork_join = False;
barta9c37392008-03-22 09:38:48 +000074static Bool s_segment_merging = True;
sewardjaf44c822007-11-25 14:01:38 +000075
76
77// Function definitions.
78
bart26f73e12008-02-24 18:37:08 +000079void thread_trace_context_switches(const Bool t)
80{
bart09dc13f2009-02-14 15:13:31 +000081 tl_assert(t == False || t == True);
bart3772a982008-03-15 08:11:03 +000082 s_trace_context_switches = t;
bart26f73e12008-02-24 18:37:08 +000083}
84
barte73b0aa2008-06-28 07:19:56 +000085void thread_trace_conflict_set(const Bool t)
bart26f73e12008-02-24 18:37:08 +000086{
bart09dc13f2009-02-14 15:13:31 +000087 tl_assert(t == False || t == True);
barte73b0aa2008-06-28 07:19:56 +000088 s_trace_conflict_set = t;
bart26f73e12008-02-24 18:37:08 +000089}
90
bart09dc13f2009-02-14 15:13:31 +000091Bool DRD_(thread_get_trace_fork_join)(void)
92{
93 return s_trace_fork_join;
94}
95
96void DRD_(thread_set_trace_fork_join)(const Bool t)
97{
98 tl_assert(t == False || t == True);
99 s_trace_fork_join = t;
100}
101
barta9c37392008-03-22 09:38:48 +0000102void thread_set_segment_merging(const Bool m)
103{
bart09dc13f2009-02-14 15:13:31 +0000104 tl_assert(m == False || m == True);
barta9c37392008-03-22 09:38:48 +0000105 s_segment_merging = m;
106}
107
sewardjaf44c822007-11-25 14:01:38 +0000108/**
109 * Convert Valgrind's ThreadId into a DrdThreadId. Report failure if
110 * Valgrind's ThreadId does not yet exist.
111 **/
112DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid)
113{
bart3772a982008-03-15 08:11:03 +0000114 int i;
sewardjaf44c822007-11-25 14:01:38 +0000115
bart3772a982008-03-15 08:11:03 +0000116 if (tid == VG_INVALID_THREADID)
117 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000118
bart3772a982008-03-15 08:11:03 +0000119 for (i = 1; i < DRD_N_THREADS; i++)
120 {
121 if (s_threadinfo[i].vg_thread_exists == True
122 && s_threadinfo[i].vg_threadid == tid)
123 {
124 return i;
125 }
126 }
sewardjaf44c822007-11-25 14:01:38 +0000127
bart3772a982008-03-15 08:11:03 +0000128 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000129}
130
131static
132DrdThreadId VgThreadIdToNewDrdThreadId(const ThreadId tid)
133{
bart3772a982008-03-15 08:11:03 +0000134 int i;
sewardjaf44c822007-11-25 14:01:38 +0000135
bart3772a982008-03-15 08:11:03 +0000136 tl_assert(VgThreadIdToDrdThreadId(tid) == DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000137
bart3772a982008-03-15 08:11:03 +0000138 for (i = 1; i < DRD_N_THREADS; i++)
139 {
140 if (s_threadinfo[i].vg_thread_exists == False
141 && s_threadinfo[i].posix_thread_exists == False
142 && s_threadinfo[i].detached_posix_thread == False)
143 {
144 s_threadinfo[i].vg_thread_exists = True;
145 s_threadinfo[i].vg_threadid = tid;
146 s_threadinfo[i].pt_threadid = INVALID_POSIX_THREADID;
bart3772a982008-03-15 08:11:03 +0000147 s_threadinfo[i].stack_min = 0;
bartcac53462008-03-29 09:27:08 +0000148 s_threadinfo[i].stack_min_min = 0;
bart3772a982008-03-15 08:11:03 +0000149 s_threadinfo[i].stack_startup = 0;
150 s_threadinfo[i].stack_max = 0;
bart3772a982008-03-15 08:11:03 +0000151 s_threadinfo[i].is_recording = True;
152 s_threadinfo[i].synchr_nesting = 0;
153 if (s_threadinfo[i].first != 0)
154 VG_(printf)("drd thread id = %d\n", i);
155 tl_assert(s_threadinfo[i].first == 0);
156 tl_assert(s_threadinfo[i].last == 0);
157 return i;
158 }
159 }
sewardjaf44c822007-11-25 14:01:38 +0000160
bart3772a982008-03-15 08:11:03 +0000161 tl_assert(False);
sewardjaf44c822007-11-25 14:01:38 +0000162
bart3772a982008-03-15 08:11:03 +0000163 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000164}
165
166DrdThreadId PtThreadIdToDrdThreadId(const PThreadId tid)
167{
bart3772a982008-03-15 08:11:03 +0000168 int i;
sewardjaf44c822007-11-25 14:01:38 +0000169
bart3772a982008-03-15 08:11:03 +0000170 tl_assert(tid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000171
bart3772a982008-03-15 08:11:03 +0000172 for (i = 1; i < DRD_N_THREADS; i++)
173 {
174 if (s_threadinfo[i].posix_thread_exists
175 && s_threadinfo[i].pt_threadid == tid)
176 {
177 return i;
178 }
179 }
180 return DRD_INVALID_THREADID;
sewardjaf44c822007-11-25 14:01:38 +0000181}
182
183ThreadId DrdThreadIdToVgThreadId(const DrdThreadId tid)
184{
bart74a5f212008-05-11 06:43:07 +0000185 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
186 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000187 return (s_threadinfo[tid].vg_thread_exists
188 ? s_threadinfo[tid].vg_threadid
189 : VG_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000190}
191
bart23d3a4e2008-04-05 12:53:00 +0000192#if 0
bart26f73e12008-02-24 18:37:08 +0000193/** Sanity check of the doubly linked list of segments referenced by a
194 * ThreadInfo struct.
195 * @return True if sane, False if not.
sewardjaf44c822007-11-25 14:01:38 +0000196 */
197static Bool sane_ThreadInfo(const ThreadInfo* const ti)
198{
bart3772a982008-03-15 08:11:03 +0000199 Segment* p;
200 for (p = ti->first; p; p = p->next) {
201 if (p->next && p->next->prev != p)
202 return False;
203 if (p->next == 0 && p != ti->last)
204 return False;
205 }
206 for (p = ti->last; p; p = p->prev) {
207 if (p->prev && p->prev->next != p)
208 return False;
209 if (p->prev == 0 && p != ti->first)
210 return False;
211 }
212 return True;
sewardjaf44c822007-11-25 14:01:38 +0000213}
bart23d3a4e2008-04-05 12:53:00 +0000214#endif
sewardjaf44c822007-11-25 14:01:38 +0000215
bart439c55f2009-02-15 10:38:37 +0000216/**
217 * Create the first segment for a newly started thread.
218 *
219 * This function is called from the handler installed via
220 * VG_(track_pre_thread_ll_create)(). The Valgrind core invokes this handler
221 * from the context of the creator thread, before the new thread has been
222 * created.
223 */
sewardjaf44c822007-11-25 14:01:38 +0000224DrdThreadId thread_pre_create(const DrdThreadId creator,
225 const ThreadId vg_created)
226{
bart3772a982008-03-15 08:11:03 +0000227 DrdThreadId created;
sewardjaf44c822007-11-25 14:01:38 +0000228
bart3772a982008-03-15 08:11:03 +0000229 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
230 created = VgThreadIdToNewDrdThreadId(vg_created);
bart74a5f212008-05-11 06:43:07 +0000231 tl_assert(0 <= (int)created && created < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000232 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000233
bart3772a982008-03-15 08:11:03 +0000234 tl_assert(s_threadinfo[created].first == 0);
235 tl_assert(s_threadinfo[created].last == 0);
bart62ada3f2009-02-14 17:19:58 +0000236 thread_append_segment(created, DRD_(sg_new)(creator, created));
sewardjaf44c822007-11-25 14:01:38 +0000237
bart3772a982008-03-15 08:11:03 +0000238 return created;
sewardjaf44c822007-11-25 14:01:38 +0000239}
240
bart439c55f2009-02-15 10:38:37 +0000241/**
242 * Initialize s_threadinfo[] for a newly created thread. Must be called after
243 * the thread has been created and before any client instructioins are run
244 * on the newly created thread, e.g. from the handler installed via
245 * VG_(track_pre_thread_first_insn)().
246 */
247DrdThreadId thread_post_create(const ThreadId vg_created)
248{
249 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
250
251 tl_assert(0 <= (int)created && created < DRD_N_THREADS
252 && created != DRD_INVALID_THREADID);
253
254 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
255 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
256 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
257 s_threadinfo[created].stack_min_min = s_threadinfo[created].stack_max;
258 s_threadinfo[created].stack_size = VG_(thread_get_stack_size)(vg_created);
259 tl_assert(s_threadinfo[created].stack_max != 0);
260
261 return created;
262}
bart09dc13f2009-02-14 15:13:31 +0000263
264/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
265/* after thread drd_joiner joined thread drd_joinee. */
266void DRD_(thread_post_join)(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
267{
268 tl_assert(IsValidDrdThreadId(drd_joiner));
269 tl_assert(IsValidDrdThreadId(drd_joinee));
270 thread_new_segment(drd_joinee);
271 thread_combine_vc(drd_joiner, drd_joinee);
272 thread_new_segment(drd_joiner);
273
274 if (s_trace_fork_join)
275 {
276 const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
277 const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
278 const unsigned msg_size = 256;
279 char* msg;
280
281 msg = VG_(malloc)("drd.main.dptj.1", msg_size);
282 tl_assert(msg);
283 VG_(snprintf)(msg, msg_size,
284 "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
285 joiner, drd_joiner, joinee, drd_joinee);
286 if (joiner)
287 {
288 VG_(snprintf)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
289 ", new vc: ");
bart41b226c2009-02-14 16:55:19 +0000290 DRD_(vc_snprint)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
291 thread_get_vc(drd_joiner));
bart09dc13f2009-02-14 15:13:31 +0000292 }
293 VG_(message)(Vg_DebugMsg, "%s", msg);
294 VG_(free)(msg);
295 }
296
297 if (! DRD_(get_check_stack_accesses)())
298 {
bart1335ecc2009-02-14 16:10:53 +0000299 DRD_(finish_suppression)(thread_get_stack_max(drd_joinee)
300 - thread_get_stack_size(drd_joinee),
301 thread_get_stack_max(drd_joinee));
bart09dc13f2009-02-14 15:13:31 +0000302 }
303 thread_delete(drd_joinee);
304 mutex_thread_delete(drd_joinee);
305 cond_thread_delete(drd_joinee);
306 semaphore_thread_delete(drd_joinee);
307 barrier_thread_delete(drd_joinee);
308}
309
sewardjaf44c822007-11-25 14:01:38 +0000310/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
311/* and accesses this data structure from multiple threads without locking. */
312/* Any conflicting accesses in the range stack_startup..stack_max will be */
313/* ignored. */
314void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
315{
bart74a5f212008-05-11 06:43:07 +0000316 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
317 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000318 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
319 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
320 s_threadinfo[tid].stack_startup = stack_startup;
sewardjaf44c822007-11-25 14:01:38 +0000321}
322
323Addr thread_get_stack_min(const DrdThreadId tid)
324{
bart74a5f212008-05-11 06:43:07 +0000325 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000326 && tid != DRD_INVALID_THREADID);
327 return s_threadinfo[tid].stack_min;
sewardjaf44c822007-11-25 14:01:38 +0000328}
329
bartcac53462008-03-29 09:27:08 +0000330Addr thread_get_stack_min_min(const DrdThreadId tid)
331{
bart74a5f212008-05-11 06:43:07 +0000332 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartcac53462008-03-29 09:27:08 +0000333 && tid != DRD_INVALID_THREADID);
334 return s_threadinfo[tid].stack_min_min;
335}
336
bartd43f8d32008-03-16 17:29:20 +0000337Addr thread_get_stack_max(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000338{
bart74a5f212008-05-11 06:43:07 +0000339 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartd43f8d32008-03-16 17:29:20 +0000340 && tid != DRD_INVALID_THREADID);
341 return s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000342}
343
bartcac53462008-03-29 09:27:08 +0000344SizeT thread_get_stack_size(const DrdThreadId tid)
345{
bart74a5f212008-05-11 06:43:07 +0000346 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartcac53462008-03-29 09:27:08 +0000347 && tid != DRD_INVALID_THREADID);
348 return s_threadinfo[tid].stack_size;
349}
350
bart09dc13f2009-02-14 15:13:31 +0000351/**
352 * Clean up thread-specific data structures. Call this just after
353 * pthread_join().
sewardjaf44c822007-11-25 14:01:38 +0000354 */
355void thread_delete(const DrdThreadId tid)
356{
bart3772a982008-03-15 08:11:03 +0000357 Segment* sg;
358 Segment* sg_prev;
sewardjaf44c822007-11-25 14:01:38 +0000359
bart74a5f212008-05-11 06:43:07 +0000360 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000361 && tid != DRD_INVALID_THREADID);
bart5c3da012009-02-14 14:46:16 +0000362 tl_assert(s_threadinfo[tid].synchr_nesting >= 0);
bart3772a982008-03-15 08:11:03 +0000363 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
364 {
365 sg_prev = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000366 sg->prev = 0;
367 sg->next = 0;
bart62ada3f2009-02-14 17:19:58 +0000368 DRD_(sg_put)(sg);
bart3772a982008-03-15 08:11:03 +0000369 }
370 s_threadinfo[tid].vg_thread_exists = False;
371 s_threadinfo[tid].posix_thread_exists = False;
372 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
373 s_threadinfo[tid].first = 0;
374 s_threadinfo[tid].last = 0;
sewardjaf44c822007-11-25 14:01:38 +0000375}
376
377/* Called after a thread performed its last memory access and before */
378/* thread_delete() is called. Note: thread_delete() is only called for */
379/* joinable threads, not for detached threads. */
380void thread_finished(const DrdThreadId tid)
381{
bart74a5f212008-05-11 06:43:07 +0000382 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000383 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000384
bart3772a982008-03-15 08:11:03 +0000385 s_threadinfo[tid].vg_thread_exists = False;
sewardjaf44c822007-11-25 14:01:38 +0000386
bart3772a982008-03-15 08:11:03 +0000387 if (s_threadinfo[tid].detached_posix_thread)
388 {
389 /* Once a detached thread has finished, its stack is deallocated and */
barte73b0aa2008-06-28 07:19:56 +0000390 /* should no longer be taken into account when computing the conflict set*/
bart3772a982008-03-15 08:11:03 +0000391 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000392
bart3772a982008-03-15 08:11:03 +0000393 /* For a detached thread, calling pthread_exit() invalidates the */
394 /* POSIX thread ID associated with the detached thread. For joinable */
395 /* POSIX threads however, the POSIX thread ID remains live after the */
396 /* pthread_exit() call until pthread_join() is called. */
397 s_threadinfo[tid].posix_thread_exists = False;
398 }
sewardjaf44c822007-11-25 14:01:38 +0000399}
400
bart9b2974a2008-09-27 12:35:31 +0000401/** Called just before pthread_cancel(). */
bartaf0691b2008-09-27 12:26:50 +0000402void thread_pre_cancel(const DrdThreadId tid)
403{
404 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
405 && tid != DRD_INVALID_THREADID);
406 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
407
408 s_threadinfo[tid].synchr_nesting = 0;
409}
410
sewardjaf44c822007-11-25 14:01:38 +0000411void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
412{
bart74a5f212008-05-11 06:43:07 +0000413 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000414 && tid != DRD_INVALID_THREADID);
415 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
416 tl_assert(ptid != INVALID_POSIX_THREADID);
417 s_threadinfo[tid].posix_thread_exists = True;
418 s_threadinfo[tid].pt_threadid = ptid;
sewardjaf44c822007-11-25 14:01:38 +0000419}
420
421Bool thread_get_joinable(const DrdThreadId tid)
422{
bart74a5f212008-05-11 06:43:07 +0000423 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000424 && tid != DRD_INVALID_THREADID);
425 return ! s_threadinfo[tid].detached_posix_thread;
sewardjaf44c822007-11-25 14:01:38 +0000426}
427
428void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
429{
bart74a5f212008-05-11 06:43:07 +0000430 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000431 && tid != DRD_INVALID_THREADID);
432 tl_assert(!! joinable == joinable);
433 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000434#if 0
bart3772a982008-03-15 08:11:03 +0000435 VG_(message)(Vg_DebugMsg,
436 "thread_set_joinable(%d/%d, %s)",
437 tid,
438 s_threadinfo[tid].vg_threadid,
439 joinable ? "joinable" : "detached");
sewardjaf44c822007-11-25 14:01:38 +0000440#endif
bart3772a982008-03-15 08:11:03 +0000441 s_threadinfo[tid].detached_posix_thread = ! joinable;
sewardjaf44c822007-11-25 14:01:38 +0000442}
443
sewardj8b09d4f2007-12-04 21:27:18 +0000444void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000445{
bart3772a982008-03-15 08:11:03 +0000446 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000447
bart3772a982008-03-15 08:11:03 +0000448 if (vg_tid != s_vg_running_tid)
449 {
450 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
451 }
sewardj8b09d4f2007-12-04 21:27:18 +0000452
bart3772a982008-03-15 08:11:03 +0000453 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
454 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000455}
456
457void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
458{
bart3772a982008-03-15 08:11:03 +0000459 tl_assert(vg_tid != VG_INVALID_THREADID);
460 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000461
bart3772a982008-03-15 08:11:03 +0000462 if (vg_tid != s_vg_running_tid)
463 {
464 if (s_trace_context_switches
465 && s_drd_running_tid != DRD_INVALID_THREADID)
466 {
467 VG_(message)(Vg_DebugMsg,
barta2b6e1b2008-03-17 18:32:39 +0000468 "Context switch from thread %d/%d to thread %d/%d;"
469 " segments: %llu",
bartaa97a542008-03-16 17:57:01 +0000470 s_vg_running_tid, s_drd_running_tid,
barta2b6e1b2008-03-17 18:32:39 +0000471 DrdThreadIdToVgThreadId(drd_tid), drd_tid,
bart62ada3f2009-02-14 17:19:58 +0000472 DRD_(sg_get_segments_alive_count)());
bart3772a982008-03-15 08:11:03 +0000473 }
474 s_vg_running_tid = vg_tid;
475 s_drd_running_tid = drd_tid;
barte73b0aa2008-06-28 07:19:56 +0000476 thread_compute_conflict_set(&s_conflict_set, drd_tid);
bart3772a982008-03-15 08:11:03 +0000477 s_context_switch_count++;
478 }
sewardj8b09d4f2007-12-04 21:27:18 +0000479
bart3772a982008-03-15 08:11:03 +0000480 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
481 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000482}
483
bart0268dfa2008-03-11 20:10:21 +0000484int thread_enter_synchr(const DrdThreadId tid)
485{
bart3772a982008-03-15 08:11:03 +0000486 tl_assert(IsValidDrdThreadId(tid));
487 return s_threadinfo[tid].synchr_nesting++;
bart0268dfa2008-03-11 20:10:21 +0000488}
489
490int thread_leave_synchr(const DrdThreadId tid)
491{
bart3772a982008-03-15 08:11:03 +0000492 tl_assert(IsValidDrdThreadId(tid));
493 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
494 return --s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000495}
496
497int thread_get_synchr_nesting_count(const DrdThreadId tid)
498{
bart3772a982008-03-15 08:11:03 +0000499 tl_assert(IsValidDrdThreadId(tid));
500 return s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000501}
502
bart1a473c72008-03-13 19:03:38 +0000503/** Append a new segment at the end of the segment list. */
bart26f73e12008-02-24 18:37:08 +0000504static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000505{
bart74a5f212008-05-11 06:43:07 +0000506 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000507 && tid != DRD_INVALID_THREADID);
bart23d3a4e2008-04-05 12:53:00 +0000508 // tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart3772a982008-03-15 08:11:03 +0000509 sg->prev = s_threadinfo[tid].last;
510 sg->next = 0;
511 if (s_threadinfo[tid].last)
512 s_threadinfo[tid].last->next = sg;
513 s_threadinfo[tid].last = sg;
514 if (s_threadinfo[tid].first == 0)
515 s_threadinfo[tid].first = sg;
bart23d3a4e2008-04-05 12:53:00 +0000516 // tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000517}
518
bart26f73e12008-02-24 18:37:08 +0000519/** Remove a segment from the segment list of thread threadid, and free the
520 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000521 */
bart26f73e12008-02-24 18:37:08 +0000522static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000523{
bart74a5f212008-05-11 06:43:07 +0000524 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000525 && tid != DRD_INVALID_THREADID);
bart3f749672008-03-22 09:49:40 +0000526 //tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000527
bart3772a982008-03-15 08:11:03 +0000528 if (sg->prev)
529 sg->prev->next = sg->next;
530 if (sg->next)
531 sg->next->prev = sg->prev;
532 if (sg == s_threadinfo[tid].first)
533 s_threadinfo[tid].first = sg->next;
534 if (sg == s_threadinfo[tid].last)
535 s_threadinfo[tid].last = sg->prev;
bart62ada3f2009-02-14 17:19:58 +0000536 DRD_(sg_put)(sg);
bart3f749672008-03-22 09:49:40 +0000537
538 //tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000539}
540
541VectorClock* thread_get_vc(const DrdThreadId tid)
542{
bart74a5f212008-05-11 06:43:07 +0000543 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
544 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000545 tl_assert(s_threadinfo[tid].last);
546 return &s_threadinfo[tid].last->vc;
sewardjaf44c822007-11-25 14:01:38 +0000547}
548
barta2b6e1b2008-03-17 18:32:39 +0000549/** Return the latest segment of thread 'tid' and increment its reference
550 * count.
551 */
552void thread_get_latest_segment(Segment** sg, const DrdThreadId tid)
553{
554 tl_assert(sg);
bart74a5f212008-05-11 06:43:07 +0000555 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
556 && tid != DRD_INVALID_THREADID);
barta2b6e1b2008-03-17 18:32:39 +0000557 tl_assert(s_threadinfo[tid].last);
558
bart62ada3f2009-02-14 17:19:58 +0000559 DRD_(sg_put)(*sg);
560 *sg = DRD_(sg_get)(s_threadinfo[tid].last);
barta2b6e1b2008-03-17 18:32:39 +0000561}
562
sewardjaf44c822007-11-25 14:01:38 +0000563/**
564 * Compute the minimum of all latest vector clocks of all threads
565 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
566 * @param vc pointer to a vectorclock, holds result upon return.
567 */
568static void thread_compute_minimum_vc(VectorClock* vc)
569{
bart3772a982008-03-15 08:11:03 +0000570 unsigned i;
571 Bool first;
572 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000573
bart3772a982008-03-15 08:11:03 +0000574 first = True;
575 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
576 {
577 latest_sg = s_threadinfo[i].last;
578 if (latest_sg)
579 {
580 if (first)
bart41b226c2009-02-14 16:55:19 +0000581 DRD_(vc_assign)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000582 else
bart41b226c2009-02-14 16:55:19 +0000583 DRD_(vc_min)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000584 first = False;
585 }
586 }
sewardjaf44c822007-11-25 14:01:38 +0000587}
588
589static void thread_compute_maximum_vc(VectorClock* vc)
590{
bart3772a982008-03-15 08:11:03 +0000591 unsigned i;
592 Bool first;
593 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000594
bart3772a982008-03-15 08:11:03 +0000595 first = True;
596 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
597 {
598 latest_sg = s_threadinfo[i].last;
599 if (latest_sg)
600 {
601 if (first)
bart41b226c2009-02-14 16:55:19 +0000602 DRD_(vc_assign)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000603 else
bart41b226c2009-02-14 16:55:19 +0000604 DRD_(vc_combine)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000605 first = False;
606 }
607 }
sewardjaf44c822007-11-25 14:01:38 +0000608}
609
610/**
bart5bd9f2d2008-03-03 20:31:58 +0000611 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000612 * clock of every thread -- these segments can no longer be involved in a
613 * data race.
614 */
615static void thread_discard_ordered_segments(void)
616{
bart3772a982008-03-15 08:11:03 +0000617 unsigned i;
618 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000619
bart3772a982008-03-15 08:11:03 +0000620 s_discard_ordered_segments_count++;
sewardjaf44c822007-11-25 14:01:38 +0000621
bart41b226c2009-02-14 16:55:19 +0000622 DRD_(vc_init)(&thread_vc_min, 0, 0);
bart3772a982008-03-15 08:11:03 +0000623 thread_compute_minimum_vc(&thread_vc_min);
bart62ada3f2009-02-14 17:19:58 +0000624 if (DRD_(sg_get_trace)())
bart3772a982008-03-15 08:11:03 +0000625 {
626 char msg[256];
627 VectorClock thread_vc_max;
sewardjaf44c822007-11-25 14:01:38 +0000628
bart41b226c2009-02-14 16:55:19 +0000629 DRD_(vc_init)(&thread_vc_max, 0, 0);
bart3772a982008-03-15 08:11:03 +0000630 thread_compute_maximum_vc(&thread_vc_max);
631 VG_(snprintf)(msg, sizeof(msg),
632 "Discarding ordered segments -- min vc is ");
bart41b226c2009-02-14 16:55:19 +0000633 DRD_(vc_snprint)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
634 &thread_vc_min);
bart3772a982008-03-15 08:11:03 +0000635 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
636 ", max vc is ");
bart41b226c2009-02-14 16:55:19 +0000637 DRD_(vc_snprint)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
638 &thread_vc_max);
barta2b6e1b2008-03-17 18:32:39 +0000639 VG_(message)(Vg_UserMsg, "%s", msg);
bart41b226c2009-02-14 16:55:19 +0000640 DRD_(vc_cleanup)(&thread_vc_max);
bart3772a982008-03-15 08:11:03 +0000641 }
sewardjaf44c822007-11-25 14:01:38 +0000642
bart3772a982008-03-15 08:11:03 +0000643 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
644 {
645 Segment* sg;
646 Segment* sg_next;
647 for (sg = s_threadinfo[i].first;
bart41b226c2009-02-14 16:55:19 +0000648 sg && (sg_next = sg->next) && DRD_(vc_lte)(&sg->vc, &thread_vc_min);
bart3772a982008-03-15 08:11:03 +0000649 sg = sg_next)
650 {
651 thread_discard_segment(i, sg);
652 }
653 }
bart41b226c2009-02-14 16:55:19 +0000654 DRD_(vc_cleanup)(&thread_vc_min);
sewardjaf44c822007-11-25 14:01:38 +0000655}
656
barta9c37392008-03-22 09:38:48 +0000657/** Merge all segments that may be merged without triggering false positives
658 * or discarding real data races. For the theoretical background of segment
659 * merging, see also the following paper:
660 * Mark Christiaens, Michiel Ronsse and Koen De Bosschere.
661 * Bounding the number of segment histories during data race detection.
662 * Parallel Computing archive, Volume 28, Issue 9, pp 1221-1238,
663 * September 2002.
664 */
665static void thread_merge_segments(void)
666{
667 unsigned i;
668
669 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
670 {
671 Segment* sg;
672
bart23d3a4e2008-04-05 12:53:00 +0000673 // tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
barta9c37392008-03-22 09:38:48 +0000674
675 for (sg = s_threadinfo[i].first; sg; sg = sg->next)
676 {
bart62ada3f2009-02-14 17:19:58 +0000677 if (DRD_(sg_get_refcnt)(sg) == 1
barta9c37392008-03-22 09:38:48 +0000678 && sg->next
bart62ada3f2009-02-14 17:19:58 +0000679 && DRD_(sg_get_refcnt)(sg->next) == 1
barta9c37392008-03-22 09:38:48 +0000680 && sg->next->next)
681 {
682 /* Merge sg and sg->next into sg. */
bart62ada3f2009-02-14 17:19:58 +0000683 DRD_(sg_merge)(sg, sg->next);
barta9c37392008-03-22 09:38:48 +0000684 thread_discard_segment(i, sg->next);
685 }
686 }
687
bart23d3a4e2008-04-05 12:53:00 +0000688 // tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
barta9c37392008-03-22 09:38:48 +0000689 }
690}
691
bartd66e3a82008-04-06 15:02:17 +0000692/** Every change in the vector clock of a thread may cause segments that
693 * were previously ordered to this thread to become unordered. Hence,
barte73b0aa2008-06-28 07:19:56 +0000694 * it may be necessary to recalculate the conflict set if the vector clock
bartd66e3a82008-04-06 15:02:17 +0000695 * of the current thread is updated. This function check whether such a
696 * recalculation is necessary.
697 *
698 * @param tid Thread ID of the thread to which a new segment has been
699 * appended.
700 * @param new_sg Pointer to the most recent segment of thread tid.
701 */
barte73b0aa2008-06-28 07:19:56 +0000702static Bool conflict_set_update_needed(const DrdThreadId tid,
bart41b226c2009-02-14 16:55:19 +0000703 const Segment* const new_sg)
bartd66e3a82008-04-06 15:02:17 +0000704{
bart5d421ba2008-04-19 15:15:12 +0000705#if 0
bartd66e3a82008-04-06 15:02:17 +0000706 unsigned i;
707 const Segment* old_sg;
708
709 tl_assert(new_sg);
710
711 /* If a new segment was added to another thread than the running thread, */
barte73b0aa2008-06-28 07:19:56 +0000712 /* just tell the caller to update the conflict set. */
bartd66e3a82008-04-06 15:02:17 +0000713 if (tid != s_drd_running_tid)
714 return True;
715
barte73b0aa2008-06-28 07:19:56 +0000716 /* Always let the caller update the conflict set after creation of the */
bartd66e3a82008-04-06 15:02:17 +0000717 /* first segment. */
718 old_sg = new_sg->prev;
719 if (old_sg == 0)
720 return True;
721
722 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
723 {
724 Segment* q;
725
726 if (i == s_drd_running_tid)
727 continue;
728
729 for (q = s_threadinfo[i].last; q; q = q->prev)
730 {
731 /* If the expression below evaluates to false, this expression will */
732 /* also evaluate to false for all subsequent iterations. So stop */
733 /* iterating. */
bart41b226c2009-02-14 16:55:19 +0000734 if (DRD_(vc_lte)(&q->vc, &old_sg->vc))
bartd66e3a82008-04-06 15:02:17 +0000735 break;
736 /* If the vector clock of the 2nd the last segment is not ordered */
737 /* to the vector clock of segment q, and the last segment is, ask */
barte73b0aa2008-06-28 07:19:56 +0000738 /* the caller to update the conflict set. */
bart41b226c2009-02-14 16:55:19 +0000739 if (! DRD_(vc_lte)(&old_sg->vc, &q->vc))
bartd66e3a82008-04-06 15:02:17 +0000740 {
741 return True;
742 }
743 /* If the vector clock of the last segment is not ordered to the */
barte73b0aa2008-06-28 07:19:56 +0000744 /* vector clock of segment q, ask the caller to update the conflict */
bartd66e3a82008-04-06 15:02:17 +0000745 /* set. */
bart41b226c2009-02-14 16:55:19 +0000746 if (! DRD_(vc_lte)(&q->vc, &new_sg->vc) && ! DRD_(vc_lte)(&new_sg->vc, &q->vc))
bartd66e3a82008-04-06 15:02:17 +0000747 {
748 return True;
749 }
750 }
751 }
752
753 return False;
bart5d421ba2008-04-19 15:15:12 +0000754#else
755 return True;
756#endif
bartd66e3a82008-04-06 15:02:17 +0000757}
758
barta2b6e1b2008-03-17 18:32:39 +0000759/** Create a new segment for the specified thread, and discard any segments
760 * that cannot cause races anymore.
sewardjaf44c822007-11-25 14:01:38 +0000761 */
762void thread_new_segment(const DrdThreadId tid)
763{
bartd66e3a82008-04-06 15:02:17 +0000764 Segment* new_sg;
765
bart74a5f212008-05-11 06:43:07 +0000766 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
767 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000768
bart62ada3f2009-02-14 17:19:58 +0000769 new_sg = DRD_(sg_new)(tid, tid);
bartd66e3a82008-04-06 15:02:17 +0000770 thread_append_segment(tid, new_sg);
771
barte73b0aa2008-06-28 07:19:56 +0000772 if (conflict_set_update_needed(tid, new_sg))
bartd66e3a82008-04-06 15:02:17 +0000773 {
barte73b0aa2008-06-28 07:19:56 +0000774 thread_compute_conflict_set(&s_conflict_set, s_drd_running_tid);
775 s_conflict_set_new_segment_count++;
bartd66e3a82008-04-06 15:02:17 +0000776 }
bart82195c12008-04-13 17:35:08 +0000777 else if (tid == s_drd_running_tid)
778 {
barte73b0aa2008-06-28 07:19:56 +0000779 tl_assert(thread_conflict_set_up_to_date(s_drd_running_tid));
bart82195c12008-04-13 17:35:08 +0000780 }
sewardjaf44c822007-11-25 14:01:38 +0000781
bart3772a982008-03-15 08:11:03 +0000782 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000783
barta9c37392008-03-22 09:38:48 +0000784 if (s_segment_merging)
785 thread_merge_segments();
sewardjaf44c822007-11-25 14:01:38 +0000786}
787
bart26f73e12008-02-24 18:37:08 +0000788/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000789void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
790{
bart3772a982008-03-15 08:11:03 +0000791 tl_assert(joiner != joinee);
bart74a5f212008-05-11 06:43:07 +0000792 tl_assert(0 <= (int)joiner && joiner < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000793 && joiner != DRD_INVALID_THREADID);
bart74a5f212008-05-11 06:43:07 +0000794 tl_assert(0 <= (int)joinee && joinee < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000795 && joinee != DRD_INVALID_THREADID);
796 tl_assert(s_threadinfo[joiner].last);
797 tl_assert(s_threadinfo[joinee].last);
bart41b226c2009-02-14 16:55:19 +0000798 DRD_(vc_combine)(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
bart3772a982008-03-15 08:11:03 +0000799 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000800
bart3772a982008-03-15 08:11:03 +0000801 if (joiner == s_drd_running_tid)
802 {
barte73b0aa2008-06-28 07:19:56 +0000803 thread_compute_conflict_set(&s_conflict_set, joiner);
bart3772a982008-03-15 08:11:03 +0000804 }
sewardjaf44c822007-11-25 14:01:38 +0000805}
806
bart26f73e12008-02-24 18:37:08 +0000807/** Call this function after thread 'tid' had to wait because of thread
808 * synchronization until the memory accesses in the segment with vector clock
809 * 'vc' finished.
810 */
sewardjaf44c822007-11-25 14:01:38 +0000811void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
812{
bart74a5f212008-05-11 06:43:07 +0000813 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
814 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000815 tl_assert(s_threadinfo[tid].last);
816 tl_assert(vc);
bart41b226c2009-02-14 16:55:19 +0000817 DRD_(vc_combine)(&s_threadinfo[tid].last->vc, vc);
barte73b0aa2008-06-28 07:19:56 +0000818 thread_compute_conflict_set(&s_conflict_set, tid);
bart3772a982008-03-15 08:11:03 +0000819 thread_discard_ordered_segments();
barte73b0aa2008-06-28 07:19:56 +0000820 s_conflict_set_combine_vc_count++;
sewardjaf44c822007-11-25 14:01:38 +0000821}
822
bart26f73e12008-02-24 18:37:08 +0000823/** Call this function whenever a thread is no longer using the memory
824 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
825 * increase.
826 */
sewardjaf44c822007-11-25 14:01:38 +0000827void thread_stop_using_mem(const Addr a1, const Addr a2)
828{
bartd43f8d32008-03-16 17:29:20 +0000829 DrdThreadId other_user;
830 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000831
bart3772a982008-03-15 08:11:03 +0000832 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
bartd43f8d32008-03-16 17:29:20 +0000833 other_user = DRD_INVALID_THREADID;
bart3772a982008-03-15 08:11:03 +0000834 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
835 {
836 Segment* p;
837 for (p = s_threadinfo[i].first; p; p = p->next)
838 {
839 if (other_user == DRD_INVALID_THREADID
bart8bf2f8b2008-03-30 17:56:43 +0000840 && i != s_drd_running_tid)
sewardjaf44c822007-11-25 14:01:38 +0000841 {
bart8bf2f8b2008-03-30 17:56:43 +0000842 if (UNLIKELY(bm_test_and_clear(p->bm, a1, a2)))
843 {
844 other_user = i;
845 }
846 continue;
sewardjaf44c822007-11-25 14:01:38 +0000847 }
bart3772a982008-03-15 08:11:03 +0000848 bm_clear(p->bm, a1, a2);
849 }
850 }
sewardjaf44c822007-11-25 14:01:38 +0000851
bart3772a982008-03-15 08:11:03 +0000852 /* If any other thread had accessed memory in [ a1, a2 [, update the */
barte73b0aa2008-06-28 07:19:56 +0000853 /* conflict set. */
bart3772a982008-03-15 08:11:03 +0000854 if (other_user != DRD_INVALID_THREADID
barte73b0aa2008-06-28 07:19:56 +0000855 && bm_has_any_access(s_conflict_set, a1, a2))
bart3772a982008-03-15 08:11:03 +0000856 {
barte73b0aa2008-06-28 07:19:56 +0000857 thread_compute_conflict_set(&s_conflict_set, thread_get_running_tid());
bart3772a982008-03-15 08:11:03 +0000858 }
sewardjaf44c822007-11-25 14:01:38 +0000859}
860
bart0268dfa2008-03-11 20:10:21 +0000861void thread_start_recording(const DrdThreadId tid)
862{
bart74a5f212008-05-11 06:43:07 +0000863 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
864 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000865 tl_assert(! s_threadinfo[tid].is_recording);
866 s_threadinfo[tid].is_recording = True;
bart0268dfa2008-03-11 20:10:21 +0000867}
868
869void thread_stop_recording(const DrdThreadId tid)
870{
bart74a5f212008-05-11 06:43:07 +0000871 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
872 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000873 tl_assert(s_threadinfo[tid].is_recording);
874 s_threadinfo[tid].is_recording = False;
bart0268dfa2008-03-11 20:10:21 +0000875}
876
sewardjaf44c822007-11-25 14:01:38 +0000877void thread_print_all(void)
878{
bart3772a982008-03-15 08:11:03 +0000879 unsigned i;
880 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000881
bart3772a982008-03-15 08:11:03 +0000882 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
883 {
884 if (s_threadinfo[i].first)
885 {
886 VG_(printf)("**************\n"
barta2b6e1b2008-03-17 18:32:39 +0000887 "* thread %3d (%d/%d/%d/0x%lx/%d) *\n"
bart3772a982008-03-15 08:11:03 +0000888 "**************\n",
889 i,
890 s_threadinfo[i].vg_thread_exists,
891 s_threadinfo[i].vg_threadid,
892 s_threadinfo[i].posix_thread_exists,
893 s_threadinfo[i].pt_threadid,
bart354009c2008-03-16 10:42:33 +0000894 s_threadinfo[i].detached_posix_thread);
bart3772a982008-03-15 08:11:03 +0000895 for (p = s_threadinfo[i].first; p; p = p->next)
sewardjaf44c822007-11-25 14:01:38 +0000896 {
bart62ada3f2009-02-14 17:19:58 +0000897 DRD_(sg_print)(p);
sewardjaf44c822007-11-25 14:01:38 +0000898 }
bart3772a982008-03-15 08:11:03 +0000899 }
900 }
sewardjaf44c822007-11-25 14:01:38 +0000901}
902
903static void show_call_stack(const DrdThreadId tid,
904 const Char* const msg,
905 ExeContext* const callstack)
906{
bart3772a982008-03-15 08:11:03 +0000907 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000908
bartaa97a542008-03-16 17:57:01 +0000909 VG_(message)(Vg_UserMsg, "%s (thread %d/%d)", msg, vg_tid, tid);
sewardjaf44c822007-11-25 14:01:38 +0000910
bart3772a982008-03-15 08:11:03 +0000911 if (vg_tid != VG_INVALID_THREADID)
912 {
913 if (callstack)
914 {
915 VG_(pp_ExeContext)(callstack);
916 }
917 else
918 {
919 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
920 }
921 }
922 else
923 {
924 VG_(message)(Vg_UserMsg,
925 " (thread finished, call stack no longer available)");
926 }
sewardjaf44c822007-11-25 14:01:38 +0000927}
928
sewardjaf44c822007-11-25 14:01:38 +0000929static void
930thread_report_conflicting_segments_segment(const DrdThreadId tid,
931 const Addr addr,
932 const SizeT size,
933 const BmAccessTypeT access_type,
934 const Segment* const p)
935{
bart3772a982008-03-15 08:11:03 +0000936 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000937
bart74a5f212008-05-11 06:43:07 +0000938 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000939 && tid != DRD_INVALID_THREADID);
940 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000941
bart3772a982008-03-15 08:11:03 +0000942 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
943 {
944 if (i != tid)
945 {
946 Segment* q;
947 for (q = s_threadinfo[i].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000948 {
bart3772a982008-03-15 08:11:03 +0000949 // Since q iterates over the segments of thread i in order of
950 // decreasing vector clocks, if q->vc <= p->vc, then
951 // q->next->vc <= p->vc will also hold. Hence, break out of the
952 // loop once this condition is met.
bart41b226c2009-02-14 16:55:19 +0000953 if (DRD_(vc_lte)(&q->vc, &p->vc))
bart3772a982008-03-15 08:11:03 +0000954 break;
bart41b226c2009-02-14 16:55:19 +0000955 if (! DRD_(vc_lte)(&p->vc, &q->vc))
bart3772a982008-03-15 08:11:03 +0000956 {
957 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
958 {
959 tl_assert(q->stacktrace);
960 show_call_stack(i, "Other segment start",
961 q->stacktrace);
962 show_call_stack(i, "Other segment end",
963 q->next ? q->next->stacktrace : 0);
964 }
965 }
sewardjaf44c822007-11-25 14:01:38 +0000966 }
bart3772a982008-03-15 08:11:03 +0000967 }
968 }
sewardjaf44c822007-11-25 14:01:38 +0000969}
970
971void thread_report_conflicting_segments(const DrdThreadId tid,
972 const Addr addr,
973 const SizeT size,
974 const BmAccessTypeT access_type)
975{
bart3772a982008-03-15 08:11:03 +0000976 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000977
bart74a5f212008-05-11 06:43:07 +0000978 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000979 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000980
bart3772a982008-03-15 08:11:03 +0000981 for (p = s_threadinfo[tid].first; p; p = p->next)
982 {
983 if (bm_has(p->bm, addr, addr + size, access_type))
984 {
985 thread_report_conflicting_segments_segment(tid, addr, size,
986 access_type, p);
987 }
988 }
sewardjaf44c822007-11-25 14:01:38 +0000989}
sewardjaf44c822007-11-25 14:01:38 +0000990
barte73b0aa2008-06-28 07:19:56 +0000991/** Verify whether the conflict set for thread tid is up to date. Only perform
992 * the check if the environment variable DRD_VERIFY_CONFLICT_SET has been set.
bart82195c12008-04-13 17:35:08 +0000993 */
barte73b0aa2008-06-28 07:19:56 +0000994static Bool thread_conflict_set_up_to_date(const DrdThreadId tid)
bart82195c12008-04-13 17:35:08 +0000995{
barte73b0aa2008-06-28 07:19:56 +0000996 static int do_verify_conflict_set = -1;
bart82195c12008-04-13 17:35:08 +0000997 Bool result;
barte73b0aa2008-06-28 07:19:56 +0000998 struct bitmap* computed_conflict_set = 0;
bart82195c12008-04-13 17:35:08 +0000999
barte73b0aa2008-06-28 07:19:56 +00001000 if (do_verify_conflict_set < 0)
bart82195c12008-04-13 17:35:08 +00001001 {
barte73b0aa2008-06-28 07:19:56 +00001002 //VG_(message)(Vg_DebugMsg, "%s", VG_(getenv)("DRD_VERIFY_CONFLICT_SET"));
1003 do_verify_conflict_set = VG_(getenv)("DRD_VERIFY_CONFLICT_SET") != 0;
bart82195c12008-04-13 17:35:08 +00001004 }
barte73b0aa2008-06-28 07:19:56 +00001005 if (do_verify_conflict_set == 0)
bart82195c12008-04-13 17:35:08 +00001006 return True;
1007
barte73b0aa2008-06-28 07:19:56 +00001008 thread_compute_conflict_set(&computed_conflict_set, tid);
1009 result = bm_equal(s_conflict_set, computed_conflict_set);
1010 bm_delete(computed_conflict_set);
bart82195c12008-04-13 17:35:08 +00001011 return result;
1012}
1013
bart26f73e12008-02-24 18:37:08 +00001014/** Compute a bitmap that represents the union of all memory accesses of all
1015 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +00001016 */
barte73b0aa2008-06-28 07:19:56 +00001017static void thread_compute_conflict_set(struct bitmap** conflict_set,
1018 const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +00001019{
bart3772a982008-03-15 08:11:03 +00001020 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +00001021
bart74a5f212008-05-11 06:43:07 +00001022 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
1023 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +00001024 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +00001025
barte73b0aa2008-06-28 07:19:56 +00001026 s_update_conflict_set_count++;
1027 s_conflict_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
1028 s_conflict_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +00001029
barte73b0aa2008-06-28 07:19:56 +00001030 if (*conflict_set)
bart3772a982008-03-15 08:11:03 +00001031 {
barte73b0aa2008-06-28 07:19:56 +00001032 bm_delete(*conflict_set);
bart3772a982008-03-15 08:11:03 +00001033 }
barte73b0aa2008-06-28 07:19:56 +00001034 *conflict_set = bm_new();
bart26f73e12008-02-24 18:37:08 +00001035
barte73b0aa2008-06-28 07:19:56 +00001036 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001037 {
1038 char msg[256];
1039
1040 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001041 "computing conflict set for thread %d/%d with vc ",
bartaa97a542008-03-16 17:57:01 +00001042 DrdThreadIdToVgThreadId(tid), tid);
bart41b226c2009-02-14 16:55:19 +00001043 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1044 sizeof(msg) - VG_(strlen)(msg),
1045 &s_threadinfo[tid].last->vc);
barta2b6e1b2008-03-17 18:32:39 +00001046 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001047 }
1048
1049 p = s_threadinfo[tid].last;
1050 {
1051 unsigned j;
1052
barte73b0aa2008-06-28 07:19:56 +00001053 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001054 {
bart26f73e12008-02-24 18:37:08 +00001055 char msg[256];
1056
1057 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001058 "conflict set: thread [%d] at vc ",
bart26f73e12008-02-24 18:37:08 +00001059 tid);
bart41b226c2009-02-14 16:55:19 +00001060 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1061 sizeof(msg) - VG_(strlen)(msg),
1062 &p->vc);
barta2b6e1b2008-03-17 18:32:39 +00001063 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001064 }
sewardjaf44c822007-11-25 14:01:38 +00001065
bart3772a982008-03-15 08:11:03 +00001066 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
1067 {
bartd66e3a82008-04-06 15:02:17 +00001068 if (j != tid && IsValidDrdThreadId(j))
bart26f73e12008-02-24 18:37:08 +00001069 {
bart3772a982008-03-15 08:11:03 +00001070 const Segment* q;
1071 for (q = s_threadinfo[j].last; q; q = q->prev)
bartd66e3a82008-04-06 15:02:17 +00001072 {
bart41b226c2009-02-14 16:55:19 +00001073 if (! DRD_(vc_lte)(&q->vc, &p->vc) && ! DRD_(vc_lte)(&p->vc, &q->vc))
bart3772a982008-03-15 08:11:03 +00001074 {
barte73b0aa2008-06-28 07:19:56 +00001075 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001076 {
1077 char msg[256];
1078 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001079 "conflict set: [%d] merging segment ", j);
bart41b226c2009-02-14 16:55:19 +00001080 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1081 sizeof(msg) - VG_(strlen)(msg),
1082 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +00001083 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001084 }
barte73b0aa2008-06-28 07:19:56 +00001085 bm_merge2(*conflict_set, q->bm);
bart3772a982008-03-15 08:11:03 +00001086 }
1087 else
1088 {
barte73b0aa2008-06-28 07:19:56 +00001089 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001090 {
1091 char msg[256];
1092 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001093 "conflict set: [%d] ignoring segment ", j);
bart41b226c2009-02-14 16:55:19 +00001094 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1095 sizeof(msg) - VG_(strlen)(msg),
1096 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +00001097 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001098 }
1099 }
bartd66e3a82008-04-06 15:02:17 +00001100 }
bart26f73e12008-02-24 18:37:08 +00001101 }
bart3772a982008-03-15 08:11:03 +00001102 }
bart3772a982008-03-15 08:11:03 +00001103 }
sewardjaf44c822007-11-25 14:01:38 +00001104
barte73b0aa2008-06-28 07:19:56 +00001105 s_conflict_set_bitmap_creation_count += bm_get_bitmap_creation_count();
1106 s_conflict_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +00001107
barte73b0aa2008-06-28 07:19:56 +00001108 if (0 && s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001109 {
barte73b0aa2008-06-28 07:19:56 +00001110 VG_(message)(Vg_UserMsg, "[%d] new conflict set:", tid);
1111 bm_print(*conflict_set);
1112 VG_(message)(Vg_UserMsg, "[%d] end of new conflict set.", tid);
bart3772a982008-03-15 08:11:03 +00001113 }
sewardjaf44c822007-11-25 14:01:38 +00001114}
1115
sewardjaf44c822007-11-25 14:01:38 +00001116ULong thread_get_context_switch_count(void)
1117{
bart3772a982008-03-15 08:11:03 +00001118 return s_context_switch_count;
sewardjaf44c822007-11-25 14:01:38 +00001119}
1120
sewardjaf44c822007-11-25 14:01:38 +00001121ULong thread_get_discard_ordered_segments_count(void)
1122{
bart3772a982008-03-15 08:11:03 +00001123 return s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +00001124}
1125
barte73b0aa2008-06-28 07:19:56 +00001126ULong thread_get_update_conflict_set_count(ULong* dsnsc, ULong* dscvc)
sewardjaf44c822007-11-25 14:01:38 +00001127{
bartd66e3a82008-04-06 15:02:17 +00001128 tl_assert(dsnsc);
1129 tl_assert(dscvc);
barte73b0aa2008-06-28 07:19:56 +00001130 *dsnsc = s_conflict_set_new_segment_count;
1131 *dscvc = s_conflict_set_combine_vc_count;
1132 return s_update_conflict_set_count;
sewardjaf44c822007-11-25 14:01:38 +00001133}
1134
barte73b0aa2008-06-28 07:19:56 +00001135ULong thread_get_conflict_set_bitmap_creation_count(void)
sewardjaf44c822007-11-25 14:01:38 +00001136{
barte73b0aa2008-06-28 07:19:56 +00001137 return s_conflict_set_bitmap_creation_count;
sewardjaf44c822007-11-25 14:01:38 +00001138}
1139
barte73b0aa2008-06-28 07:19:56 +00001140ULong thread_get_conflict_set_bitmap2_creation_count(void)
sewardjaf44c822007-11-25 14:01:38 +00001141{
barte73b0aa2008-06-28 07:19:56 +00001142 return s_conflict_set_bitmap2_creation_count;
sewardjaf44c822007-11-25 14:01:38 +00001143}