blob: 2523d7beb4cac1ce50a76ddf1519b718d640d117 [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
216DrdThreadId thread_pre_create(const DrdThreadId creator,
217 const ThreadId vg_created)
218{
bart3772a982008-03-15 08:11:03 +0000219 DrdThreadId created;
sewardjaf44c822007-11-25 14:01:38 +0000220
bart3772a982008-03-15 08:11:03 +0000221 tl_assert(VgThreadIdToDrdThreadId(vg_created) == DRD_INVALID_THREADID);
222 created = VgThreadIdToNewDrdThreadId(vg_created);
bart74a5f212008-05-11 06:43:07 +0000223 tl_assert(0 <= (int)created && created < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000224 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000225
bart3772a982008-03-15 08:11:03 +0000226 tl_assert(s_threadinfo[created].first == 0);
227 tl_assert(s_threadinfo[created].last == 0);
228 thread_append_segment(created, sg_new(creator, created));
sewardjaf44c822007-11-25 14:01:38 +0000229
bart3772a982008-03-15 08:11:03 +0000230 return created;
sewardjaf44c822007-11-25 14:01:38 +0000231}
232
bart09dc13f2009-02-14 15:13:31 +0000233
234/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
235/* after thread drd_joiner joined thread drd_joinee. */
236void DRD_(thread_post_join)(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
237{
238 tl_assert(IsValidDrdThreadId(drd_joiner));
239 tl_assert(IsValidDrdThreadId(drd_joinee));
240 thread_new_segment(drd_joinee);
241 thread_combine_vc(drd_joiner, drd_joinee);
242 thread_new_segment(drd_joiner);
243
244 if (s_trace_fork_join)
245 {
246 const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
247 const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
248 const unsigned msg_size = 256;
249 char* msg;
250
251 msg = VG_(malloc)("drd.main.dptj.1", msg_size);
252 tl_assert(msg);
253 VG_(snprintf)(msg, msg_size,
254 "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
255 joiner, drd_joiner, joinee, drd_joinee);
256 if (joiner)
257 {
258 VG_(snprintf)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
259 ", new vc: ");
bart41b226c2009-02-14 16:55:19 +0000260 DRD_(vc_snprint)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
261 thread_get_vc(drd_joiner));
bart09dc13f2009-02-14 15:13:31 +0000262 }
263 VG_(message)(Vg_DebugMsg, "%s", msg);
264 VG_(free)(msg);
265 }
266
267 if (! DRD_(get_check_stack_accesses)())
268 {
bart1335ecc2009-02-14 16:10:53 +0000269 DRD_(finish_suppression)(thread_get_stack_max(drd_joinee)
270 - thread_get_stack_size(drd_joinee),
271 thread_get_stack_max(drd_joinee));
bart09dc13f2009-02-14 15:13:31 +0000272 }
273 thread_delete(drd_joinee);
274 mutex_thread_delete(drd_joinee);
275 cond_thread_delete(drd_joinee);
276 semaphore_thread_delete(drd_joinee);
277 barrier_thread_delete(drd_joinee);
278}
279
bart26f73e12008-02-24 18:37:08 +0000280/** Allocate the first segment for a thread. Call this just after
281 * pthread_create().
sewardjaf44c822007-11-25 14:01:38 +0000282 */
283DrdThreadId thread_post_create(const ThreadId vg_created)
284{
bart3772a982008-03-15 08:11:03 +0000285 const DrdThreadId created = VgThreadIdToDrdThreadId(vg_created);
sewardjaf44c822007-11-25 14:01:38 +0000286
bart74a5f212008-05-11 06:43:07 +0000287 tl_assert(0 <= (int)created && created < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000288 && created != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000289
bart3772a982008-03-15 08:11:03 +0000290 s_threadinfo[created].stack_max = VG_(thread_get_stack_max)(vg_created);
291 s_threadinfo[created].stack_startup = s_threadinfo[created].stack_max;
292 s_threadinfo[created].stack_min = s_threadinfo[created].stack_max;
bartcac53462008-03-29 09:27:08 +0000293 s_threadinfo[created].stack_min_min = s_threadinfo[created].stack_max;
294 s_threadinfo[created].stack_size = VG_(thread_get_stack_size)(vg_created);
bart3772a982008-03-15 08:11:03 +0000295 tl_assert(s_threadinfo[created].stack_max != 0);
sewardjaf44c822007-11-25 14:01:38 +0000296
bart3772a982008-03-15 08:11:03 +0000297 return created;
sewardjaf44c822007-11-25 14:01:38 +0000298}
299
300/* NPTL hack: NPTL allocates the 'struct pthread' on top of the stack, */
301/* and accesses this data structure from multiple threads without locking. */
302/* Any conflicting accesses in the range stack_startup..stack_max will be */
303/* ignored. */
304void thread_set_stack_startup(const DrdThreadId tid, const Addr stack_startup)
305{
bart74a5f212008-05-11 06:43:07 +0000306 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
307 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000308 tl_assert(s_threadinfo[tid].stack_min <= stack_startup);
309 tl_assert(stack_startup <= s_threadinfo[tid].stack_max);
310 s_threadinfo[tid].stack_startup = stack_startup;
sewardjaf44c822007-11-25 14:01:38 +0000311}
312
313Addr thread_get_stack_min(const DrdThreadId tid)
314{
bart74a5f212008-05-11 06:43:07 +0000315 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000316 && tid != DRD_INVALID_THREADID);
317 return s_threadinfo[tid].stack_min;
sewardjaf44c822007-11-25 14:01:38 +0000318}
319
bartcac53462008-03-29 09:27:08 +0000320Addr thread_get_stack_min_min(const DrdThreadId tid)
321{
bart74a5f212008-05-11 06:43:07 +0000322 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartcac53462008-03-29 09:27:08 +0000323 && tid != DRD_INVALID_THREADID);
324 return s_threadinfo[tid].stack_min_min;
325}
326
bartd43f8d32008-03-16 17:29:20 +0000327Addr thread_get_stack_max(const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +0000328{
bart74a5f212008-05-11 06:43:07 +0000329 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartd43f8d32008-03-16 17:29:20 +0000330 && tid != DRD_INVALID_THREADID);
331 return s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000332}
333
bartcac53462008-03-29 09:27:08 +0000334SizeT thread_get_stack_size(const DrdThreadId tid)
335{
bart74a5f212008-05-11 06:43:07 +0000336 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bartcac53462008-03-29 09:27:08 +0000337 && tid != DRD_INVALID_THREADID);
338 return s_threadinfo[tid].stack_size;
339}
340
bart09dc13f2009-02-14 15:13:31 +0000341/**
342 * Clean up thread-specific data structures. Call this just after
343 * pthread_join().
sewardjaf44c822007-11-25 14:01:38 +0000344 */
345void thread_delete(const DrdThreadId tid)
346{
bart3772a982008-03-15 08:11:03 +0000347 Segment* sg;
348 Segment* sg_prev;
sewardjaf44c822007-11-25 14:01:38 +0000349
bart74a5f212008-05-11 06:43:07 +0000350 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000351 && tid != DRD_INVALID_THREADID);
bart5c3da012009-02-14 14:46:16 +0000352 tl_assert(s_threadinfo[tid].synchr_nesting >= 0);
bart3772a982008-03-15 08:11:03 +0000353 for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
354 {
355 sg_prev = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000356 sg->prev = 0;
357 sg->next = 0;
358 sg_put(sg);
bart3772a982008-03-15 08:11:03 +0000359 }
360 s_threadinfo[tid].vg_thread_exists = False;
361 s_threadinfo[tid].posix_thread_exists = False;
362 tl_assert(s_threadinfo[tid].detached_posix_thread == False);
363 s_threadinfo[tid].first = 0;
364 s_threadinfo[tid].last = 0;
sewardjaf44c822007-11-25 14:01:38 +0000365}
366
367/* Called after a thread performed its last memory access and before */
368/* thread_delete() is called. Note: thread_delete() is only called for */
369/* joinable threads, not for detached threads. */
370void thread_finished(const DrdThreadId tid)
371{
bart74a5f212008-05-11 06:43:07 +0000372 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000373 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000374
bart3772a982008-03-15 08:11:03 +0000375 s_threadinfo[tid].vg_thread_exists = False;
sewardjaf44c822007-11-25 14:01:38 +0000376
bart3772a982008-03-15 08:11:03 +0000377 if (s_threadinfo[tid].detached_posix_thread)
378 {
379 /* Once a detached thread has finished, its stack is deallocated and */
barte73b0aa2008-06-28 07:19:56 +0000380 /* should no longer be taken into account when computing the conflict set*/
bart3772a982008-03-15 08:11:03 +0000381 s_threadinfo[tid].stack_min = s_threadinfo[tid].stack_max;
sewardjaf44c822007-11-25 14:01:38 +0000382
bart3772a982008-03-15 08:11:03 +0000383 /* For a detached thread, calling pthread_exit() invalidates the */
384 /* POSIX thread ID associated with the detached thread. For joinable */
385 /* POSIX threads however, the POSIX thread ID remains live after the */
386 /* pthread_exit() call until pthread_join() is called. */
387 s_threadinfo[tid].posix_thread_exists = False;
388 }
sewardjaf44c822007-11-25 14:01:38 +0000389}
390
bart9b2974a2008-09-27 12:35:31 +0000391/** Called just before pthread_cancel(). */
bartaf0691b2008-09-27 12:26:50 +0000392void thread_pre_cancel(const DrdThreadId tid)
393{
394 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
395 && tid != DRD_INVALID_THREADID);
396 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
397
398 s_threadinfo[tid].synchr_nesting = 0;
399}
400
sewardjaf44c822007-11-25 14:01:38 +0000401void thread_set_pthreadid(const DrdThreadId tid, const PThreadId ptid)
402{
bart74a5f212008-05-11 06:43:07 +0000403 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000404 && tid != DRD_INVALID_THREADID);
405 tl_assert(s_threadinfo[tid].pt_threadid == INVALID_POSIX_THREADID);
406 tl_assert(ptid != INVALID_POSIX_THREADID);
407 s_threadinfo[tid].posix_thread_exists = True;
408 s_threadinfo[tid].pt_threadid = ptid;
sewardjaf44c822007-11-25 14:01:38 +0000409}
410
411Bool thread_get_joinable(const DrdThreadId tid)
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 return ! s_threadinfo[tid].detached_posix_thread;
sewardjaf44c822007-11-25 14:01:38 +0000416}
417
418void thread_set_joinable(const DrdThreadId tid, const Bool joinable)
419{
bart74a5f212008-05-11 06:43:07 +0000420 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000421 && tid != DRD_INVALID_THREADID);
422 tl_assert(!! joinable == joinable);
423 tl_assert(s_threadinfo[tid].pt_threadid != INVALID_POSIX_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000424#if 0
bart3772a982008-03-15 08:11:03 +0000425 VG_(message)(Vg_DebugMsg,
426 "thread_set_joinable(%d/%d, %s)",
427 tid,
428 s_threadinfo[tid].vg_threadid,
429 joinable ? "joinable" : "detached");
sewardjaf44c822007-11-25 14:01:38 +0000430#endif
bart3772a982008-03-15 08:11:03 +0000431 s_threadinfo[tid].detached_posix_thread = ! joinable;
sewardjaf44c822007-11-25 14:01:38 +0000432}
433
sewardj8b09d4f2007-12-04 21:27:18 +0000434void thread_set_vg_running_tid(const ThreadId vg_tid)
sewardjaf44c822007-11-25 14:01:38 +0000435{
bart3772a982008-03-15 08:11:03 +0000436 tl_assert(vg_tid != VG_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000437
bart3772a982008-03-15 08:11:03 +0000438 if (vg_tid != s_vg_running_tid)
439 {
440 thread_set_running_tid(vg_tid, VgThreadIdToDrdThreadId(vg_tid));
441 }
sewardj8b09d4f2007-12-04 21:27:18 +0000442
bart3772a982008-03-15 08:11:03 +0000443 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
444 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000445}
446
447void thread_set_running_tid(const ThreadId vg_tid, const DrdThreadId drd_tid)
448{
bart3772a982008-03-15 08:11:03 +0000449 tl_assert(vg_tid != VG_INVALID_THREADID);
450 tl_assert(drd_tid != DRD_INVALID_THREADID);
sewardj8b09d4f2007-12-04 21:27:18 +0000451
bart3772a982008-03-15 08:11:03 +0000452 if (vg_tid != s_vg_running_tid)
453 {
454 if (s_trace_context_switches
455 && s_drd_running_tid != DRD_INVALID_THREADID)
456 {
457 VG_(message)(Vg_DebugMsg,
barta2b6e1b2008-03-17 18:32:39 +0000458 "Context switch from thread %d/%d to thread %d/%d;"
459 " segments: %llu",
bartaa97a542008-03-16 17:57:01 +0000460 s_vg_running_tid, s_drd_running_tid,
barta2b6e1b2008-03-17 18:32:39 +0000461 DrdThreadIdToVgThreadId(drd_tid), drd_tid,
462 sg_get_alive_segments_count());
bart3772a982008-03-15 08:11:03 +0000463 }
464 s_vg_running_tid = vg_tid;
465 s_drd_running_tid = drd_tid;
barte73b0aa2008-06-28 07:19:56 +0000466 thread_compute_conflict_set(&s_conflict_set, drd_tid);
bart3772a982008-03-15 08:11:03 +0000467 s_context_switch_count++;
468 }
sewardj8b09d4f2007-12-04 21:27:18 +0000469
bart3772a982008-03-15 08:11:03 +0000470 tl_assert(s_vg_running_tid != VG_INVALID_THREADID);
471 tl_assert(s_drd_running_tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000472}
473
bart0268dfa2008-03-11 20:10:21 +0000474int thread_enter_synchr(const DrdThreadId tid)
475{
bart3772a982008-03-15 08:11:03 +0000476 tl_assert(IsValidDrdThreadId(tid));
477 return s_threadinfo[tid].synchr_nesting++;
bart0268dfa2008-03-11 20:10:21 +0000478}
479
480int thread_leave_synchr(const DrdThreadId tid)
481{
bart3772a982008-03-15 08:11:03 +0000482 tl_assert(IsValidDrdThreadId(tid));
483 tl_assert(s_threadinfo[tid].synchr_nesting >= 1);
484 return --s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000485}
486
487int thread_get_synchr_nesting_count(const DrdThreadId tid)
488{
bart3772a982008-03-15 08:11:03 +0000489 tl_assert(IsValidDrdThreadId(tid));
490 return s_threadinfo[tid].synchr_nesting;
bart0268dfa2008-03-11 20:10:21 +0000491}
492
bart1a473c72008-03-13 19:03:38 +0000493/** Append a new segment at the end of the segment list. */
bart26f73e12008-02-24 18:37:08 +0000494static void thread_append_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000495{
bart74a5f212008-05-11 06:43:07 +0000496 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000497 && tid != DRD_INVALID_THREADID);
bart23d3a4e2008-04-05 12:53:00 +0000498 // tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart3772a982008-03-15 08:11:03 +0000499 sg->prev = s_threadinfo[tid].last;
500 sg->next = 0;
501 if (s_threadinfo[tid].last)
502 s_threadinfo[tid].last->next = sg;
503 s_threadinfo[tid].last = sg;
504 if (s_threadinfo[tid].first == 0)
505 s_threadinfo[tid].first = sg;
bart23d3a4e2008-04-05 12:53:00 +0000506 // tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000507}
508
bart26f73e12008-02-24 18:37:08 +0000509/** Remove a segment from the segment list of thread threadid, and free the
510 * associated memory.
sewardjaf44c822007-11-25 14:01:38 +0000511 */
bart26f73e12008-02-24 18:37:08 +0000512static void thread_discard_segment(const DrdThreadId tid, Segment* const sg)
sewardjaf44c822007-11-25 14:01:38 +0000513{
bart74a5f212008-05-11 06:43:07 +0000514 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000515 && tid != DRD_INVALID_THREADID);
bart3f749672008-03-22 09:49:40 +0000516 //tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
bart26f73e12008-02-24 18:37:08 +0000517
bart3772a982008-03-15 08:11:03 +0000518 if (sg->prev)
519 sg->prev->next = sg->next;
520 if (sg->next)
521 sg->next->prev = sg->prev;
522 if (sg == s_threadinfo[tid].first)
523 s_threadinfo[tid].first = sg->next;
524 if (sg == s_threadinfo[tid].last)
525 s_threadinfo[tid].last = sg->prev;
barta2b6e1b2008-03-17 18:32:39 +0000526 sg_put(sg);
bart3f749672008-03-22 09:49:40 +0000527
528 //tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
sewardjaf44c822007-11-25 14:01:38 +0000529}
530
531VectorClock* thread_get_vc(const DrdThreadId tid)
532{
bart74a5f212008-05-11 06:43:07 +0000533 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
534 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000535 tl_assert(s_threadinfo[tid].last);
536 return &s_threadinfo[tid].last->vc;
sewardjaf44c822007-11-25 14:01:38 +0000537}
538
barta2b6e1b2008-03-17 18:32:39 +0000539/** Return the latest segment of thread 'tid' and increment its reference
540 * count.
541 */
542void thread_get_latest_segment(Segment** sg, const DrdThreadId tid)
543{
544 tl_assert(sg);
bart74a5f212008-05-11 06:43:07 +0000545 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
546 && tid != DRD_INVALID_THREADID);
barta2b6e1b2008-03-17 18:32:39 +0000547 tl_assert(s_threadinfo[tid].last);
548
549 sg_put(*sg);
550 *sg = sg_get(s_threadinfo[tid].last);
551}
552
sewardjaf44c822007-11-25 14:01:38 +0000553/**
554 * Compute the minimum of all latest vector clocks of all threads
555 * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
556 * @param vc pointer to a vectorclock, holds result upon return.
557 */
558static void thread_compute_minimum_vc(VectorClock* vc)
559{
bart3772a982008-03-15 08:11:03 +0000560 unsigned i;
561 Bool first;
562 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000563
bart3772a982008-03-15 08:11:03 +0000564 first = True;
565 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
566 {
567 latest_sg = s_threadinfo[i].last;
568 if (latest_sg)
569 {
570 if (first)
bart41b226c2009-02-14 16:55:19 +0000571 DRD_(vc_assign)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000572 else
bart41b226c2009-02-14 16:55:19 +0000573 DRD_(vc_min)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000574 first = False;
575 }
576 }
sewardjaf44c822007-11-25 14:01:38 +0000577}
578
579static void thread_compute_maximum_vc(VectorClock* vc)
580{
bart3772a982008-03-15 08:11:03 +0000581 unsigned i;
582 Bool first;
583 Segment* latest_sg;
sewardjaf44c822007-11-25 14:01:38 +0000584
bart3772a982008-03-15 08:11:03 +0000585 first = True;
586 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
587 {
588 latest_sg = s_threadinfo[i].last;
589 if (latest_sg)
590 {
591 if (first)
bart41b226c2009-02-14 16:55:19 +0000592 DRD_(vc_assign)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000593 else
bart41b226c2009-02-14 16:55:19 +0000594 DRD_(vc_combine)(vc, &latest_sg->vc);
bart3772a982008-03-15 08:11:03 +0000595 first = False;
596 }
597 }
sewardjaf44c822007-11-25 14:01:38 +0000598}
599
600/**
bart5bd9f2d2008-03-03 20:31:58 +0000601 * Discard all segments that have a defined order against the latest vector
sewardjaf44c822007-11-25 14:01:38 +0000602 * clock of every thread -- these segments can no longer be involved in a
603 * data race.
604 */
605static void thread_discard_ordered_segments(void)
606{
bart3772a982008-03-15 08:11:03 +0000607 unsigned i;
608 VectorClock thread_vc_min;
sewardjaf44c822007-11-25 14:01:38 +0000609
bart3772a982008-03-15 08:11:03 +0000610 s_discard_ordered_segments_count++;
sewardjaf44c822007-11-25 14:01:38 +0000611
bart41b226c2009-02-14 16:55:19 +0000612 DRD_(vc_init)(&thread_vc_min, 0, 0);
bart3772a982008-03-15 08:11:03 +0000613 thread_compute_minimum_vc(&thread_vc_min);
614 if (sg_get_trace())
615 {
616 char msg[256];
617 VectorClock thread_vc_max;
sewardjaf44c822007-11-25 14:01:38 +0000618
bart41b226c2009-02-14 16:55:19 +0000619 DRD_(vc_init)(&thread_vc_max, 0, 0);
bart3772a982008-03-15 08:11:03 +0000620 thread_compute_maximum_vc(&thread_vc_max);
621 VG_(snprintf)(msg, sizeof(msg),
622 "Discarding ordered segments -- min vc is ");
bart41b226c2009-02-14 16:55:19 +0000623 DRD_(vc_snprint)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
624 &thread_vc_min);
bart3772a982008-03-15 08:11:03 +0000625 VG_(snprintf)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
626 ", max vc is ");
bart41b226c2009-02-14 16:55:19 +0000627 DRD_(vc_snprint)(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
628 &thread_vc_max);
barta2b6e1b2008-03-17 18:32:39 +0000629 VG_(message)(Vg_UserMsg, "%s", msg);
bart41b226c2009-02-14 16:55:19 +0000630 DRD_(vc_cleanup)(&thread_vc_max);
bart3772a982008-03-15 08:11:03 +0000631 }
sewardjaf44c822007-11-25 14:01:38 +0000632
bart3772a982008-03-15 08:11:03 +0000633 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
634 {
635 Segment* sg;
636 Segment* sg_next;
637 for (sg = s_threadinfo[i].first;
bart41b226c2009-02-14 16:55:19 +0000638 sg && (sg_next = sg->next) && DRD_(vc_lte)(&sg->vc, &thread_vc_min);
bart3772a982008-03-15 08:11:03 +0000639 sg = sg_next)
640 {
641 thread_discard_segment(i, sg);
642 }
643 }
bart41b226c2009-02-14 16:55:19 +0000644 DRD_(vc_cleanup)(&thread_vc_min);
sewardjaf44c822007-11-25 14:01:38 +0000645}
646
barta9c37392008-03-22 09:38:48 +0000647/** Merge all segments that may be merged without triggering false positives
648 * or discarding real data races. For the theoretical background of segment
649 * merging, see also the following paper:
650 * Mark Christiaens, Michiel Ronsse and Koen De Bosschere.
651 * Bounding the number of segment histories during data race detection.
652 * Parallel Computing archive, Volume 28, Issue 9, pp 1221-1238,
653 * September 2002.
654 */
655static void thread_merge_segments(void)
656{
657 unsigned i;
658
659 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
660 {
661 Segment* sg;
662
bart23d3a4e2008-04-05 12:53:00 +0000663 // tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
barta9c37392008-03-22 09:38:48 +0000664
665 for (sg = s_threadinfo[i].first; sg; sg = sg->next)
666 {
667 if (sg_get_refcnt(sg) == 1
668 && sg->next
669 && sg_get_refcnt(sg->next) == 1
670 && sg->next->next)
671 {
672 /* Merge sg and sg->next into sg. */
673 sg_merge(sg, sg->next);
674 thread_discard_segment(i, sg->next);
675 }
676 }
677
bart23d3a4e2008-04-05 12:53:00 +0000678 // tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
barta9c37392008-03-22 09:38:48 +0000679 }
680}
681
bartd66e3a82008-04-06 15:02:17 +0000682/** Every change in the vector clock of a thread may cause segments that
683 * were previously ordered to this thread to become unordered. Hence,
barte73b0aa2008-06-28 07:19:56 +0000684 * it may be necessary to recalculate the conflict set if the vector clock
bartd66e3a82008-04-06 15:02:17 +0000685 * of the current thread is updated. This function check whether such a
686 * recalculation is necessary.
687 *
688 * @param tid Thread ID of the thread to which a new segment has been
689 * appended.
690 * @param new_sg Pointer to the most recent segment of thread tid.
691 */
barte73b0aa2008-06-28 07:19:56 +0000692static Bool conflict_set_update_needed(const DrdThreadId tid,
bart41b226c2009-02-14 16:55:19 +0000693 const Segment* const new_sg)
bartd66e3a82008-04-06 15:02:17 +0000694{
bart5d421ba2008-04-19 15:15:12 +0000695#if 0
bartd66e3a82008-04-06 15:02:17 +0000696 unsigned i;
697 const Segment* old_sg;
698
699 tl_assert(new_sg);
700
701 /* If a new segment was added to another thread than the running thread, */
barte73b0aa2008-06-28 07:19:56 +0000702 /* just tell the caller to update the conflict set. */
bartd66e3a82008-04-06 15:02:17 +0000703 if (tid != s_drd_running_tid)
704 return True;
705
barte73b0aa2008-06-28 07:19:56 +0000706 /* Always let the caller update the conflict set after creation of the */
bartd66e3a82008-04-06 15:02:17 +0000707 /* first segment. */
708 old_sg = new_sg->prev;
709 if (old_sg == 0)
710 return True;
711
712 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
713 {
714 Segment* q;
715
716 if (i == s_drd_running_tid)
717 continue;
718
719 for (q = s_threadinfo[i].last; q; q = q->prev)
720 {
721 /* If the expression below evaluates to false, this expression will */
722 /* also evaluate to false for all subsequent iterations. So stop */
723 /* iterating. */
bart41b226c2009-02-14 16:55:19 +0000724 if (DRD_(vc_lte)(&q->vc, &old_sg->vc))
bartd66e3a82008-04-06 15:02:17 +0000725 break;
726 /* If the vector clock of the 2nd the last segment is not ordered */
727 /* to the vector clock of segment q, and the last segment is, ask */
barte73b0aa2008-06-28 07:19:56 +0000728 /* the caller to update the conflict set. */
bart41b226c2009-02-14 16:55:19 +0000729 if (! DRD_(vc_lte)(&old_sg->vc, &q->vc))
bartd66e3a82008-04-06 15:02:17 +0000730 {
731 return True;
732 }
733 /* If the vector clock of the last segment is not ordered to the */
barte73b0aa2008-06-28 07:19:56 +0000734 /* vector clock of segment q, ask the caller to update the conflict */
bartd66e3a82008-04-06 15:02:17 +0000735 /* set. */
bart41b226c2009-02-14 16:55:19 +0000736 if (! DRD_(vc_lte)(&q->vc, &new_sg->vc) && ! DRD_(vc_lte)(&new_sg->vc, &q->vc))
bartd66e3a82008-04-06 15:02:17 +0000737 {
738 return True;
739 }
740 }
741 }
742
743 return False;
bart5d421ba2008-04-19 15:15:12 +0000744#else
745 return True;
746#endif
bartd66e3a82008-04-06 15:02:17 +0000747}
748
barta2b6e1b2008-03-17 18:32:39 +0000749/** Create a new segment for the specified thread, and discard any segments
750 * that cannot cause races anymore.
sewardjaf44c822007-11-25 14:01:38 +0000751 */
752void thread_new_segment(const DrdThreadId tid)
753{
bartd66e3a82008-04-06 15:02:17 +0000754 Segment* new_sg;
755
bart74a5f212008-05-11 06:43:07 +0000756 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
757 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000758
bartd66e3a82008-04-06 15:02:17 +0000759 new_sg = sg_new(tid, tid);
760 thread_append_segment(tid, new_sg);
761
barte73b0aa2008-06-28 07:19:56 +0000762 if (conflict_set_update_needed(tid, new_sg))
bartd66e3a82008-04-06 15:02:17 +0000763 {
barte73b0aa2008-06-28 07:19:56 +0000764 thread_compute_conflict_set(&s_conflict_set, s_drd_running_tid);
765 s_conflict_set_new_segment_count++;
bartd66e3a82008-04-06 15:02:17 +0000766 }
bart82195c12008-04-13 17:35:08 +0000767 else if (tid == s_drd_running_tid)
768 {
barte73b0aa2008-06-28 07:19:56 +0000769 tl_assert(thread_conflict_set_up_to_date(s_drd_running_tid));
bart82195c12008-04-13 17:35:08 +0000770 }
sewardjaf44c822007-11-25 14:01:38 +0000771
bart3772a982008-03-15 08:11:03 +0000772 thread_discard_ordered_segments();
bart26f73e12008-02-24 18:37:08 +0000773
barta9c37392008-03-22 09:38:48 +0000774 if (s_segment_merging)
775 thread_merge_segments();
sewardjaf44c822007-11-25 14:01:38 +0000776}
777
bart26f73e12008-02-24 18:37:08 +0000778/** Call this function after thread 'joiner' joined thread 'joinee'. */
sewardjaf44c822007-11-25 14:01:38 +0000779void thread_combine_vc(DrdThreadId joiner, DrdThreadId joinee)
780{
bart3772a982008-03-15 08:11:03 +0000781 tl_assert(joiner != joinee);
bart74a5f212008-05-11 06:43:07 +0000782 tl_assert(0 <= (int)joiner && joiner < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000783 && joiner != DRD_INVALID_THREADID);
bart74a5f212008-05-11 06:43:07 +0000784 tl_assert(0 <= (int)joinee && joinee < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000785 && joinee != DRD_INVALID_THREADID);
786 tl_assert(s_threadinfo[joiner].last);
787 tl_assert(s_threadinfo[joinee].last);
bart41b226c2009-02-14 16:55:19 +0000788 DRD_(vc_combine)(&s_threadinfo[joiner].last->vc, &s_threadinfo[joinee].last->vc);
bart3772a982008-03-15 08:11:03 +0000789 thread_discard_ordered_segments();
sewardjaf44c822007-11-25 14:01:38 +0000790
bart3772a982008-03-15 08:11:03 +0000791 if (joiner == s_drd_running_tid)
792 {
barte73b0aa2008-06-28 07:19:56 +0000793 thread_compute_conflict_set(&s_conflict_set, joiner);
bart3772a982008-03-15 08:11:03 +0000794 }
sewardjaf44c822007-11-25 14:01:38 +0000795}
796
bart26f73e12008-02-24 18:37:08 +0000797/** Call this function after thread 'tid' had to wait because of thread
798 * synchronization until the memory accesses in the segment with vector clock
799 * 'vc' finished.
800 */
sewardjaf44c822007-11-25 14:01:38 +0000801void thread_combine_vc2(DrdThreadId tid, const VectorClock* const vc)
802{
bart74a5f212008-05-11 06:43:07 +0000803 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
804 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000805 tl_assert(s_threadinfo[tid].last);
806 tl_assert(vc);
bart41b226c2009-02-14 16:55:19 +0000807 DRD_(vc_combine)(&s_threadinfo[tid].last->vc, vc);
barte73b0aa2008-06-28 07:19:56 +0000808 thread_compute_conflict_set(&s_conflict_set, tid);
bart3772a982008-03-15 08:11:03 +0000809 thread_discard_ordered_segments();
barte73b0aa2008-06-28 07:19:56 +0000810 s_conflict_set_combine_vc_count++;
sewardjaf44c822007-11-25 14:01:38 +0000811}
812
bart26f73e12008-02-24 18:37:08 +0000813/** Call this function whenever a thread is no longer using the memory
814 * [ a1, a2 [, e.g. because of a call to free() or a stack pointer
815 * increase.
816 */
sewardjaf44c822007-11-25 14:01:38 +0000817void thread_stop_using_mem(const Addr a1, const Addr a2)
818{
bartd43f8d32008-03-16 17:29:20 +0000819 DrdThreadId other_user;
820 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000821
bart3772a982008-03-15 08:11:03 +0000822 /* For all threads, mark the range [ a1, a2 [ as no longer in use. */
bartd43f8d32008-03-16 17:29:20 +0000823 other_user = DRD_INVALID_THREADID;
bart3772a982008-03-15 08:11:03 +0000824 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
825 {
826 Segment* p;
827 for (p = s_threadinfo[i].first; p; p = p->next)
828 {
829 if (other_user == DRD_INVALID_THREADID
bart8bf2f8b2008-03-30 17:56:43 +0000830 && i != s_drd_running_tid)
sewardjaf44c822007-11-25 14:01:38 +0000831 {
bart8bf2f8b2008-03-30 17:56:43 +0000832 if (UNLIKELY(bm_test_and_clear(p->bm, a1, a2)))
833 {
834 other_user = i;
835 }
836 continue;
sewardjaf44c822007-11-25 14:01:38 +0000837 }
bart3772a982008-03-15 08:11:03 +0000838 bm_clear(p->bm, a1, a2);
839 }
840 }
sewardjaf44c822007-11-25 14:01:38 +0000841
bart3772a982008-03-15 08:11:03 +0000842 /* If any other thread had accessed memory in [ a1, a2 [, update the */
barte73b0aa2008-06-28 07:19:56 +0000843 /* conflict set. */
bart3772a982008-03-15 08:11:03 +0000844 if (other_user != DRD_INVALID_THREADID
barte73b0aa2008-06-28 07:19:56 +0000845 && bm_has_any_access(s_conflict_set, a1, a2))
bart3772a982008-03-15 08:11:03 +0000846 {
barte73b0aa2008-06-28 07:19:56 +0000847 thread_compute_conflict_set(&s_conflict_set, thread_get_running_tid());
bart3772a982008-03-15 08:11:03 +0000848 }
sewardjaf44c822007-11-25 14:01:38 +0000849}
850
bart0268dfa2008-03-11 20:10:21 +0000851void thread_start_recording(const DrdThreadId tid)
852{
bart74a5f212008-05-11 06:43:07 +0000853 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
854 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000855 tl_assert(! s_threadinfo[tid].is_recording);
856 s_threadinfo[tid].is_recording = True;
bart0268dfa2008-03-11 20:10:21 +0000857}
858
859void thread_stop_recording(const DrdThreadId tid)
860{
bart74a5f212008-05-11 06:43:07 +0000861 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
862 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +0000863 tl_assert(s_threadinfo[tid].is_recording);
864 s_threadinfo[tid].is_recording = False;
bart0268dfa2008-03-11 20:10:21 +0000865}
866
sewardjaf44c822007-11-25 14:01:38 +0000867void thread_print_all(void)
868{
bart3772a982008-03-15 08:11:03 +0000869 unsigned i;
870 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000871
bart3772a982008-03-15 08:11:03 +0000872 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
873 {
874 if (s_threadinfo[i].first)
875 {
876 VG_(printf)("**************\n"
barta2b6e1b2008-03-17 18:32:39 +0000877 "* thread %3d (%d/%d/%d/0x%lx/%d) *\n"
bart3772a982008-03-15 08:11:03 +0000878 "**************\n",
879 i,
880 s_threadinfo[i].vg_thread_exists,
881 s_threadinfo[i].vg_threadid,
882 s_threadinfo[i].posix_thread_exists,
883 s_threadinfo[i].pt_threadid,
bart354009c2008-03-16 10:42:33 +0000884 s_threadinfo[i].detached_posix_thread);
bart3772a982008-03-15 08:11:03 +0000885 for (p = s_threadinfo[i].first; p; p = p->next)
sewardjaf44c822007-11-25 14:01:38 +0000886 {
bart3772a982008-03-15 08:11:03 +0000887 sg_print(p);
sewardjaf44c822007-11-25 14:01:38 +0000888 }
bart3772a982008-03-15 08:11:03 +0000889 }
890 }
sewardjaf44c822007-11-25 14:01:38 +0000891}
892
893static void show_call_stack(const DrdThreadId tid,
894 const Char* const msg,
895 ExeContext* const callstack)
896{
bart3772a982008-03-15 08:11:03 +0000897 const ThreadId vg_tid = DrdThreadIdToVgThreadId(tid);
sewardjaf44c822007-11-25 14:01:38 +0000898
bartaa97a542008-03-16 17:57:01 +0000899 VG_(message)(Vg_UserMsg, "%s (thread %d/%d)", msg, vg_tid, tid);
sewardjaf44c822007-11-25 14:01:38 +0000900
bart3772a982008-03-15 08:11:03 +0000901 if (vg_tid != VG_INVALID_THREADID)
902 {
903 if (callstack)
904 {
905 VG_(pp_ExeContext)(callstack);
906 }
907 else
908 {
909 VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
910 }
911 }
912 else
913 {
914 VG_(message)(Vg_UserMsg,
915 " (thread finished, call stack no longer available)");
916 }
sewardjaf44c822007-11-25 14:01:38 +0000917}
918
sewardjaf44c822007-11-25 14:01:38 +0000919static void
920thread_report_conflicting_segments_segment(const DrdThreadId tid,
921 const Addr addr,
922 const SizeT size,
923 const BmAccessTypeT access_type,
924 const Segment* const p)
925{
bart3772a982008-03-15 08:11:03 +0000926 unsigned i;
sewardjaf44c822007-11-25 14:01:38 +0000927
bart74a5f212008-05-11 06:43:07 +0000928 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000929 && tid != DRD_INVALID_THREADID);
930 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000931
bart3772a982008-03-15 08:11:03 +0000932 for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
933 {
934 if (i != tid)
935 {
936 Segment* q;
937 for (q = s_threadinfo[i].last; q; q = q->prev)
sewardjaf44c822007-11-25 14:01:38 +0000938 {
bart3772a982008-03-15 08:11:03 +0000939 // Since q iterates over the segments of thread i in order of
940 // decreasing vector clocks, if q->vc <= p->vc, then
941 // q->next->vc <= p->vc will also hold. Hence, break out of the
942 // loop once this condition is met.
bart41b226c2009-02-14 16:55:19 +0000943 if (DRD_(vc_lte)(&q->vc, &p->vc))
bart3772a982008-03-15 08:11:03 +0000944 break;
bart41b226c2009-02-14 16:55:19 +0000945 if (! DRD_(vc_lte)(&p->vc, &q->vc))
bart3772a982008-03-15 08:11:03 +0000946 {
947 if (bm_has_conflict_with(q->bm, addr, addr + size, access_type))
948 {
949 tl_assert(q->stacktrace);
950 show_call_stack(i, "Other segment start",
951 q->stacktrace);
952 show_call_stack(i, "Other segment end",
953 q->next ? q->next->stacktrace : 0);
954 }
955 }
sewardjaf44c822007-11-25 14:01:38 +0000956 }
bart3772a982008-03-15 08:11:03 +0000957 }
958 }
sewardjaf44c822007-11-25 14:01:38 +0000959}
960
961void thread_report_conflicting_segments(const DrdThreadId tid,
962 const Addr addr,
963 const SizeT size,
964 const BmAccessTypeT access_type)
965{
bart3772a982008-03-15 08:11:03 +0000966 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +0000967
bart74a5f212008-05-11 06:43:07 +0000968 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
bart3772a982008-03-15 08:11:03 +0000969 && tid != DRD_INVALID_THREADID);
sewardjaf44c822007-11-25 14:01:38 +0000970
bart3772a982008-03-15 08:11:03 +0000971 for (p = s_threadinfo[tid].first; p; p = p->next)
972 {
973 if (bm_has(p->bm, addr, addr + size, access_type))
974 {
975 thread_report_conflicting_segments_segment(tid, addr, size,
976 access_type, p);
977 }
978 }
sewardjaf44c822007-11-25 14:01:38 +0000979}
sewardjaf44c822007-11-25 14:01:38 +0000980
barte73b0aa2008-06-28 07:19:56 +0000981/** Verify whether the conflict set for thread tid is up to date. Only perform
982 * the check if the environment variable DRD_VERIFY_CONFLICT_SET has been set.
bart82195c12008-04-13 17:35:08 +0000983 */
barte73b0aa2008-06-28 07:19:56 +0000984static Bool thread_conflict_set_up_to_date(const DrdThreadId tid)
bart82195c12008-04-13 17:35:08 +0000985{
barte73b0aa2008-06-28 07:19:56 +0000986 static int do_verify_conflict_set = -1;
bart82195c12008-04-13 17:35:08 +0000987 Bool result;
barte73b0aa2008-06-28 07:19:56 +0000988 struct bitmap* computed_conflict_set = 0;
bart82195c12008-04-13 17:35:08 +0000989
barte73b0aa2008-06-28 07:19:56 +0000990 if (do_verify_conflict_set < 0)
bart82195c12008-04-13 17:35:08 +0000991 {
barte73b0aa2008-06-28 07:19:56 +0000992 //VG_(message)(Vg_DebugMsg, "%s", VG_(getenv)("DRD_VERIFY_CONFLICT_SET"));
993 do_verify_conflict_set = VG_(getenv)("DRD_VERIFY_CONFLICT_SET") != 0;
bart82195c12008-04-13 17:35:08 +0000994 }
barte73b0aa2008-06-28 07:19:56 +0000995 if (do_verify_conflict_set == 0)
bart82195c12008-04-13 17:35:08 +0000996 return True;
997
barte73b0aa2008-06-28 07:19:56 +0000998 thread_compute_conflict_set(&computed_conflict_set, tid);
999 result = bm_equal(s_conflict_set, computed_conflict_set);
1000 bm_delete(computed_conflict_set);
bart82195c12008-04-13 17:35:08 +00001001 return result;
1002}
1003
bart26f73e12008-02-24 18:37:08 +00001004/** Compute a bitmap that represents the union of all memory accesses of all
1005 * segments that are unordered to the current segment of the thread tid.
sewardjaf44c822007-11-25 14:01:38 +00001006 */
barte73b0aa2008-06-28 07:19:56 +00001007static void thread_compute_conflict_set(struct bitmap** conflict_set,
1008 const DrdThreadId tid)
sewardjaf44c822007-11-25 14:01:38 +00001009{
bart3772a982008-03-15 08:11:03 +00001010 Segment* p;
sewardjaf44c822007-11-25 14:01:38 +00001011
bart74a5f212008-05-11 06:43:07 +00001012 tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
1013 && tid != DRD_INVALID_THREADID);
bart3772a982008-03-15 08:11:03 +00001014 tl_assert(tid == s_drd_running_tid);
sewardjaf44c822007-11-25 14:01:38 +00001015
barte73b0aa2008-06-28 07:19:56 +00001016 s_update_conflict_set_count++;
1017 s_conflict_set_bitmap_creation_count -= bm_get_bitmap_creation_count();
1018 s_conflict_set_bitmap2_creation_count -= bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +00001019
barte73b0aa2008-06-28 07:19:56 +00001020 if (*conflict_set)
bart3772a982008-03-15 08:11:03 +00001021 {
barte73b0aa2008-06-28 07:19:56 +00001022 bm_delete(*conflict_set);
bart3772a982008-03-15 08:11:03 +00001023 }
barte73b0aa2008-06-28 07:19:56 +00001024 *conflict_set = bm_new();
bart26f73e12008-02-24 18:37:08 +00001025
barte73b0aa2008-06-28 07:19:56 +00001026 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001027 {
1028 char msg[256];
1029
1030 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001031 "computing conflict set for thread %d/%d with vc ",
bartaa97a542008-03-16 17:57:01 +00001032 DrdThreadIdToVgThreadId(tid), tid);
bart41b226c2009-02-14 16:55:19 +00001033 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1034 sizeof(msg) - VG_(strlen)(msg),
1035 &s_threadinfo[tid].last->vc);
barta2b6e1b2008-03-17 18:32:39 +00001036 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001037 }
1038
1039 p = s_threadinfo[tid].last;
1040 {
1041 unsigned j;
1042
barte73b0aa2008-06-28 07:19:56 +00001043 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001044 {
bart26f73e12008-02-24 18:37:08 +00001045 char msg[256];
1046
1047 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001048 "conflict set: thread [%d] at vc ",
bart26f73e12008-02-24 18:37:08 +00001049 tid);
bart41b226c2009-02-14 16:55:19 +00001050 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1051 sizeof(msg) - VG_(strlen)(msg),
1052 &p->vc);
barta2b6e1b2008-03-17 18:32:39 +00001053 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001054 }
sewardjaf44c822007-11-25 14:01:38 +00001055
bart3772a982008-03-15 08:11:03 +00001056 for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
1057 {
bartd66e3a82008-04-06 15:02:17 +00001058 if (j != tid && IsValidDrdThreadId(j))
bart26f73e12008-02-24 18:37:08 +00001059 {
bart3772a982008-03-15 08:11:03 +00001060 const Segment* q;
1061 for (q = s_threadinfo[j].last; q; q = q->prev)
bartd66e3a82008-04-06 15:02:17 +00001062 {
bart41b226c2009-02-14 16:55:19 +00001063 if (! DRD_(vc_lte)(&q->vc, &p->vc) && ! DRD_(vc_lte)(&p->vc, &q->vc))
bart3772a982008-03-15 08:11:03 +00001064 {
barte73b0aa2008-06-28 07:19:56 +00001065 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001066 {
1067 char msg[256];
1068 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001069 "conflict set: [%d] merging segment ", j);
bart41b226c2009-02-14 16:55:19 +00001070 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1071 sizeof(msg) - VG_(strlen)(msg),
1072 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +00001073 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001074 }
barte73b0aa2008-06-28 07:19:56 +00001075 bm_merge2(*conflict_set, q->bm);
bart3772a982008-03-15 08:11:03 +00001076 }
1077 else
1078 {
barte73b0aa2008-06-28 07:19:56 +00001079 if (s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001080 {
1081 char msg[256];
1082 VG_(snprintf)(msg, sizeof(msg),
barte73b0aa2008-06-28 07:19:56 +00001083 "conflict set: [%d] ignoring segment ", j);
bart41b226c2009-02-14 16:55:19 +00001084 DRD_(vc_snprint)(msg + VG_(strlen)(msg),
1085 sizeof(msg) - VG_(strlen)(msg),
1086 &q->vc);
barta2b6e1b2008-03-17 18:32:39 +00001087 VG_(message)(Vg_UserMsg, "%s", msg);
bart3772a982008-03-15 08:11:03 +00001088 }
1089 }
bartd66e3a82008-04-06 15:02:17 +00001090 }
bart26f73e12008-02-24 18:37:08 +00001091 }
bart3772a982008-03-15 08:11:03 +00001092 }
bart3772a982008-03-15 08:11:03 +00001093 }
sewardjaf44c822007-11-25 14:01:38 +00001094
barte73b0aa2008-06-28 07:19:56 +00001095 s_conflict_set_bitmap_creation_count += bm_get_bitmap_creation_count();
1096 s_conflict_set_bitmap2_creation_count += bm_get_bitmap2_creation_count();
sewardjaf44c822007-11-25 14:01:38 +00001097
barte73b0aa2008-06-28 07:19:56 +00001098 if (0 && s_trace_conflict_set)
bart3772a982008-03-15 08:11:03 +00001099 {
barte73b0aa2008-06-28 07:19:56 +00001100 VG_(message)(Vg_UserMsg, "[%d] new conflict set:", tid);
1101 bm_print(*conflict_set);
1102 VG_(message)(Vg_UserMsg, "[%d] end of new conflict set.", tid);
bart3772a982008-03-15 08:11:03 +00001103 }
sewardjaf44c822007-11-25 14:01:38 +00001104}
1105
sewardjaf44c822007-11-25 14:01:38 +00001106ULong thread_get_context_switch_count(void)
1107{
bart3772a982008-03-15 08:11:03 +00001108 return s_context_switch_count;
sewardjaf44c822007-11-25 14:01:38 +00001109}
1110
sewardjaf44c822007-11-25 14:01:38 +00001111ULong thread_get_discard_ordered_segments_count(void)
1112{
bart3772a982008-03-15 08:11:03 +00001113 return s_discard_ordered_segments_count;
sewardjaf44c822007-11-25 14:01:38 +00001114}
1115
barte73b0aa2008-06-28 07:19:56 +00001116ULong thread_get_update_conflict_set_count(ULong* dsnsc, ULong* dscvc)
sewardjaf44c822007-11-25 14:01:38 +00001117{
bartd66e3a82008-04-06 15:02:17 +00001118 tl_assert(dsnsc);
1119 tl_assert(dscvc);
barte73b0aa2008-06-28 07:19:56 +00001120 *dsnsc = s_conflict_set_new_segment_count;
1121 *dscvc = s_conflict_set_combine_vc_count;
1122 return s_update_conflict_set_count;
sewardjaf44c822007-11-25 14:01:38 +00001123}
1124
barte73b0aa2008-06-28 07:19:56 +00001125ULong thread_get_conflict_set_bitmap_creation_count(void)
sewardjaf44c822007-11-25 14:01:38 +00001126{
barte73b0aa2008-06-28 07:19:56 +00001127 return s_conflict_set_bitmap_creation_count;
sewardjaf44c822007-11-25 14:01:38 +00001128}
1129
barte73b0aa2008-06-28 07:19:56 +00001130ULong thread_get_conflict_set_bitmap2_creation_count(void)
sewardjaf44c822007-11-25 14:01:38 +00001131{
barte73b0aa2008-06-28 07:19:56 +00001132 return s_conflict_set_bitmap2_creation_count;
sewardjaf44c822007-11-25 14:01:38 +00001133}