1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helgrind: a Valgrind tool for detecting errors               ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- in threaded programs.                              hg_main.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Helgrind, a Valgrind tool for detecting errors
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in threaded programs.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2007-2011 OpenWorks LLP
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      info@open-works.co.uk
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2007-2011 Apple, Inc.
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Neither the names of the U.S. Department of Energy nor the
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   University of California nor the names of its contributors may be
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   used to endorse or promote products derived from this software
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   without prior written permission.
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_threadstate.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_tooliface.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_hashtable.h"
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_replacemalloc.h"
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_machine.h"
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_xarray.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_stacktrace.h"
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_wordfm.h"
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_debuginfo.h" // VG_(find_seginfo), VG_(seginfo_soname)
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_redir.h"     // sonames for the dynamic linkers
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_vki.h"       // VKI_PAGE_SIZE
55f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#include "pub_tool_libcproc.h"  // VG_(atfork)
56f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_basics.h"
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_wordset.h"
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_lock_n_thread.h"
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_errors.h"
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libhb.h"
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "helgrind.h"
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME: new_mem_w_tid ignores the supplied tid. (wtf?!)
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME: when client destroys a lock or a CV, remove these
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// from our mappings, so that the associated SO can be freed up
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                          ---*/
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Note this needs to be compiled with -fno-strict-aliasing, since it
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   contains a whole bunch of calls to lookupFM etc which cast between
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word and pointer types.  gcc rightly complains this breaks ANSI C
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   strict aliasing rules, at -O2.  No complaints at -O, but -O2 gives
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   worthwhile performance benefits over -O.
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME what is supposed to happen to locks in memory which
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// is relocated as a result of client realloc?
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME put referencing ThreadId into Thread and get
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// rid of the slow reverse mapping function.
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME accesses to NoAccess areas: change state to Excl?
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME report errors for accesses of NoAccess memory?
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME pth_cond_wait/timedwait wrappers.  Even if these fail,
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the thread still holds the lock.
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------ Debug/trace options ------------ */
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 0 for silent, 1 for some stuff, 2 for lots of stuff
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SHOW_EVENTS 0
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void all__sanity_check ( Char* who ); /* fwds */
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define HG_CLI__MALLOC_REDZONE_SZB 16 /* let's say */
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 0 for none, 1 for dump at end of run
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SHOW_DATA_STRUCTURES 0
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------ Misc comments ------------ */
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME: don't hardwire initial entries for root thread.
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Instead, let the pre_thread_ll_create handler do this.
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Primary data structures                                  ---*/
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Admin linked list of Threads */
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Thread* admin_threads = NULL;
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovThread* get_admin_threads ( void ) { return admin_threads; }
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Admin double linked list of Locks */
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* We need a double linked list to properly and efficiently
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   handle del_LockN. */
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Lock* admin_locks = NULL;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Mapping table for core ThreadIds to Thread* */
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Thread** map_threads = NULL; /* Array[VG_N_THREADS] of Thread* */
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Mapping table for lock guest addresses to Lock* */
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_locks = NULL; /* WordFM LockAddr Lock* */
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* The word-set universes for lock sets. */
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordSetU* univ_lsets = NULL; /* sets of Lock* */
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordSetU* univ_laog  = NULL; /* sets of Lock*, for LAOG */
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Int next_gc_univ_laog = 1;
140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* univ_laog will be garbaged collected when the nr of element in univ_laog is
141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   >= next_gc_univ_laog. */
142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Allow libhb to get at the universe of locksets stored
144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   here.  Sigh. */
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovWordSetU* HG_(get_univ_lsets) ( void ) { return univ_lsets; }
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Allow libhb to get at the list of locks stored here.  Ditto
148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   sigh. */
149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovLock* HG_(get_admin_locks) ( void ) { return admin_locks; }
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Simple helpers for the data structures                   ---*/
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UWord stats__lockN_acquires = 0;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UWord stats__lockN_releases = 0;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr ); /*fwds*/
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Constructors --------- */
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Thread* mk_Thread ( Thr* hbthr ) {
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Int indx      = 1;
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thread       = HG_(zalloc)( "hg.mk_Thread.1", sizeof(Thread) );
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->locksetA     = HG_(emptyWS)( univ_lsets );
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->locksetW     = HG_(emptyWS)( univ_lsets );
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->magic        = Thread_MAGIC;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->hbthr        = hbthr;
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->coretid      = VG_INVALID_THREADID;
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->created_at   = NULL;
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->announced    = False;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->errmsg_index = indx++;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread->admin        = admin_threads;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   admin_threads        = thread;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return thread;
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Make a new lock which is unlocked (hence ownerless)
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// and insert the new lock in admin_locks double linked list.
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Lock* mk_LockN ( LockKind kind, Addr guestaddr ) {
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static ULong unique = 0;
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lock             = HG_(zalloc)( "hg.mk_Lock.1", sizeof(Lock) );
185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* begin: add to double linked list */
186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (admin_locks)
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      admin_locks->admin_prev = lock;
188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   lock->admin_next       = admin_locks;
189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   lock->admin_prev       = NULL;
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   admin_locks            = lock;
191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* end: add */
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->unique           = unique++;
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->magic            = LockN_MAGIC;
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->appeared_at      = NULL;
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->acquired_at      = NULL;
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->hbso             = libhb_so_alloc();
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->guestaddr        = guestaddr;
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->kind             = kind;
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->heldW            = False;
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock->heldBy           = NULL;
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lock));
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return lock;
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Release storage for a Lock.  Also release storage in .heldBy, if
206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   any. Removes from admin_locks double linked list. */
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void del_LockN ( Lock* lk )
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->hbso);
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_dealloc(lk->hbso);
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy)
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteBag)( lk->heldBy );
214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* begin: del lock from double linked list */
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (lk == admin_locks) {
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(lk->admin_prev == NULL);
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (lk->admin_next)
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         lk->admin_next->admin_prev = NULL;
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      admin_locks = lk->admin_next;
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else {
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(lk->admin_prev != NULL);
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lk->admin_prev->admin_next = lk->admin_next;
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (lk->admin_next)
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         lk->admin_next->admin_prev = lk->admin_prev;
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* end: del */
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(lk, 0xAA, sizeof(*lk));
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(free)(lk);
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Update 'lk' to reflect that 'thr' now has a write-acquisition of
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it.  This is done strictly: only combinations resulting from
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   correct program and libpthread behaviour are allowed. */
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lockN_acquire_writer ( Lock* lk, Thread* thr )
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stats__lockN_acquires++;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* EXPOSITION only */
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We need to keep recording snapshots of where the lock was
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      acquired, so as to produce better lock-order error messages. */
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->acquired_at == NULL) {
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ThreadId tid;
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lk->heldBy == NULL);
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid = map_threads_maybe_reverse_lookup_SLOW(thr);
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->acquired_at
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lk->heldBy != NULL);
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* end EXPOSITION only */
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (lk->kind) {
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_nonRec:
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case_LK_nonRec:
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lk->heldBy == NULL); /* can't w-lock recursively */
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(!lk->heldW);
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldW  = True;
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNaw.1", HG_(free) );
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToBag)( lk->heldBy, (Word)thr );
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_mbRec:
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (lk->heldBy == NULL)
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto case_LK_nonRec;
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* 2nd and subsequent locking of a lock by its owner */
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lk->heldW);
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* assert: lk is only held by one thread .. */
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(VG_(sizeUniqueBag(lk->heldBy)) == 1);
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* assert: .. and that thread is 'thr'. */
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(VG_(elemBag)(lk->heldBy, (Word)thr)
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   == VG_(sizeTotalBag)(lk->heldBy));
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToBag)(lk->heldBy, (Word)thr);
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_rdwr:
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lk->heldBy == NULL && !lk->heldW); /* must be unheld */
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto case_LK_nonRec;
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(0);
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  tl_assert(HG_(is_sane_LockN)(lk));
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lockN_acquire_reader ( Lock* lk, Thread* thr )
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* can only add reader to a reader-writer lock. */
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->kind == LK_rdwr);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* lk must be free or already r-held. */
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->heldBy == NULL
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             || (lk->heldBy != NULL && !lk->heldW));
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stats__lockN_acquires++;
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* EXPOSITION only */
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We need to keep recording snapshots of where the lock was
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      acquired, so as to produce better lock-order error messages. */
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->acquired_at == NULL) {
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ThreadId tid;
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lk->heldBy == NULL);
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid = map_threads_maybe_reverse_lookup_SLOW(thr);
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->acquired_at
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lk->heldBy != NULL);
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* end EXPOSITION only */
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy) {
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToBag)(lk->heldBy, (Word)thr);
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->heldW  = False;
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNar.1", HG_(free) );
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToBag)( lk->heldBy, (Word)thr );
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(!lk->heldW);
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Update 'lk' to reflect a release of it by 'thr'.  This is done
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   strictly: only combinations resulting from correct program and
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libpthread behaviour are allowed. */
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lockN_release ( Lock* lk, Thread* thr )
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool b;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* lock must be held by someone */
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->heldBy);
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stats__lockN_releases++;
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Remove it from the holder set */
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   b = VG_(delFromBag)(lk->heldBy, (Word)thr);
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* thr must actually have been a holder of lk */
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(b);
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* normalise */
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->acquired_at);
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(isEmptyBag)(lk->heldBy)) {
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteBag)(lk->heldBy);
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->heldBy      = NULL;
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->heldW       = False;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk->acquired_at = NULL;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void remove_Lock_from_locksets_of_all_owning_Threads( Lock* lk )
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!lk->heldBy) {
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!lk->heldW);
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* for each thread that holds this lock do ... */
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(initIterBag)( lk->heldBy );
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (VG_(nextIterBag)( lk->heldBy, (Word*)&thr, NULL )) {
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_Thread)(thr));
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(elemWS)( univ_lsets,
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             thr->locksetA, (Word)lk ));
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr->locksetA
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lk );
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->heldW) {
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(HG_(elemWS)( univ_lsets,
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                thr->locksetW, (Word)lk ));
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr->locksetW
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lk );
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(doneIterBag)( lk->heldBy );
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Print out the primary data structures                    ---*/
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PP_THREADS      (1<<1)
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PP_LOCKS        (1<<2)
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PP_ALL (PP_THREADS | PP_LOCKS)
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const Int sHOW_ADMIN = 0;
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void space ( Int n )
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  i;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char spaces[128+1];
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(n >= 0 && n < 128);
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n == 0)
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n; i++)
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      spaces[i] = ' ';
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spaces[i] = 0;
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(i < 128+1);
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("%s", spaces);
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_Thread ( Int d, Thread* t )
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+0); VG_(printf)("Thread %p {\n", t);
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sHOW_ADMIN) {
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("admin    %p\n",   t->admin);
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("magic    0x%x\n", (UInt)t->magic);
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("locksetA %d\n",   (Int)t->locksetA);
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("locksetW %d\n",   (Int)t->locksetW);
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+0); VG_(printf)("}\n");
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_admin_threads ( Int d )
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     i, n;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* t;
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (n = 0, t = admin_threads;  t;  n++, t = t->admin) {
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* nothing */
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("admin_threads (%d records) {\n", n);
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0, t = admin_threads;  t;  i++, t = t->admin) {
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) {
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         space(n);
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("admin_threads record %d of %d:\n", i, n);
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_Thread(d+3, t);
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("}\n");
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_map_threads ( Int d )
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i, n = 0;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("map_threads ");
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_N_THREADS; i++) {
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (map_threads[i] != NULL)
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n++;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("(%d entries) {\n", n);
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_N_THREADS; i++) {
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (map_threads[i] == NULL)
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      space(d+3);
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("coretid %d -> Thread %p\n", i, map_threads[i]);
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("}\n");
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const HChar* show_LockKind ( LockKind lkk ) {
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (lkk) {
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_mbRec:  return "mbRec";
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_nonRec: return "nonRec";
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case LK_rdwr:   return "rdwr";
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:        tl_assert(0);
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_Lock ( Int d, Lock* lk )
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+0); VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sHOW_ADMIN) {
463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      space(d+3); VG_(printf)("admin_n  %p\n",   lk->admin_next);
464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      space(d+3); VG_(printf)("admin_p  %p\n",   lk->admin_prev);
465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      space(d+3); VG_(printf)("magic    0x%x\n", (UInt)lk->magic);
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("unique %llu\n", lk->unique);
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("kind   %s\n", show_LockKind(lk->kind));
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("heldW  %s\n", lk->heldW ? "yes" : "no");
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy) {
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* thr;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word    count;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(" { ");
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(initIterBag)( lk->heldBy );
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (VG_(nextIterBag)( lk->heldBy, (Word*)&thr, &count ))
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("%lu:%p ", count, thr);
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(doneIterBag)( lk->heldBy );
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("}");
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n");
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d+0); VG_(printf)("}\n");
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_admin_locks ( Int d )
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   i, n;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk;
489b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (n = 0, lk = admin_locks;  lk;  n++, lk = lk->admin_next) {
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* nothing */
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("admin_locks (%d records) {\n", n);
493b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0, lk = admin_locks;  lk;  i++, lk = lk->admin_next) {
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) {
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         space(n);
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("admin_locks record %d of %d:\n", i, n);
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_Lock(d+3, lk);
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("}\n");
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_map_locks ( Int d )
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void* gla;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk;
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("map_locks (%d entries) {\n",
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Int)VG_(sizeFM)( map_locks ));
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(initIterFM)( map_locks );
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (VG_(nextIterFM)( map_locks, (Word*)&gla,
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      (Word*)&lk )) {
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      space(d+3);
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("guest %p -> Lock %p\n", gla, lk);
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(doneIterFM)( map_locks );
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space(d); VG_(printf)("}\n");
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_everything ( Int flags, Char* caller )
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int d = 0;
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n");
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("All_Data_Structures (caller = \"%s\") {\n", caller);
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (flags & PP_THREADS) {
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_admin_threads(d+3);
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_map_threads(d+3);
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (flags & PP_LOCKS) {
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_admin_locks(d+3);
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_map_locks(d+3);
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n");
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("}\n");
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n");
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef SHOW_ADMIN
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Initialise the primary data structures                   ---*/
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void initialise_data_structures ( Thr* hbthr_root )
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*   thr;
552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   WordSetID wsid;
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get everything initialised and zeroed. */
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(admin_threads == NULL);
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(admin_locks == NULL);
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sizeof(Addr) == sizeof(Word));
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_threads == NULL);
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_threads = HG_(zalloc)( "hg.ids.1", VG_N_THREADS * sizeof(Thread*) );
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_threads != NULL);
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sizeof(Addr) == sizeof(Word));
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_locks == NULL);
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_locks = VG_(newFM)( HG_(zalloc), "hg.ids.2", HG_(free),
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           NULL/*unboxed Word cmp*/);
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_locks != NULL);
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(univ_lsets == NULL);
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   univ_lsets = HG_(newWordSetU)( HG_(zalloc), "hg.ids.4", HG_(free),
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  8/*cacheSize*/ );
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(univ_lsets != NULL);
574b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Ensure that univ_lsets is non-empty, with lockset zero being the
575b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      empty lockset.  hg_errors.c relies on the assumption that
576b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lockset number zero in univ_lsets is always valid. */
577b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   wsid = HG_(emptyWS)(univ_lsets);
578b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(wsid == 0);
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(univ_laog == NULL);
581b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_track_lockorders)) {
582b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      univ_laog = HG_(newWordSetU)( HG_(zalloc), "hg.ids.5 (univ_laog)",
583b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    HG_(free), 24/*cacheSize*/ );
584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(univ_laog != NULL);
585b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up entries for the root thread */
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: this assumes that the first real ThreadId is 1
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* a Thread for the new thread ... */
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = mk_Thread(hbthr_root);
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr->coretid = 1; /* FIXME: hardwires an assumption about the
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        identity of the root thread. */
594b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert( libhb_get_Thr_hgthread(hbthr_root) == NULL );
595b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_set_Thr_hgthread(hbthr_root, thr);
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* and bind it in the thread-map table. */
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_ThreadId)(thr->coretid));
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr->coretid != VG_INVALID_THREADID);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_threads[thr->coretid] = thr;
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_INVALID_THREADID == 0);
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all__sanity_check("initialise_data_structures");
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- map_threads :: array[core-ThreadId] of Thread*           ---*/
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Doesn't assert if the relevant map_threads entry is NULL. */
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Thread* map_threads_maybe_lookup ( ThreadId coretid )
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(coretid) );
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads[coretid];
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return thr;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Asserts if the relevant map_threads entry is NULL. */
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Thread* map_threads_lookup ( ThreadId coretid )
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(coretid) );
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads[coretid];
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr);
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return thr;
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a reverse lookup.  Does not assert if 'thr' is not found in
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_threads. */
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr )
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid;
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check nobody used the invalid-threadid slot */
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_INVALID_THREADID >= 0 && VG_INVALID_THREADID < VG_N_THREADS);
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_threads[VG_INVALID_THREADID] == NULL);
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tid = thr->coretid;
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_ThreadId)(tid));
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tid;
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a reverse lookup.  Warning: POTENTIALLY SLOW.  Asserts if 'thr'
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is not found in map_threads. */
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ThreadId map_threads_reverse_lookup_SLOW ( Thread* thr )
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid = map_threads_maybe_reverse_lookup_SLOW( thr );
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(tid != VG_INVALID_THREADID);
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_threads[tid]);
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(map_threads[tid]->coretid == tid);
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tid;
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_threads_delete ( ThreadId coretid )
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(coretid != 0);
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(coretid) );
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads[coretid];
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr);
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_threads[coretid] = NULL;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- map_locks :: WordFM guest-Addr-of-lock Lock*             ---*/
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Make sure there is a lock table entry for the given (lock) guest
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address.  If not, create one of the stated 'kind' in unheld state.
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In any case, return the address of the existing or new Lock. */
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownLock* map_locks_lookup_or_create ( LockKind lkk, Addr ga, ThreadId tid )
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  found;
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* oldlock = NULL;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_ThreadId)(tid));
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   found = VG_(lookupFM)( map_locks,
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          NULL, (Word*)&oldlock, (Word)ga );
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!found) {
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Lock* lock = mk_LockN(lkk, ga);
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lock->appeared_at = VG_(record_ExeContext)( tid, 0 );
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_LockN)(lock));
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( map_locks, (Word)ga, (Word)lock );
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(oldlock == NULL);
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return lock;
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(oldlock != NULL);
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_LockN)(oldlock));
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(oldlock->guestaddr == ga);
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return oldlock;
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Lock* map_locks_maybe_lookup ( Addr ga )
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  found;
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk = NULL;
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   found = VG_(lookupFM)( map_locks, NULL, (Word*)&lk, (Word)ga );
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(found  ?  lk != NULL  :  lk == NULL);
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return lk;
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_locks_delete ( Addr ga )
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr  ga2 = 0;
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk  = NULL;
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(delFromFM)( map_locks,
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   (Word*)&ga2, (Word*)&lk, (Word)ga );
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* delFromFM produces the val which is being deleted, if it is
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      found.  So assert it is non-null; that in effect asserts that we
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      are deleting a (ga, Lock) pair which actually exists. */
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk != NULL);
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(ga2 == ga);
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Sanity checking the data structures                      ---*/
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UWord stats__sanity_checks = 0;
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__sanity_check ( Char* who ); /* fwds */
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* REQUIRED INVARIANTS:
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread vs Segment/Lock/SecMaps
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for each t in Threads {
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Thread.lockset: each element is really a valid Lock
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Thread.lockset: each Lock in set is actually held by that thread
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for lk in Thread.lockset
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            lk == LockedBy(t)
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Thread.csegid is a valid SegmentID
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // and the associated Segment has .thr == t
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all thread Locksets are pairwise empty under intersection
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (that is, no lock is claimed to be held by more than one thread)
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      -- this is guaranteed if all locks in locksets point back to their
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      owner threads
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock vs Thread/Segment/SecMaps
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for each entry (gla, la) in map_locks
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gla == la->guest_addr
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for each lk in Locks {
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->tag is valid
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->guest_addr does not have shadow state NoAccess
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if lk == LockedBy(t), then t->lockset contains lk
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if lk == UnlockedBy(segid) then segid is valid SegmentID
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             and can be mapped to a valid Segment(seg)
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             and seg->thr->lockset does not contain lk
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if lk == UnlockedNew then (no lockset contains lk)
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         secmaps for lk has .mbHasLocks == True
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Segment vs Thread/Lock/SecMaps
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the Segment graph is a dag (no cycles)
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all of the Segment graph must be reachable from the segids
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mentioned in the Threads
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for seg in Segments {
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         seg->thr is a sane Thread
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SecMaps vs Segment/Thread/Lock
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for sm in SecMaps {
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sm properly aligned
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if any shadow word is ShR or ShM then .mbHasShared == True
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for each Excl(segid) state
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            map_segments_lookup maps to a sane Segment(seg)
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for each ShM/ShR(tsetid,lsetid) state
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            each lk in lset is a valid Lock
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            each thr in tset is a valid thread, which is non-dead
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff 'thr' holds 'lk' in some mode. */
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool thread_is_a_holder_of_Lock ( Thread* thr, Lock* lk )
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy)
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VG_(elemBag)( lk->heldBy, (Word)thr ) > 0;
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sanity check Threads, as far as possible */
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void threads__sanity_check ( Char* who )
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BAD(_str) do { how = (_str); goto bad; } while (0)
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char*     how = "no error";
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*   thr;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordSetID wsA, wsW;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord*    ls_words;
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word      ls_size, i;
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*     lk;
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (thr = admin_threads; thr; thr = thr->admin) {
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!HG_(is_sane_Thread)(thr)) BAD("1");
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      wsA = thr->locksetA;
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      wsW = thr->locksetW;
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // locks held in W mode are a subset of all locks held
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!HG_(isSubsetOf)( univ_lsets, wsW, wsA )) BAD("7");
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, wsA );
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < ls_size; i++) {
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk = (Lock*)ls_words[i];
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Thread.lockset: each element is really a valid Lock
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!HG_(is_sane_LockN)(lk)) BAD("2");
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Thread.lockset: each Lock in set is actually held by that
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // thread
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!thread_is_a_holder_of_Lock(thr,lk)) BAD("3");
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("threads__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(0);
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef BAD
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sanity check Locks, as far as possible */
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void locks__sanity_check ( Char* who )
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BAD(_str) do { how = (_str); goto bad; } while (0)
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char*     how = "no error";
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr      gla;
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*     lk;
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       i;
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // # entries in admin_locks == # entries in map_locks
854b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0, lk = admin_locks;  lk;  i++, lk = lk->admin_next)
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ;
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (i != VG_(sizeFM)(map_locks)) BAD("1");
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // for each entry (gla, lk) in map_locks
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //      gla == lk->guest_addr
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(initIterFM)( map_locks );
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (VG_(nextIterFM)( map_locks,
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (Word*)&gla, (Word*)&lk )) {
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->guestaddr != gla) BAD("2");
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(doneIterFM)( map_locks );
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // scan through admin_locks ...
866b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (lk = admin_locks; lk; lk = lk->admin_next) {
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // lock is sane.  Quite comprehensive, also checks that
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // referenced (holder) threads are sane.
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!HG_(is_sane_LockN)(lk)) BAD("3");
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // map_locks binds guest address back to this lock
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk != map_locks_maybe_lookup(lk->guestaddr)) BAD("4");
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // look at all threads mentioned as holders of this lock.  Ensure
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // this lock is mentioned in their locksets.
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->heldBy) {
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Thread* thr;
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Word    count;
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(initIterBag)( lk->heldBy );
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         while (VG_(nextIterBag)( lk->heldBy,
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  (Word*)&thr, &count )) {
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // HG_(is_sane_LockN) above ensures these
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(count >= 1);
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(HG_(is_sane_Thread)(thr));
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!HG_(elemWS)(univ_lsets, thr->locksetA, (Word)lk))
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               BAD("6");
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // also check the w-only lockset
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (lk->heldW
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && !HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               BAD("7");
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((!lk->heldW)
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               BAD("8");
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(doneIterBag)( lk->heldBy );
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* lock not held by anybody */
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (lk->heldW) BAD("9"); /* should be False if !heldBy */
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // since lk is unheld, then (no lockset contains lk)
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // hmm, this is really too expensive to check.  Hmm.
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("locks__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(0);
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef BAD
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void all_except_Locks__sanity_check ( Char* who ) {
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stats__sanity_checks++;
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("all_except_Locks__sanity_check(%s)\n", who);
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   threads__sanity_check(who);
914b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_track_lockorders))
915b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      laog__sanity_check(who);
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void all__sanity_check ( Char* who ) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all_except_Locks__sanity_check(who);
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   locks__sanity_check(who);
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Shadow value and address range handlers                  ---*/
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__pre_thread_acquires_lock ( Thread*, Lock* ); /* fwds */
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//static void laog__handle_lock_deletions    ( WordSetID ); /* fwds */
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Thread* get_current_Thread ( void ); /* fwds */
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__handle_one_lock_deletion ( Lock* lk ); /* fwds */
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Block-copy states (needed for implementing realloc()). */
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* FIXME this copies shadow memory; it doesn't apply the MSM to it.
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is that a problem? (hence 'scopy' rather than 'ccopy') */
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void shadow_mem_scopy_range ( Thread* thr,
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     Addr src, Addr dst, SizeT len )
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbthr);
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_copy_shadow_state( hbthr, src, dst, len );
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void shadow_mem_cread_range ( Thread* thr, Addr a, SizeT len )
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbthr);
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_N(hbthr, a, len);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void shadow_mem_cwrite_range ( Thread* thr, Addr a, SizeT len ) {
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbthr);
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_N(hbthr, a, len);
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void shadow_mem_make_New ( Thread* thr, Addr a, SizeT len )
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_srange_new( thr->hbthr, a, len );
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
963b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void shadow_mem_make_NoAccess_NoFX ( Thread* thr, Addr aIN, SizeT len )
964b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
965b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0 && len > 500)
966b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("make NoAccess_NoFX ( %#lx, %ld )\n", aIN, len );
967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // has no effect (NoFX)
968b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_srange_noaccess_NoFX( thr->hbthr, aIN, len );
969b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
970b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
971b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void shadow_mem_make_NoAccess_AHAE ( Thread* thr, Addr aIN, SizeT len )
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && len > 500)
974b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("make NoAccess_AHAE ( %#lx, %ld )\n", aIN, len );
975b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Actually Has An Effect (AHAE)
976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_srange_noaccess_AHAE( thr->hbthr, aIN, len );
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void shadow_mem_make_Untracked ( Thread* thr, Addr aIN, SizeT len )
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && len > 500)
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("make Untracked ( %#lx, %ld )\n", aIN, len );
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_srange_untrack( thr->hbthr, aIN, len );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Event handlers (evh__* functions)                        ---*/
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- plus helpers (evhH__* functions)                         ---*/
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------- Event handler helpers (evhH__* functions) ---------*/
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create a new segment for 'thr', making it depend (.prev) on its
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   existing segment, bind together the SegmentID and Segment, and
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return both of them.  Also update 'thr' so it references the new
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Segment. */
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz static
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz void evhH__start_new_segment_for_thread ( /*OUT*/SegmentID* new_segidP,
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz                                           /*OUT*/Segment** new_segP,
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz                                           Thread* thr )
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz {
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    Segment* cur_seg;
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    tl_assert(new_segP);
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    tl_assert(new_segidP);
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    tl_assert(HG_(is_sane_Thread)(thr));
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    cur_seg = map_segments_lookup( thr->csegid );
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    tl_assert(cur_seg);
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    tl_assert(cur_seg->thr == thr); /* all sane segs should point back
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz                                       at their owner thread. */
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    *new_segP = mk_Segment( thr, cur_seg, NULL/*other*/ );
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    *new_segidP = alloc_SegmentID();
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    map_segments_add( *new_segidP, *new_segP );
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz    thr->csegid = *new_segidP;
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//zz }
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The lock at 'lock_ga' has acquired a writer.  Make all necessary
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   updates, and also do all possible error checks. */
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evhH__post_thread_w_acquires_lock ( Thread* thr,
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         LockKind lkk, Addr lock_ga )
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk;
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Basically what we need to do is call lockN_acquire_writer.
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      However, that will barf if any 'invalid' lock states would
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      result.  Therefore check before calling.  Side effect is that
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      routine.
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Because this routine is only called after successful lock
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      acquisition, we should not be asked to move the lock into any
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      invalid states.  Requests to do so are bugs in libpthread, since
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that should have rejected any such requests. */
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Try to find the lock.  If we can't, then create a new one with
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kind 'lkk'. */
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_lookup_or_create(
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockN)(lk) );
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* check libhb level entities exist */
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr->hbthr);
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->hbso);
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy == NULL) {
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* the lock isn't held.  Simple. */
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!lk->heldW);
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lockN_acquire_writer( lk, thr );
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* acquire a dependency from the lock's VCs */
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto noerror;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So the lock is already held.  If held as a r-lock then
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libpthread must be buggy. */
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->heldBy);
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!lk->heldW) {
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "Bug in libpthread: write lock "
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "granted on rwlock which is currently rd-held");
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So the lock is held in w-mode.  If it's held by some other
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread, then libpthread must be buggy. */
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_(sizeUniqueBag)(lk->heldBy) == 1); /* from precondition */
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (thr != (Thread*)VG_(anyElementOfBag)(lk->heldBy)) {
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "Bug in libpthread: write lock "
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "granted on mutex/rwlock which is currently "
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "wr-held by a different thread");
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So the lock is already held in w-mode by 'thr'.  That means this
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is an attempt to lock it recursively, which is only allowable
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for LK_mbRec kinded locks.  Since this routine is called only
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      once the lock has been acquired, this must also be a libpthread
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bug. */
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->kind != LK_mbRec) {
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "Bug in libpthread: recursive write lock "
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "granted on mutex/wrlock which does not "
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "support recursion");
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So we are recursively re-locking a lock we already w-hold. */
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lockN_acquire_writer( lk, thr );
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* acquire a dependency from the lock's VC.  Probably pointless,
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      but also harmless. */
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto noerror;
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  noerror:
1100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_track_lockorders)) {
1101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* check lock order acquisition graph, and update.  This has to
1102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         happen before the lock is added to the thread's locksetA/W. */
1103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      laog__pre_thread_acquires_lock( thr, lk );
1104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* update the thread's held-locks set */
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr->locksetW = HG_(addToWS)( univ_lsets, thr->locksetW, (Word)lk );
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* fall through */
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  error:
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The lock at 'lock_ga' has acquired a reader.  Make all necessary
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   updates, and also do all possible error checks. */
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evhH__post_thread_r_acquires_lock ( Thread* thr,
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         LockKind lkk, Addr lock_ga )
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk;
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Basically what we need to do is call lockN_acquire_reader.
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      However, that will barf if any 'invalid' lock states would
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      result.  Therefore check before calling.  Side effect is that
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      routine.
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Because this routine is only called after successful lock
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      acquisition, we should not be asked to move the lock into any
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      invalid states.  Requests to do so are bugs in libpthread, since
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that should have rejected any such requests. */
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Try to find the lock.  If we can't, then create a new one with
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kind 'lkk'.  Only a reader-writer lock can be read-locked,
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hence the first assertion. */
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lkk == LK_rdwr);
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_lookup_or_create(
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockN)(lk) );
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* check libhb level entities exist */
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr->hbthr);
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->hbso);
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldBy == NULL) {
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* the lock isn't held.  Simple. */
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!lk->heldW);
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lockN_acquire_reader( lk, thr );
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* acquire a dependency from the lock's VC */
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto noerror;
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So the lock is already held.  If held as a w-lock then
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libpthread must be buggy. */
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->heldBy);
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk->heldW) {
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr, "Bug in libpthread: read lock "
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "granted on rwlock which is "
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "currently wr-held");
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Easy enough.  In short anybody can get a read-lock on a rwlock
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      provided it is either unlocked or already in rd-held. */
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lockN_acquire_reader( lk, thr );
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* acquire a dependency from the lock's VC.  Probably pointless,
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      but also harmless. */
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto noerror;
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  noerror:
1175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_track_lockorders)) {
1176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* check lock order acquisition graph, and update.  This has to
1177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         happen before the lock is added to the thread's locksetA/W. */
1178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      laog__pre_thread_acquires_lock( thr, lk );
1179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* update the thread's held-locks set */
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* but don't update thr->locksetW, since lk is only rd-held */
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* fall through */
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  error:
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lk));
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The lock at 'lock_ga' is just about to be unlocked.  Make all
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   necessary updates, and also do all possible error checks. */
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evhH__pre_thread_releases_lock ( Thread* thr,
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      Addr lock_ga, Bool isRDWR )
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lock;
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word  n;
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  was_heldW;
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This routine is called prior to a lock release, before
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libpthread has had a chance to validate the call.  Hence we need
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to detect and reject any attempts to move the lock into an
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      invalid state.  Such attempts are bugs in the client.
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      isRDWR is True if we know from the wrapper context that lock_ga
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should refer to a reader-writer lock, and is False if [ditto]
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lock_ga should refer to a standard mutex. */
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lock = map_locks_maybe_lookup( lock_ga );
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!lock) {
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We know nothing about a lock at 'lock_ga'.  Nevertheless
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the client is trying to unlock it.  So complain, then ignore
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the attempt. */
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_UnlockBogus)( thr, lock_ga );
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lock->guestaddr == lock_ga);
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lock));
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRDWR && lock->kind != LK_rdwr) {
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr, "pthread_rwlock_unlock with a "
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "pthread_mutex_t* argument " );
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((!isRDWR) && lock->kind == LK_rdwr) {
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr, "pthread_mutex_unlock with a "
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "pthread_rwlock_t* argument " );
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!lock->heldBy) {
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The lock is not held.  This indicates a serious bug in the
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         client. */
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!lock->heldW);
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_UnlockUnlocked)( thr, lock );
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* test just above dominates */
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lock->heldBy);
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   was_heldW = lock->heldW;
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The lock is held.  Is this thread one of the holders?  If not,
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      report a bug in the client. */
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = VG_(elemBag)( lock->heldBy, (Word)thr );
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(n >= 0);
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n == 0) {
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We are not a current holder of the lock.  This is a bug in
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the guest, and (per POSIX pthread rules) the unlock
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         attempt will fail.  So just complain and do nothing
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else. */
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* realOwner = (Thread*)VG_(anyElementOfBag)( lock->heldBy );
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_Thread)(realOwner));
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(realOwner != thr);
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_UnlockForeign)( thr, realOwner, lock );
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto error;
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ok, we hold the lock 'n' times. */
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(n >= 1);
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lockN_release( lock, thr );
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n--;
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(n >= 0);
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n > 0) {
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lock->heldBy);
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(n == VG_(elemBag)( lock->heldBy, (Word)thr ));
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We still hold the lock.  So either it's a recursive lock
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         or a rwlock which is currently r-held. */
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lock->kind == LK_mbRec
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                || (lock->kind == LK_rdwr && !lock->heldW));
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lock->heldW)
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* n is zero.  This means we don't hold the lock any more.  But
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if it's a rwlock held in r-mode, someone else could still
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         hold it.  Just do whatever sanity checks we can. */
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lock->kind == LK_rdwr && lock->heldBy) {
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's a rwlock.  We no longer hold it but we used to;
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nevertheless it still appears to be held by someone else.
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            The implication is that, prior to this release, it must
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            have been shared by us and and whoever else is holding it;
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which in turn implies it must be r-held, since a lock
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            can't be w-held by more than one thread. */
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The lock is now R-held by somebody else: */
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lock->heldW == False);
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Normal case.  It's either not a rwlock, or it's a rwlock
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that we used to hold in w-mode (which is pretty much the
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            same thing as a non-rwlock.)  Since this transaction is
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            atomic (V does not allow multiple threads to run
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            simultaneously), it must mean the lock is now not held by
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            anybody.  Hence assert for it. */
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The lock is now not held by anybody: */
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(!lock->heldBy);
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lock->heldW == False);
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //if (lock->heldBy) {
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   tl_assert(0 == VG_(elemBag)( lock->heldBy, (Word)thr ));
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //}
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update this thread's lockset accordingly. */
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr->locksetA
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lock );
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr->locksetW
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lock );
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* push our VC into the lock */
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(thr->hbthr);
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(lock->hbso);
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If the lock was previously W-held, then we want to do a
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         strong send, and if previously R-held, then a weak send. */
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_send( thr->hbthr, lock->hbso, was_heldW );
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* fall through */
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  error:
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_LockN)(lock));
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------- */
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------- Event handlers proper (evh__* functions) -------- */
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------- */
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* What is the Thread* for the currently running thread?  This is
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   absolutely performance critical.  We receive notifications from the
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   core for client code starts/stops, and cache the looked-up result
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in 'current_Thread'.  Hence, for the vast majority of requests,
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   finding the current thread reduces to a read of a global variable,
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   provided get_current_Thread_in_C_C is inlined.
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Outside of client code, current_Thread is NULL, and presumably
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   any uses of it will cause a segfault.  Hence:
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - for uses definitely within client code, use
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     get_current_Thread_in_C_C.
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - for all other uses, use get_current_Thread.
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Thread *current_Thread      = NULL,
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              *current_Thread_prev = NULL;
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__start_client_code ( ThreadId tid, ULong nDisp ) {
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("start %d %llu\n", (Int)tid, nDisp);
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(current_Thread == NULL);
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   current_Thread = map_threads_lookup( tid );
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(current_Thread != NULL);
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (current_Thread != current_Thread_prev) {
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_Thr_resumes( current_Thread->hbthr );
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      current_Thread_prev = current_Thread;
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__stop_client_code ( ThreadId tid, ULong nDisp ) {
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)(" stop %d %llu\n", (Int)tid, nDisp);
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(current_Thread != NULL);
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   current_Thread = NULL;
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_maybe_GC();
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Thread* get_current_Thread_in_C_C ( void ) {
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return current_Thread;
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Thread* get_current_Thread ( void ) {
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId coretid;
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr;
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = get_current_Thread_in_C_C();
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (LIKELY(thr))
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return thr;
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* evidently not in client code.  Do it the slow way. */
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   coretid = VG_(get_running_tid)();
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FIXME: get rid of the following kludge.  It exists because
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evh__new_mem is called during initialisation (as notification
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of initial memory layout) and VG_(get_running_tid)() returns
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_INVALID_THREADID at that point. */
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (coretid == VG_INVALID_THREADID)
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      coretid = 1; /* KLUDGE */
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_lookup( coretid );
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return thr;
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__new_mem ( Addr a, SizeT len ) {
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_make_New( get_current_Thread(), a, len );
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__new_mem-post");
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__new_mem_stack ( Addr a, SizeT len ) {
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__new_mem_stack(%p, %lu)\n", (void*)a, len );
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_make_New( get_current_Thread(),
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        -VG_STACK_REDZONE_SZB + a, len );
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__new_mem_stack-post");
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__new_mem_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__new_mem_w_tid(%p, %lu)\n", (void*)a, len );
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_make_New( get_current_Thread(), a, len );
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__new_mem_w_tid-post");
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__new_mem_w_perms ( Addr a, SizeT len,
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Bool rr, Bool ww, Bool xx, ULong di_handle ) {
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (rr || ww || xx)
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shadow_mem_make_New( get_current_Thread(), a, len );
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__new_mem_w_perms-post");
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__set_perms ( Addr a, SizeT len,
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool rr, Bool ww, Bool xx ) {
1433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // This handles mprotect requests.  If the memory is being put
1434b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // into no-R no-W state, paint it as NoAccess, for the reasons
1435b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // documented at evh__die_mem_munmap().
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("evh__set_perms(%p, %lu, r=%d w=%d x=%d)\n",
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Hmm.  What should we do here, that actually makes any sense?
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Let's say: if neither readable nor writable, then declare it
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NoAccess, else leave it alone. */
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(rr || ww))
1443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__set_perms-post");
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__die_mem ( Addr a, SizeT len ) {
1450b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Urr, libhb ignores this.
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
1453b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   shadow_mem_make_NoAccess_NoFX( get_current_Thread(), a, len );
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__die_mem-post");
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid evh__die_mem_munmap ( Addr a, SizeT len ) {
1460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // It's important that libhb doesn't ignore this.  If, as is likely,
1461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // the client is subject to address space layout randomization,
1462b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // then unmapped areas may never get remapped over, even in long
1463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // runs.  If we just ignore them we wind up with large resource
1464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // (VTS) leaks in libhb.  So force them to NoAccess, so that all
1465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // VTS references in the affected area are dropped.  Marking memory
1466b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // as NoAccess is expensive, but we assume that munmap is sufficiently
1467b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // rare that the space gains of doing this are worth the costs.
1468b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (SHOW_EVENTS >= 2)
1469b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("evh__die_mem_munmap(%p, %lu)\n", (void*)a, len );
1470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
1472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1473b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__untrack_mem ( Addr a, SizeT len ) {
1475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Libhb doesn't ignore this.
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__untrack_mem(%p, %lu)\n", (void*)a, len );
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_make_Untracked( get_current_Thread(), a, len );
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__untrack_mem-post");
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__copy_mem ( Addr src, Addr dst, SizeT len ) {
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2)
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__copy_mem(%p, %p, %lu)\n", (void*)src, (void*)dst, len );
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_scopy_range( get_current_Thread(), src, dst, len );
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__copy_mem-post");
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__pre_thread_ll_create ( ThreadId parent, ThreadId child )
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__pre_thread_ll_create(p=%d, c=%d)\n",
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)parent, (Int)child );
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (parent != VG_INVALID_THREADID) {
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* thr_p;
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* thr_c;
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thr*    hbthr_p;
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thr*    hbthr_c;
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_ThreadId)(parent));
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(HG_(is_sane_ThreadId)(child));
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(parent != child);
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr_p = map_threads_maybe_lookup( parent );
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr_c = map_threads_maybe_lookup( child );
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(thr_p != NULL);
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(thr_c == NULL);
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hbthr_p = thr_p->hbthr;
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(hbthr_p != NULL);
1517b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert( libhb_get_Thr_hgthread(hbthr_p) == thr_p );
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hbthr_c = libhb_create ( hbthr_p );
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Create a new thread record for the child. */
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a Thread for the new thread ... */
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr_c = mk_Thread( hbthr_c );
1524b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert( libhb_get_Thr_hgthread(hbthr_c) == NULL );
1525b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      libhb_set_Thr_hgthread(hbthr_c, thr_c);
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* and bind it in the thread-map table */
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_threads[child] = thr_c;
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(thr_c->coretid == VG_INVALID_THREADID);
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr_c->coretid = child;
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Record where the parent is so we can later refer to this in
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         error messages.
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         On amd64-linux, this entails a nasty glibc-2.5 specific hack.
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         The stack snapshot is taken immediately after the parent has
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         returned from its sys_clone call.  Unfortunately there is no
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unwind info for the insn following "syscall" - reading the
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         glibc sources confirms this.  So we ask for a snapshot to be
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         taken as if RIP was 3 bytes earlier, in a place where there
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is unwind info.  Sigh.
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      { Word first_ip_delta = 0;
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#       if defined(VGP_amd64_linux)
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        first_ip_delta = -3;
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#       endif
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_THREADS)
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_thread_create-post");
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__pre_thread_ll_exit ( ThreadId quit_tid )
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     nHeld;
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr_q;
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)quit_tid );
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* quit_tid has disappeared without joining to any other thread.
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Therefore there is no synchronisation event associated with its
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      exit and so we have to pretty much treat it as if it was still
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      alive but mysteriously making no progress.  That is because, if
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      we don't know when it really exited, then we can never say there
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is a point in time when we're sure the thread really has
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      finished, and so we need to consider the possibility that it
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lingers indefinitely and continues to interact with other
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      threads. */
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* However, it might have rendezvous'd with a thread that called
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pthread_join with this one as arg, prior to this point (that's
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      how NPTL works).  In which case there has already been a prior
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sync event.  So in any case, just let the thread exit.  On NPTL,
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all thread exits go through here. */
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_ThreadId)(quit_tid));
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr_q = map_threads_maybe_lookup( quit_tid );
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_q != NULL);
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Complain if this thread holds any locks. */
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nHeld = HG_(cardinalityWS)( univ_lsets, thr_q->locksetA );
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(nHeld >= 0);
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nHeld > 0) {
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar buf[80];
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nHeld, nHeld > 1 ? "s" : "");
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr_q, buf );
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Not much to do here:
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - tell libhb the thread is gone
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - clear the map_threads entry, in order that the Valgrind core
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        can re-use it. */
1596f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* Cleanup actions (next 5 lines) copied in evh__atfork_child; keep
1597f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      in sync. */
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_q->hbthr);
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_async_exit(thr_q->hbthr);
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_q->coretid == quit_tid);
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr_q->coretid = VG_INVALID_THREADID;
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_threads_delete( quit_tid );
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_THREADS)
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_thread_ll_exit-post");
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1608f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/* This is called immediately after fork, for the child only.  'tid'
1609f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   is the only surviving thread (as per POSIX rules on fork() in
1610f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   threaded programs), so we have to clean up map_threads to remove
1611f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   entries for any other threads. */
1612f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Rootstatic
1613f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Rootvoid evh__atfork_child ( ThreadId tid )
1614f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root{
1615f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   UInt    i;
1616f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   Thread* thr;
1617f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* Slot 0 should never be used. */
1618f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   thr = map_threads_maybe_lookup( 0/*INVALID*/ );
1619f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   tl_assert(!thr);
1620f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* Clean up all other slots except 'tid'. */
1621f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   for (i = 1; i < VG_N_THREADS; i++) {
1622f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (i == tid)
1623f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         continue;
1624f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      thr = map_threads_maybe_lookup(i);
1625f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (!thr)
1626f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         continue;
1627f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Cleanup actions (next 5 lines) copied from end of
1628f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         evh__pre_thread_ll_exit; keep in sync. */
1629f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      tl_assert(thr->hbthr);
1630f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      libhb_async_exit(thr->hbthr);
1631f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      tl_assert(thr->coretid == i);
1632f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      thr->coretid = VG_INVALID_THREADID;
1633f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      map_threads_delete(i);
1634f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
1635f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root}
1636f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_JOIN_POST ( ThreadId stay_tid, Thread* quit_thr )
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr_s;
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr_q;
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr_s;
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr_q;
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*      so;
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__post_thread_join(stayer=%d, quitter=%p)\n",
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)stay_tid, quit_thr );
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_ThreadId)(stay_tid));
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr_s = map_threads_maybe_lookup( stay_tid );
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr_q = quit_thr;
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_s != NULL);
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_q != NULL);
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr_s != thr_q);
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hbthr_s = thr_s->hbthr;
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hbthr_q = thr_q->hbthr;
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbthr_s != hbthr_q);
1662b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert( libhb_get_Thr_hgthread(hbthr_s) == thr_s );
1663b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert( libhb_get_Thr_hgthread(hbthr_q) == thr_q );
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Allocate a temporary synchronisation object and use it to send
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      an imaginary message from the quitter to the stayer, the purpose
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      being to generate a dependence from the quitter to the
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stayer. */
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so = libhb_so_alloc();
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(so);
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Send last arg of _so_send as False, since the sending thread
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      doesn't actually exist any more, so we don't want _so_send to
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      try taking stack snapshots of it. */
1674b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_so_send(hbthr_q, so, True/*strong_send*//*?!? wrt comment above*/);
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_recv(hbthr_s, so, True/*strong_recv*/);
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_dealloc(so);
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1678b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Tell libhb that the quitter has been reaped.  Note that we might
1679b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      have to be cleverer about this, to exclude 2nd and subsequent
1680b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      notifications for the same hbthr_q, in the case where the app is
1681b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      buggy (calls pthread_join twice or more on the same thread) AND
1682b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      where libpthread is also buggy and doesn't return ESRCH on
1683b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      subsequent calls.  (If libpthread isn't thusly buggy, then the
1684b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      wrapper for pthread_join in hg_intercepts.c will stop us getting
1685b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      notified here multiple times for the same joinee.)  See also
1686b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      comments in helgrind/tests/jointwice.c. */
1687b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_joinedwith_done(hbthr_q);
1688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* evh__pre_thread_ll_exit issues an error message if the exiting
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread holds any locks.  No need to check here. */
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This holds because, at least when using NPTL as the thread
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      library, we should be notified the low level thread exit before
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      we hear of any join event on it.  The low level exit
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      notification feeds through into evh__pre_thread_ll_exit,
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      which should clear the map_threads entry for it.  Hence we
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expect there to be no map_threads entry at this point. */
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              == VG_INVALID_THREADID);
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_THREADS)
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__post_thread_join-post");
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__pre_mem_read ( CorePart part, ThreadId tid, Char* s,
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr a, SizeT size) {
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 2
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || (SHOW_EVENTS >= 1 && size != 1))
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, s, (void*)a, size );
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_cread_range( map_threads_lookup(tid), a, size);
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_mem_read-post");
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__pre_mem_read_asciiz ( CorePart part, ThreadId tid,
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                Char* s, Addr a ) {
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__pre_mem_asciiz(ctid=%d, \"%s\", %p)\n",
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, s, (void*)a );
1724f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   // Don't segfault if the string starts in an obviously stupid
1725f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   // place.  Actually we should check the whole string, not just
1726f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   // the start address, but that's too much trouble.  At least
1727f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   // checking the first byte is better than nothing.  See #255009.
1728f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (!VG_(am_is_valid_for_client) (a, 1, VKI_PROT_READ))
1729f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      return;
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   len = VG_(strlen)( (Char*) a );
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_cread_range( map_threads_lookup(tid), a, len+1 );
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_mem_read_asciiz-post");
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__pre_mem_write ( CorePart part, ThreadId tid, Char* s,
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Addr a, SizeT size ) {
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, s, (void*)a, size );
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shadow_mem_cwrite_range( map_threads_lookup(tid), a, size);
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_mem_write-post");
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__new_mem_heap ( Addr a, SizeT len, Bool is_inited ) {
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__new_mem_heap(%p, %lu, inited=%d)\n",
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)a, len, (Int)is_inited );
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: this is kinda stupid
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_inited) {
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shadow_mem_make_New(get_current_Thread(), a, len);
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shadow_mem_make_New(get_current_Thread(), a, len);
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_mem_read-post");
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__die_mem_heap ( Addr a, SizeT len ) {
1764b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Thread* thr;
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
1767b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   thr = get_current_Thread();
1768b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(thr);
1769b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_free_is_write)) {
1770b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Treat frees as if the memory was written immediately prior to
1771b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         the free.  This shakes out more races, specifically, cases
1772b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         where memory is referenced by one thread, and freed by
1773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         another, and there's no observable synchronisation event to
1774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         guarantee that the reference happens before the free. */
1775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      shadow_mem_cwrite_range(thr, a, len);
1776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1777b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   shadow_mem_make_NoAccess_NoFX( thr, a, len );
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__pre_mem_read-post");
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Event handlers called from generated code --- */
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cread_1(Addr a) {
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_1(hbthr, a);
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cread_2(Addr a) {
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_2(hbthr, a);
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cread_4(Addr a) {
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_4(hbthr, a);
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cread_8(Addr a) {
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_8(hbthr, a);
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2)
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cread_N(Addr a, SizeT size) {
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CREAD_N(hbthr, a, size);
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cwrite_1(Addr a) {
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_1(hbthr, a);
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cwrite_2(Addr a) {
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_2(hbthr, a);
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cwrite_4(Addr a) {
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_4(hbthr, a);
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cwrite_8(Addr a) {
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_8(hbthr, a);
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2)
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__mem_help_cwrite_N(Addr a, SizeT size) {
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*  thr = get_current_Thread_in_C_C();
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*     hbthr = thr->hbthr;
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LIBHB_CWRITE_N(hbthr, a, size);
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- events to do with mutexes -------------- */
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* EXPOSITION only: by intercepting lock init events we can show the
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   user where the lock was initialised, rather than only being able to
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   show where it was first locked.  Intercepting lock initialisations
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is not necessary for the basic operation of the race checker. */
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_MUTEX_INIT_POST( ThreadId tid,
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      void* mutex, Word mbRec )
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_MUTEX_INIT_POST(ctid=%d, mbRec=%ld, %p)\n",
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, mbRec, (void*)mutex );
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(mbRec == 0 || mbRec == 1);
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               (Addr)mutex, tid );
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_LOCKS)
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__hg_PTHREAD_MUTEX_INIT_POST");
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_MUTEX_DESTROY_PRE( ThreadId tid, void* mutex )
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_MUTEX_DESTROY_PRE(ctid=%d, %p)\n",
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)mutex );
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* cannot fail - Thread* must already exist */
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)mutex );
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk == NULL || (lk->kind != LK_nonRec && lk->kind != LK_mbRec)) {
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_mutex_destroy with invalid argument" );
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk) {
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockN)(lk) );
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( lk->guestaddr == (Addr)mutex );
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->heldBy) {
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Basically act like we unlocked the lock */
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)(
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, "pthread_mutex_destroy of a locked mutex" );
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* remove lock from locksets of all owning threads */
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         remove_Lock_from_locksets_of_all_owning_Threads( lk );
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(deleteBag)( lk->heldBy );
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldBy = NULL;
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldW = False;
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->acquired_at = NULL;
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( !lk->heldBy );
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockN)(lk) );
1913b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1914b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (HG_(clo_track_lockorders))
1915b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         laog__handle_one_lock_deletion(lk);
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_locks_delete( lk->guestaddr );
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      del_LockN( lk );
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_LOCKS)
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__hg_PTHREAD_MUTEX_DESTROY_PRE");
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_MUTEX_LOCK_PRE ( ThreadId tid,
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             void* mutex, Word isTryLock )
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Just check the mutex is sane; nothing else to do. */
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'mutex' may be invalid - not checked by wrapper
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_MUTEX_LOCK_PRE(ctid=%d, mutex=%p)\n",
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)mutex );
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isTryLock == 0 || isTryLock == 1);
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)mutex );
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk && (lk->kind == LK_rdwr)) {
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr, "pthread_mutex_lock with a "
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "pthread_rwlock_t* argument " );
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( lk
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && isTryLock == 0
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (lk->kind == LK_nonRec || lk->kind == LK_rdwr)
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && lk->heldBy
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && lk->heldW
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && VG_(elemBag)( lk->heldBy, (Word)thr ) > 0 ) {
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* uh, it's a non-recursive lock and we already w-hold it, and
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this is a real lock operation (not a speculative "tryLock"
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kind of thing).  Duh.  Deadlock coming up; but at least
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         produce an error message. */
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* errstr = "Attempt to re-lock a "
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "non-recursive lock I already hold";
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* auxstr = "Lock was previously acquired";
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->acquired_at) {
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc_w_aux)( thr, errstr, auxstr, lk->acquired_at );
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)( thr, errstr );
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_MUTEX_LOCK_POST ( ThreadId tid, void* mutex )
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only called if the real library call succeeded - so mutex is sane
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_MUTEX_LOCK_POST(ctid=%d, mutex=%p)\n",
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)mutex );
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evhH__post_thread_w_acquires_lock(
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr,
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LK_mbRec, /* if not known, create new lock with this LockKind */
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Addr)mutex
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_MUTEX_UNLOCK_PRE ( ThreadId tid, void* mutex )
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'mutex' may be invalid - not checked by wrapper
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ctid=%d, mutex=%p)\n",
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)mutex );
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evhH__pre_thread_releases_lock( thr, (Addr)mutex, False/*!isRDWR*/ );
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_MUTEX_UNLOCK_POST ( ThreadId tid, void* mutex )
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only called if the real library call succeeded - so mutex is sane
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_MUTEX_UNLOCK_POST(ctid=%d, mutex=%p)\n",
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)mutex );
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // anything we should do here?
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- events to do with spinlocks ------------ */
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All a bit of a kludge.  Pretend we're really dealing with ordinary
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pthread_mutex_t's instead, for the most part. */
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( ThreadId tid,
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                     void* slock )
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In glibc's kludgey world, we're either initialising or unlocking
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it.  Since this is the pre-routine, if it is locked, unlock it
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and take a dependence edge.  Otherwise, do nothing. */
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE"
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(ctid=%d, slock=%p)\n",
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)slock );
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* cannot fail - Thread* must already exist */;
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)slock );
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk && lk->heldBy) {
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* it's held.  So do the normal pre-unlock actions, as copied
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         from evh__HG_PTHREAD_MUTEX_UNLOCK_PRE.  This stupidly
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         duplicates the map_locks_maybe_lookup. */
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evhH__pre_thread_releases_lock( thr, (Addr)slock,
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           False/*!isRDWR*/ );
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( ThreadId tid,
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                      void* slock )
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk;
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* More kludgery.  If the lock has never been seen before, do
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      actions as per evh__HG_PTHREAD_MUTEX_INIT_POST.  Else do
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nothing. */
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_POST"
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(ctid=%d, slock=%p)\n",
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)slock );
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)slock );
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!lk) {
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_locks_lookup_or_create( LK_nonRec, (Addr)slock, tid );
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_SPIN_LOCK_PRE( ThreadId tid,
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* slock, Word isTryLock )
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, slock, isTryLock );
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_SPIN_LOCK_POST( ThreadId tid,
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            void* slock )
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, slock );
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_SPIN_DESTROY_PRE( ThreadId tid,
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              void* slock )
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, slock );
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------------------------------------- */
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- events to do with CVs --------------- */
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------------------------------------- */
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A mapping from CV to (the SO associated with it, plus some
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxiliary data for error checking).  When the CV is
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signalled/broadcasted upon, we do a 'send' into the SO, and when a
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wait on it completes, we do a 'recv' from the SO.  This is believed
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to give the correct happens-before events arising from CV
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signallings/broadcasts.
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* .so is the SO for this CV.
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   .mx_ga is the associated mutex, when .nWaiters > 0
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   POSIX says effectively that the first pthread_cond_{timed}wait call
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   causes a dynamic binding between the CV and the mutex, and that
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lasts until such time as the waiter count falls to zero.  Hence
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   need to keep track of the number of waiters in order to do
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   consistency tracking. */
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SO*   so;       /* libhb-allocated SO */
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void* mx_ga;    /* addr of associated mutex, if any */
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord nWaiters; /* # threads waiting on the CV */
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CVInfo;
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* pthread_cond_t* -> CVInfo* */
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_cond_to_CVInfo = NULL;
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_cond_to_CVInfo_INIT ( void ) {
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(map_cond_to_CVInfo == NULL)) {
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_cond_to_CVInfo = VG_(newFM)( HG_(zalloc),
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       "hg.mctCI.1", HG_(free), NULL );
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_cond_to_CVInfo != NULL);
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic CVInfo* map_cond_to_CVInfo_lookup_or_alloc ( void* cond ) {
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord key, val;
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_cond_to_CVInfo_INIT();
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(key == (UWord)cond);
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return (CVInfo*)val;
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SO*     so  = libhb_so_alloc();
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      CVInfo* cvi = HG_(zalloc)("hg.mctCloa.1", sizeof(CVInfo));
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cvi->so     = so;
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cvi->mx_ga  = 0;
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( map_cond_to_CVInfo, (UWord)cond, (UWord)cvi );
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cvi;
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_cond_to_CVInfo_delete ( void* cond ) {
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord keyW, valW;
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_cond_to_CVInfo_INIT();
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(delFromFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond )) {
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      CVInfo* cvi = (CVInfo*)valW;
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (UWord)cond);
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(cvi);
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(cvi->so);
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_dealloc(cvi->so);
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cvi->mx_ga = 0;
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(free)(cvi);
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_COND_SIGNAL_PRE ( ThreadId tid, void* cond )
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 'tid' has signalled on 'cond'.  As per the comment above, bind
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond to a SO if it is not already so bound, and 'send' on the
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SO.  This is later used by other thread(s) which successfully
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      exit from a pthread_cond_wait on the same cv; then they 'recv'
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from the SO, thereby acquiring a dependency on this signalling
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      event. */
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*   thr;
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CVInfo*   cvi;
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //Lock*     lk;
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_COND_SIGNAL_PRE(ctid=%d, cond=%p)\n",
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)cond );
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi);
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi->so);
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: mutex is bogus
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: mutex is not locked
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Hmm.  POSIX doesn't actually say that it's an error to call
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // pthread_cond_signal with the associated mutex being unlocked.
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Although it does say that it should be "if consistent scheduling
2184b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // is desired."  For that reason, print "dubious" if the lock isn't
2185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // held by any thread.  Skip the "dubious" if it is held by some
2186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // other thread; that sounds straight-out wrong.
2187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //
2188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Anybody who writes code that signals on a CV without holding
2189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // the associated MX needs to be shipped off to a lunatic asylum
2190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // ASAP, even though POSIX doesn't actually declare such behaviour
2191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // illegal -- it makes code extremely difficult to understand/
2192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // reason about.  In particular it puts the signalling thread in
2193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // a situation where it is racing against the released waiter
2194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // as soon as the signalling is done, and so there needs to be
2195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // some auxiliary synchronisation mechanism in the program that
2196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // makes this safe -- or the race(s) need to be harmless, or
2197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // probably nonexistent.
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
2199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (1) {
2200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Lock* lk = NULL;
2201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (cvi->mx_ga != 0) {
2202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         lk = map_locks_maybe_lookup( (Addr)cvi->mx_ga );
2203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
2204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* note: lk could be NULL.  Be careful. */
2205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (lk) {
2206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (lk->kind == LK_rdwr) {
2207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            HG_(record_error_Misc)(thr,
2208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "pthread_cond_{signal,broadcast}: associated lock is a rwlock");
2209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
2210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (lk->heldBy == NULL) {
2211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            HG_(record_error_Misc)(thr,
2212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "pthread_cond_{signal,broadcast}: dubious: "
2213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "associated lock is not held by any thread");
2214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
2215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (lk->heldBy != NULL && 0 == VG_(elemBag)(lk->heldBy, (Word)thr)) {
2216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            HG_(record_error_Misc)(thr,
2217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "pthread_cond_{signal,broadcast}: "
2218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "associated lock is not held by calling thread");
2219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
2220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else {
2221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* Couldn't even find the damn thing. */
2222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // But actually .. that's not necessarily an error.  We don't
2223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // know the (CV,MX) binding until a pthread_cond_wait or bcast
2224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // shows us what it is, and if that may not have happened yet.
2225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // So just keep quiet in this circumstance.
2226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         //HG_(record_error_Misc)( thr,
2227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         //   "pthread_cond_{signal,broadcast}: "
2228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         //   "no or invalid mutex associated with cond");
2229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
2230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_send( thr->hbthr, cvi->so, True/*strong_send*/ );
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* returns True if it reckons 'mutex' is valid and held by this
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread, else False */
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool evh__HG_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            void* cond, void* mutex )
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    lk_valid = True;
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CVInfo* cvi;
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_COND_WAIT_PRE"
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(ctid=%d, cond=%p, mutex=%p)\n",
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)cond, (void*)mutex );
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)mutex );
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check for stupid mutex arguments.  There are various ways to be
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a bozo.  Only complain once, though, even if more than one thing
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is wrong. */
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk == NULL) {
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lk_valid = False;
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr,
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "pthread_cond_{timed}wait called with invalid mutex" );
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockN)(lk) );
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->kind == LK_rdwr) {
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk_valid = False;
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)(
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, "pthread_cond_{timed}wait called with mutex "
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 "of type pthread_rwlock_t*" );
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (lk->heldBy == NULL) {
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk_valid = False;
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)(
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, "pthread_cond_{timed}wait called with un-held mutex");
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->heldBy != NULL
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && VG_(elemBag)( lk->heldBy, (Word)thr ) == 0) {
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk_valid = False;
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)(
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, "pthread_cond_{timed}wait called with mutex "
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 "held by a different thread" );
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: cond is also associated with a different mutex
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cvi = map_cond_to_CVInfo_lookup_or_alloc(cond);
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi);
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi->so);
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cvi->nWaiters == 0) {
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* form initial (CV,MX) binding */
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cvi->mx_ga = mutex;
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else /* check existing (CV,MX) binding */
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cvi->mx_ga != mutex) {
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_cond_{timed}wait: cond is associated "
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "with a different mutex");
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cvi->nWaiters++;
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return lk_valid;
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_COND_WAIT_POST ( ThreadId tid,
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             void* cond, void* mutex )
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* A pthread_cond_wait(cond, mutex) completed successfully.  Find
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the SO for this cond, and 'recv' from it so as to acquire a
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dependency edge back to the signaller/broadcaster. */
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CVInfo* cvi;
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_COND_WAIT_POST"
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(ctid=%d, cond=%p, mutex=%p)\n",
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)cond, (void*)mutex );
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: cond is also associated with a different mutex
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi);
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi->so);
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(cvi->nWaiters > 0);
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!libhb_so_everSent(cvi->so)) {
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Hmm.  How can a wait on 'cond' succeed if nobody signalled
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it?  If this happened it would surely be a bug in the threads
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         library.  Or one of those fabled "spurious wakeups". */
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)( thr, "Bug in libpthread: pthread_cond_wait "
2333b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   "succeeded"
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   " without prior pthread_cond_post");
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* anyway, acquire a dependency on it. */
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_recv( thr->hbthr, cvi->so, True/*strong_recv*/ );
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cvi->nWaiters--;
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_COND_DESTROY_PRE ( ThreadId tid,
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               void* cond )
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with destroy events.  The only purpose is to free storage
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      associated with the CV, so as to avoid any possible resource
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      leaks. */
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_COND_DESTROY_PRE"
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(ctid=%d, cond=%p)\n",
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)cond );
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_cond_to_CVInfo_delete( cond );
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- events to do with rwlocks -------------- */
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* EXPOSITION only */
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_RWLOCK_INIT_POST( ThreadId tid, void* rwl )
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)rwl );
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_LOCKS)
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__hg_PTHREAD_RWLOCK_INIT_POST");
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( ThreadId tid, void* rwl )
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE(ctid=%d, %p)\n",
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)rwl );
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* cannot fail - Thread* must already exist */
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)rwl );
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk == NULL || lk->kind != LK_rdwr) {
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_rwlock_destroy with invalid argument" );
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk) {
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockN)(lk) );
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( lk->guestaddr == (Addr)rwl );
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (lk->heldBy) {
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Basically act like we unlocked the lock */
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)(
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, "pthread_rwlock_destroy of a locked mutex" );
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* remove lock from locksets of all owning threads */
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         remove_Lock_from_locksets_of_all_owning_Threads( lk );
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(deleteBag)( lk->heldBy );
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldBy = NULL;
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->heldW = False;
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lk->acquired_at = NULL;
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( !lk->heldBy );
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockN)(lk) );
2410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (HG_(clo_track_lockorders))
2412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         laog__handle_one_lock_deletion(lk);
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_locks_delete( lk->guestaddr );
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      del_LockN( lk );
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_LOCKS)
2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE");
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_RWLOCK_LOCK_PRE ( ThreadId tid,
2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       void* rwl,
2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       Word isW, Word isTryLock )
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Just check the rwl is sane; nothing else to do. */
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'rwl' may be invalid - not checked by wrapper
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*   lk;
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_PRE(ctid=%d, isW=%d, %p)\n",
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (Int)isW, (void*)rwl );
2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isTryLock == 0 || isTryLock == 1); /* assured us by wrapper */
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lk = map_locks_maybe_lookup( (Addr)rwl );
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( lk
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (lk->kind == LK_nonRec || lk->kind == LK_mbRec) ) {
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Wrong kind of lock.  Duh.  */
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_rwlock_{rd,rw}lock with a "
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "pthread_mutex_t* argument " );
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_PTHREAD_RWLOCK_LOCK_POST ( ThreadId tid, void* rwl, Word isW )
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only called if the real library call succeeded - so mutex is sane
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_POST(ctid=%d, isW=%d, %p)\n",
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (Int)isW, (void*)rwl );
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (isW ? evhH__post_thread_w_acquires_lock
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        : evhH__post_thread_r_acquires_lock)(
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thr,
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LK_rdwr, /* if not known, create new lock with this LockKind */
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Addr)rwl
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE ( ThreadId tid, void* rwl )
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'rwl' may be invalid - not checked by wrapper
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ctid=%d, rwl=%p)\n",
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)rwl );
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evhH__pre_thread_releases_lock( thr, (Addr)rwl, True/*isRDWR*/ );
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_RWLOCK_UNLOCK_POST ( ThreadId tid, void* rwl )
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only called if the real library call succeeded - so mutex is sane
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__hg_PTHREAD_RWLOCK_UNLOCK_POST(ctid=%d, rwl=%p)\n",
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)rwl );
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // anything we should do here?
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------- */
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- events to do with semaphores -------------- */
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------- */
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is similar to but not identical to the handling for condition
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   variables. */
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For each semaphore, we maintain a stack of SOs.  When a 'post'
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   operation is done on a semaphore (unlocking, essentially), a new SO
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is created for the posting thread, the posting thread does a strong
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   send to it (which merely installs the posting thread's VC in the
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO), and the SO is pushed on the semaphore's stack.
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Later, when a (probably different) thread completes 'wait' on the
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   semaphore, we pop a SO off the semaphore's stack (which should be
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nonempty), and do a strong recv from it.  This mechanism creates
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dependencies between posters and waiters of the semaphore.
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   It may not be necessary to use a stack - perhaps a bag of SOs would
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do.  But we do need to keep track of how many unused-up posts have
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happened for the semaphore.
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Imagine T1 and T2 both post once on a semaphore S, and T3 waits
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   twice on S.  T3 cannot complete its waits without both T1 and T2
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   posting.  The above mechanism will ensure that T3 acquires
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dependencies on both T1 and T2.
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When a semaphore is initialised with value N, we do as if we'd
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   posted N times on the semaphore: basically create N SOs and do a
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   strong send to all of then.  This allows up to N waits on the
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   semaphore to acquire a dependency on the initialisation point,
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which AFAICS is the correct behaviour.
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We don't emit an error for DESTROY_PRE on a semaphore we don't know
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   about.  We should.
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* sem_t* -> XArray* SO* */
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_sem_to_SO_stack = NULL;
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_sem_to_SO_stack_INIT ( void ) {
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (map_sem_to_SO_stack == NULL) {
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_sem_to_SO_stack = VG_(newFM)( HG_(zalloc), "hg.mstSs.1",
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        HG_(free), NULL );
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_sem_to_SO_stack != NULL);
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void push_SO_for_sem ( void* sem, SO* so ) {
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   keyW;
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray* xa;
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(so);
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_sem_to_SO_stack_INIT();
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( map_sem_to_SO_stack,
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &keyW, (UWord*)&xa, (UWord)sem )) {
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (UWord)sem);
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(xa);
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToXA)( xa, &so );
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     xa = VG_(newXA)( HG_(zalloc), "hg.pSfs.1", HG_(free), sizeof(SO*) );
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToXA)( xa, &so );
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( map_sem_to_SO_stack, (Word)sem, (Word)xa );
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SO* mb_pop_SO_for_sem ( void* sem ) {
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord    keyW;
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray*  xa;
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO* so;
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_sem_to_SO_stack_INIT();
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( map_sem_to_SO_stack,
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &keyW, (UWord*)&xa, (UWord)sem )) {
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* xa is the stack for this semaphore. */
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word sz;
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (UWord)sem);
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = VG_(sizeXA)( xa );
2574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(sz >= 0);
2575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 0)
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL; /* odd, the stack is empty */
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so = *(SO**)VG_(indexXA)( xa, sz-1 );
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(so);
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(dropTailXA)( xa, 1 );
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return so;
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* hmm, that's odd.  No stack for this semaphore. */
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_POSIX_SEM_DESTROY_PRE ( ThreadId tid, void* sem )
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord keyW, valW;
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*   so;
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_POSIX_SEM_DESTROY_PRE(ctid=%d, sem=%p)\n",
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)sem );
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_sem_to_SO_stack_INIT();
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Empty out the semaphore's SO stack.  This way of doing it is
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stupid, but at least it's easy. */
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so = mb_pop_SO_for_sem( sem );
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!so) break;
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_dealloc(so);
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(delFromFM)( map_sem_to_SO_stack, &keyW, &valW, (UWord)sem )) {
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XArray* xa = (XArray*)valW;
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (UWord)sem);
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(xa);
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(VG_(sizeXA)(xa) == 0); /* preceding loop just emptied it */
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteXA)(xa);
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_POSIX_SEM_INIT_POST ( ThreadId tid, void* sem, UWord value )
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*     so;
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_POSIX_SEM_INIT_POST(ctid=%d, sem=%p, value=%lu)\n",
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)sem, value );
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Empty out the semaphore's SO stack.  This way of doing it is
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stupid, but at least it's easy. */
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so = mb_pop_SO_for_sem( sem );
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!so) break;
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_dealloc(so);
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If we don't do this check, the following while loop runs us out
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of memory for stupid initial values of 'value'. */
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (value > 10000) {
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "sem_init: initial value exceeds 10000; using 10000" );
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      value = 10000;
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now create 'valid' new SOs for the thread, do a strong send to
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      each of them, and push them all on the stack. */
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (; value > 0; value--) {
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thr* hbthr = thr->hbthr;
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(hbthr);
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so = libhb_so_alloc();
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_send( hbthr, so, True/*strong send*/ );
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      push_SO_for_sem( sem, so );
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_POSIX_SEM_POST_PRE ( ThreadId tid, void* sem )
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 'tid' has posted on 'sem'.  Create a new SO, do a strong send to
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it (iow, write our VC into it, then tick ours), and push the SO
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      on on a stack of SOs associated with 'sem'.  This is later used
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by other thread(s) which successfully exit from a sem_wait on
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the same sem; by doing a strong recv from SOs popped of the
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stack, they acquire dependencies on the posting thread
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      segment(s). */
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*     so;
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*    hbthr;
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_POSIX_SEM_POST_PRE(ctid=%d, sem=%p)\n",
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)sem );
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: sem is bogus
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hbthr = thr->hbthr;
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbthr);
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so = libhb_so_alloc();
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_send( hbthr, so, True/*strong send*/ );
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   push_SO_for_sem( sem, so );
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_POSIX_SEM_WAIT_POST ( ThreadId tid, void* sem )
2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* A sem_wait(sem) completed successfully.  Pop the posting-SO for
2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the 'sem' from this semaphore's SO-stack, and do a strong recv
2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from it.  This creates a dependency back to one of the post-ers
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for the semaphore. */
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*     so;
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr*    hbthr;
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_POSIX_SEM_WAIT_POST(ctid=%d, sem=%p)\n",
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)sem );
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // error-if: sem is bogus
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so = mb_pop_SO_for_sem( sem );
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (so) {
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hbthr = thr->hbthr;
2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(hbthr);
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_recv( hbthr, so, True/*strong recv*/ );
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_dealloc(so);
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Hmm.  How can a wait on 'sem' succeed if nobody posted to it?
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         If this happened it would surely be a bug in the threads
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         library. */
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "Bug in libpthread: sem_wait succeeded on"
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              " semaphore without prior sem_post");
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------------------------------------------------- */
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- events to do with barriers -------------- */
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------------------------------------------------- */
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool    initted; /* has it yet been initted by guest? */
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool    resizable; /* is resizing allowed? */
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord   size;    /* declared size */
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XArray* waiting; /* XA of Thread*.  # present is 0 .. .size */
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar;
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bar* new_Bar ( void ) {
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar* bar = HG_(zalloc)( "hg.nB.1 (new_Bar)", sizeof(Bar) );
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* all fields are zero */
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->initted == False);
2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return bar;
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void delete_Bar ( Bar* bar ) {
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bar->waiting)
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteXA)(bar->waiting);
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(free)(bar);
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A mapping which stores auxiliary data for barriers. */
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* pthread_barrier_t* -> Bar* */
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_barrier_to_Bar = NULL;
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_barrier_to_Bar_INIT ( void ) {
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(map_barrier_to_Bar == NULL)) {
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_barrier_to_Bar = VG_(newFM)( HG_(zalloc),
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       "hg.mbtBI.1", HG_(free), NULL );
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_barrier_to_Bar != NULL);
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bar* map_barrier_to_Bar_lookup_or_alloc ( void* barrier ) {
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord key, val;
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_barrier_to_Bar_INIT();
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( map_barrier_to_Bar, &key, &val, (UWord)barrier )) {
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(key == (UWord)barrier);
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return (Bar*)val;
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bar* bar = new_Bar();
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( map_barrier_to_Bar, (UWord)barrier, (UWord)bar );
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return bar;
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_barrier_to_Bar_delete ( void* barrier ) {
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord keyW, valW;
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_barrier_to_Bar_INIT();
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(delFromFM)( map_barrier_to_Bar, &keyW, &valW, (UWord)barrier )) {
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bar* bar = (Bar*)valW;
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (UWord)barrier);
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delete_Bar(bar);
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_BARRIER_INIT_PRE ( ThreadId tid,
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               void* barrier,
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               UWord count,
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               UWord resizable )
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar*    bar;
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_BARRIER_INIT_PRE"
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(tid=%d, barrier=%p, count=%lu, resizable=%lu)\n",
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)barrier, count, resizable );
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (count == 0) {
2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_init: 'count' argument is zero"
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (resizable != 0 && resizable != 1) {
2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_init: invalid 'resizable' argument"
2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bar->initted) {
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_init: barrier is already initialised"
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(bar->initted);
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_init: threads are waiting at barrier"
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!bar->waiting) {
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bar->waiting = VG_(newXA)( HG_(zalloc), "hg.eHPBIP.1", HG_(free),
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 sizeof(Thread*) );
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->waiting);
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_(sizeXA)(bar->waiting) == 0);
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar->initted   = True;
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar->resizable = resizable == 1 ? True : False;
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar->size      = count;
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_BARRIER_DESTROY_PRE ( ThreadId tid,
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  void* barrier )
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar*    bar;
2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with destroy events.  The only purpose is to free storage
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      associated with the barrier, so as to avoid any possible
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      resource leaks. */
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_BARRIER_DESTROY_PRE"
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(tid=%d, barrier=%p)\n",
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)barrier );
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!bar->initted) {
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_destroy: barrier was never initialised"
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bar->initted && bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_destroy: threads are waiting at barrier"
2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Maybe we shouldn't do this; just let it persist, so that when it
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is reinitialised we don't need to do any dynamic memory
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allocation?  The downside is a potentially unlimited space leak,
2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if the client creates (in turn) a large number of barriers all
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      at different locations.  Note that if we do later move to the
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      don't-delete-it scheme, we need to mark the barrier as
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      uninitialised again since otherwise a later _init call will
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elicit a duplicate-init error.  */
2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_barrier_to_Bar_delete( barrier );
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All the threads have arrived.  Now do the Interesting Bit.  Get a
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new synchronisation object and do a weak send to it from all the
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   participating threads.  This makes its vector clocks be the join of
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   all the individual threads' vector clocks.  Then do a strong
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   receive from it back to all threads, so that their VCs are a copy
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of it (hence are all equal to the join of their original VCs.) */
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_barrier_cross_sync_and_empty ( Bar* bar )
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XXX check bar->waiting has no duplicates */
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord i;
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*   so = libhb_so_alloc();
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->waiting);
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_(sizeXA)(bar->waiting) == bar->size);
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* compute the join ... */
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < bar->size; i++) {
2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thr* hbthr = t->hbthr;
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_send( hbthr, so, False/*weak send*/ );
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ... and distribute to all threads */
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < bar->size; i++) {
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thr* hbthr = t->hbthr;
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_so_recv( hbthr, so, True/*strong recv*/ );
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* finally, we must empty out the waiting vector */
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* and we don't need this any more.  Perhaps a stack-allocated
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SO would be better? */
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_dealloc(so);
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_BARRIER_WAIT_PRE ( ThreadId tid,
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               void* barrier )
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* This function gets called after a client thread calls
2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     pthread_barrier_wait but before it arrives at the real
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     pthread_barrier_wait.
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Why is the following correct?  It's a bit subtle.
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     If this is not the last thread arriving at the barrier, we simply
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     note its presence and return.  Because valgrind (at least as of
2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Nov 08) is single threaded, we are guaranteed safe from any race
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     conditions when in this function -- no other client threads are
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     running.
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     If this is the last thread, then we are again the only running
2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     thread.  All the other threads will have either arrived at the
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     real pthread_barrier_wait or are on their way to it, but in any
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case are guaranteed not to be able to move past it, because this
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     thread is currently in this function and so has not yet arrived
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     at the real pthread_barrier_wait.  That means that:
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     1. While we are in this function, none of the other threads
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        waiting at the barrier can move past it.
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     2. When this function returns (and simulated execution resumes),
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        this thread and all other waiting threads will be able to move
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        past the real barrier.
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Because of this, it is now safe to update the vector clocks of
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     all threads, to represent the fact that they all arrived at the
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     barrier and have all moved on.  There is no danger of any
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     complications to do with some threads leaving the barrier and
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     racing back round to the front, whilst others are still leaving
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     (which is the primary source of complication in correct handling/
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     implementation of barriers).  That can't happen because we update
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     here our data structures so as to indicate that the threads have
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     passed the barrier, even though, as per (2) above, they are
2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     guaranteed not to pass the barrier until we return.
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     This relies crucially on Valgrind being single threaded.  If that
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     changes, this will need to be reconsidered.
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar*    bar;
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   present;
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_BARRIER_WAIT_PRE"
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(tid=%d, barrier=%p)\n",
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)barrier );
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!bar->initted) {
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_wait: barrier is uninitialised"
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* client is broken .. avoid assertions below */
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guaranteed by _INIT_PRE above */
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->size > 0);
2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->waiting);
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(addToXA)( bar->waiting, &thr );
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guaranteed by this function */
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   present = VG_(sizeXA)(bar->waiting);
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(present > 0 && present <= bar->size);
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (present < bar->size)
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_barrier_cross_sync_and_empty(bar);
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( ThreadId tid,
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                 void* barrier,
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                 UWord newcount )
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bar*    bar;
3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   present;
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_PTHREAD_BARRIER_RESIZE_PRE"
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "(tid=%d, barrier=%p, newcount=%lu)\n",
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, (void*)barrier, newcount );
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar);
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!bar->initted) {
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_resize: barrier is uninitialised"
3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* client is broken .. avoid assertions below */
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!bar->resizable) {
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_resize: barrier is may not be resized"
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* client is broken .. avoid assertions below */
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newcount == 0) {
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(record_error_Misc)(
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thr, "pthread_barrier_resize: 'newcount' argument is zero"
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* client is broken .. avoid assertions below */
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guaranteed by _INIT_PRE above */
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->size > 0);
3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bar->waiting);
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Guaranteed by this fn */
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(newcount > 0);
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newcount >= bar->size) {
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Increasing the capacity.  There's no possibility of threads
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         moving on from the barrier in this situation, so just note
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the fact and do nothing more. */
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bar->size = newcount;
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Decreasing the capacity.  If we decrease it to be equal or
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         below the number of waiting threads, they will now move past
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the barrier, so need to mess with dep edges in the same way
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         as if the barrier had filled up normally. */
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      present = VG_(sizeXA)(bar->waiting);
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(present >= 0 && present <= bar->size);
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newcount <= present) {
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bar->size = present; /* keep the cross_sync call happy */
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_barrier_cross_sync_and_empty(bar);
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bar->size = newcount;
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------------------------------------- */
3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----- events to do with user-specified HB edges ----- */
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------------------------------------- */
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A mapping from arbitrary UWord tag to the SO associated with it.
3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The UWord tags are meaningless to us, interpreted only by the
3084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   user. */
3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* UWord -> SO* */
3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_usertag_to_SO = NULL;
3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_usertag_to_SO_INIT ( void ) {
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(map_usertag_to_SO == NULL)) {
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_usertag_to_SO = VG_(newFM)( HG_(zalloc),
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      "hg.mutS.1", HG_(free), NULL );
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_usertag_to_SO != NULL);
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SO* map_usertag_to_SO_lookup_or_alloc ( UWord usertag ) {
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord key, val;
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   map_usertag_to_SO_INIT();
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( map_usertag_to_SO, &key, &val, usertag )) {
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(key == (UWord)usertag);
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return (SO*)val;
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SO* so = libhb_so_alloc();
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( map_usertag_to_SO, usertag, (UWord)so );
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return so;
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void map_usertag_to_SO_delete ( UWord usertag ) {
3113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord keyW, valW;
3114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   map_usertag_to_SO_INIT();
3115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (VG_(delFromFM)( map_usertag_to_SO, &keyW, &valW, usertag )) {
3116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SO* so = (SO*)valW;
3117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(keyW == usertag);
3118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(so);
3119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      libhb_so_dealloc(so);
3120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
3121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_USERSO_SEND_PRE ( ThreadId tid, UWord usertag )
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* TID is just about to notionally sent a message on a notional
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abstract synchronisation object whose identity is given by
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      USERTAG.  Bind USERTAG to a real SO if it is not already so
3130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      bound, and do a 'weak send' on the SO.  This joins the vector
3131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      clocks from this thread into any vector clocks already present
3132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      in the SO.  The resulting SO vector clocks are later used by
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      other thread(s) which successfully 'receive' from the SO,
3134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      thereby acquiring a dependency on all the events that have
3135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      previously signalled on this SO. */
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*     so;
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
3140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_USERSO_SEND_PRE(ctid=%d, usertag=%#lx)\n",
3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, usertag );
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so = map_usertag_to_SO_lookup_or_alloc( usertag );
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(so);
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   libhb_so_send( thr->hbthr, so, False/*!strong_send*/ );
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid evh__HG_USERSO_RECV_POST ( ThreadId tid, UWord usertag )
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* TID has just notionally received a message from a notional
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abstract synchronisation object whose identity is given by
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      USERTAG.  Bind USERTAG to a real SO if it is not already so
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bound.  If the SO has at some point in the past been 'sent' on,
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to a 'strong receive' on it, thereby acquiring a dependency on
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the sender. */
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread* thr;
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SO*     so;
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_EVENTS >= 1)
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("evh__HG_USERSO_RECV_POST(ctid=%d, usertag=%#lx)\n",
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)tid, usertag );
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr = map_threads_maybe_lookup( tid );
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr); /* cannot fail - Thread* must already exist */
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so = map_usertag_to_SO_lookup_or_alloc( usertag );
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(so);
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Acquire a dependency on it.  If the SO has never so far been
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sent on, then libhb_so_recv will do nothing.  So we're safe
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      regardless of SO's history. */
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   libhb_so_recv( thr->hbthr, so, True/*strong_recv*/ );
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
3181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid evh__HG_USERSO_FORGET_ALL ( ThreadId tid, UWord usertag )
3182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
3183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* TID declares that any happens-before edges notionally stored in
3184b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      USERTAG can be deleted.  If (as would normally be the case) a
3185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SO is associated with USERTAG, then the assocation is removed
3186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      and all resources associated with SO are freed.  Importantly,
3187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      that frees up any VTSs stored in SO. */
3188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (SHOW_EVENTS >= 1)
3189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("evh__HG_USERSO_FORGET_ALL(ctid=%d, usertag=%#lx)\n",
3190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  (Int)tid, usertag );
3191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   map_usertag_to_SO_delete( usertag );
3193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
3194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Lock acquisition order monitoring                      ---*/
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* FIXME: here are some optimisations still to do in
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          laog__pre_thread_acquires_lock.
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The graph is structured so that if L1 --*--> L2 then L1 must be
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   acquired before L2.
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The common case is that some thread T holds (eg) L1 L2 and L3 and
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is repeatedly acquiring and releasing Ln, and there is no ordering
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   error in what it is doing.  Hence it repeatly:
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (1) searches laog to see if Ln --*--> {L1,L2,L3}, which always
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       produces the answer No (because there is no error).
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (2) adds edges {L1,L2,L3} --> Ln to laog, which are already present
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       (because they already got added the first time T acquired Ln).
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Hence cache these two events:
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (1) Cache result of the query from last time.  Invalidate the cache
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       any time any edges are added to or deleted from laog.
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (2) Cache these add-edge requests and ignore them if said edges
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       have already been added to laog.  Invalidate the cache any time
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       any edges are deleted from laog.
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      WordSetID inns; /* in univ_laog */
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      WordSetID outs; /* in univ_laog */
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks;
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* lock order acquisition graph */
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* laog = NULL; /* WordFM Lock* LAOGLinks* */
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* EXPOSITION ONLY: for each edge in 'laog', record the two places
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   where that edge was created, so that we can show the user later if
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   we need to. */
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr        src_ga; /* Lock guest addresses for */
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr        dst_ga; /* src/dst of the edge */
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ExeContext* src_ec; /* And corresponding places where that */
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ExeContext* dst_ec; /* ordering was established */
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinkExposition;
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word cmp_LAOGLinkExposition ( UWord llx1W, UWord llx2W ) {
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compare LAOGLinkExposition*s by (src_ga,dst_ga) field pair. */
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinkExposition* llx1 = (LAOGLinkExposition*)llx1W;
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinkExposition* llx2 = (LAOGLinkExposition*)llx2W;
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (llx1->src_ga < llx2->src_ga) return -1;
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (llx1->src_ga > llx2->src_ga) return  1;
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (llx1->dst_ga < llx2->dst_ga) return -1;
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (llx1->dst_ga > llx2->dst_ga) return  1;
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* laog_exposition = NULL; /* WordFM LAOGLinkExposition* NULL */
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* end EXPOSITION ONLY */
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__init ( void )
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(!laog);
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(!laog_exposition);
3268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(HG_(clo_track_lockorders));
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   laog = VG_(newFM)( HG_(zalloc), "hg.laog__init.1",
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      HG_(free), NULL/*unboxedcmp*/ );
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   laog_exposition = VG_(newFM)( HG_(zalloc), "hg.laog__init.2", HG_(free),
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 cmp_LAOGLinkExposition );
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(laog);
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(laog_exposition);
3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__show ( Char* who ) {
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word i, ws_size;
3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord* ws_words;
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* me;
3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("laog (requested by %s) {\n", who);
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(initIterFM)( laog );
3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   me = NULL;
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (VG_(nextIterFM)( laog, (Word*)&me,
3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Word*)&links )) {
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(me);
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("   node %p:\n", me);
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < ws_size; i++)
3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("      inn %#lx\n", ws_words[i] );
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < ws_size; i++)
3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("      out %#lx\n", ws_words[i] );
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      me = NULL;
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links = NULL;
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(doneIterFM)( laog );
3303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("}\n");
3304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3306b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void univ_laog_do_GC ( void ) {
3307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Word i;
3308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   LAOGLinks* links;
3309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Word seen = 0;
3310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Int prev_next_gc_univ_laog = next_gc_univ_laog;
3311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const UWord univ_laog_cardinality = HG_(cardinalityWSU)( univ_laog);
3312b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3313b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool *univ_laog_seen = HG_(zalloc) ( "hg.gc_univ_laog.1",
3314b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                        (Int) univ_laog_cardinality
3315b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                        * sizeof(Bool) );
3316b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // univ_laog_seen[*] set to 0 (False) by zalloc.
3317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3318b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (VG_(clo_stats))
3319b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(message)(Vg_DebugMsg,
3320b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   "univ_laog_do_GC enter cardinality %'10d\n",
3321b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   (Int)univ_laog_cardinality);
3322b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3323b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(initIterFM)( laog );
3324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   links = NULL;
3325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while (VG_(nextIterFM)( laog, NULL, (UWord*)&links )) {
3326b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(links);
3327b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(links->inns >= 0 && links->inns < univ_laog_cardinality);
3328b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      univ_laog_seen[links->inns] = True;
3329b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(links->outs >= 0 && links->outs < univ_laog_cardinality);
3330b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      univ_laog_seen[links->outs] = True;
3331b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      links = NULL;
3332b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
3333b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(doneIterFM)( laog );
3334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < (Int)univ_laog_cardinality; i++) {
3336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (univ_laog_seen[i])
3337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         seen++;
3338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      else
3339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         HG_(dieWS) ( univ_laog, (WordSet)i );
3340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
3341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   HG_(free) (univ_laog_seen);
3343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // We need to decide the value of the next_gc.
3345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // 3 solutions were looked at:
3346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Sol 1: garbage collect at seen * 2
3347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   This solution was a lot slower, probably because we both do a lot of
3348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   garbage collection and do not keep long enough laog WV that will become
3349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   useful  again very soon.
3350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Sol 2: garbage collect at a percentage increase of the current cardinality
3351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //         (with a min increase of 1)
3352b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   Trials on a small test program with 1%, 5% and 10% increase was done.
3353b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   1% is slightly faster than 5%, which is slightly slower than 10%.
3354b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   However, on a big application, this caused the memory to be exhausted,
3355b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   as even a 1% increase of size at each gc becomes a lot, when many gc
3356b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   are done.
3357b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Sol 3: always garbage collect at current cardinality + 1.
3358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   This solution was the fastest of the 3 solutions, and caused no memory
3359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   exhaustion in the big application.
3360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //
3361b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // With regards to cost introduced by gc: on the t2t perf test (doing only
3362b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // lock/unlock operations), t2t 50 10 2 was about 25% faster than the
3363b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // version with garbage collection. With t2t 50 20 2, my machine started
3364b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // to page out, and so the garbage collected version was much faster.
3365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // On smaller lock sets (e.g. t2t 20 5 2, giving about 100 locks), the
3366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // difference performance is insignificant (~ 0.1 s).
3367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Of course, it might be that real life programs are not well represented
3368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // by t2t.
3369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // If ever we want to have a more sophisticated control
3371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // (e.g. clo options to control the percentage increase or fixed increased),
3372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // we should do it here, eg.
3373b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //     next_gc_univ_laog = prev_next_gc_univ_laog + VG_(clo_laog_gc_fixed);
3374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Currently, we just hard-code the solution 3 above.
3375b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   next_gc_univ_laog = prev_next_gc_univ_laog + 1;
3376b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (VG_(clo_stats))
3378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(message)
3379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (Vg_DebugMsg,
3380b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          "univ_laog_do_GC exit seen %'8d next gc at cardinality %'10d\n",
3381b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          (Int)seen, next_gc_univ_laog);
3382b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
3383b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3384b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__add_edge ( Lock* src, Lock* dst ) {
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       keyW;
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       presentF, presentR;
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("laog__add_edge %p %p\n", src, dst);
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Take the opportunity to sanity check the graph.  Record in
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      presentF if there is already a src->dst mapping in this node's
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      forwards links, and presentR if there is already a src->dst
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mapping in this node's backwards links.  They should agree!
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Also, we need to know whether the edge was already present so as
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to decide whether or not to update the link details mapping.  We
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      can compute presentF and presentR essentially for free, so may
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      as well do this always. */
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   presentF = presentR = False;
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Update the out edges for src */
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)src )) {
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      WordSetID outs_new;
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)src);
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      outs_new = HG_(addToWS)( univ_laog, links->outs, (Word)dst );
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      presentF = outs_new == links->outs;
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->outs = outs_new;
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links = HG_(zalloc)("hg.lae.1", sizeof(LAOGLinks));
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->inns = HG_(emptyWS)( univ_laog );
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->outs = HG_(singletonWS)( univ_laog, (Word)dst );
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( laog, (Word)src, (Word)links );
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Update the in edges for dst */
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)dst )) {
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      WordSetID inns_new;
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)dst);
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      inns_new = HG_(addToWS)( univ_laog, links->inns, (Word)src );
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      presentR = inns_new == links->inns;
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->inns = inns_new;
3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links = HG_(zalloc)("hg.lae.2", sizeof(LAOGLinks));
3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->inns = HG_(singletonWS)( univ_laog, (Word)src );
3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->outs = HG_(emptyWS)( univ_laog );
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( laog, (Word)dst, (Word)links );
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( (presentF && presentR) || (!presentF && !presentR) );
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!presentF && src->acquired_at && dst->acquired_at) {
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LAOGLinkExposition expo;
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If this edge is entering the graph, and we have acquired_at
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         information for both src and dst, record those acquisition
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         points.  Hence, if there is later a violation of this
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ordering, we can show the user the two places in which the
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         required src-dst ordering was previously established. */
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) VG_(printf)("acquire edge %#lx %#lx\n",
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         src->guestaddr, dst->guestaddr);
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expo.src_ga = src->guestaddr;
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expo.dst_ga = dst->guestaddr;
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expo.src_ec = NULL;
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expo.dst_ec = NULL;
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(laog_exposition);
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(lookupFM)( laog_exposition, NULL, NULL, (Word)&expo )) {
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* we already have it; do nothing */
3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LAOGLinkExposition* expo2 = HG_(zalloc)("hg.lae.3",
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               sizeof(LAOGLinkExposition));
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expo2->src_ga = src->guestaddr;
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expo2->dst_ga = dst->guestaddr;
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expo2->src_ec = src->acquired_at;
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expo2->dst_ec = dst->acquired_at;
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToFM)( laog_exposition, (Word)expo2, (Word)NULL );
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      univ_laog_do_GC();
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__del_edge ( Lock* src, Lock* dst ) {
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       keyW;
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0) VG_(printf)("laog__del_edge enter %p %p\n", src, dst);
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Update the out edges for src */
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)src )) {
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)src);
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->outs = HG_(delFromWS)( univ_laog, links->outs, (Word)dst );
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Update the in edges for dst */
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)dst )) {
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)dst);
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links->inns = HG_(delFromWS)( univ_laog, links->inns, (Word)src );
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3489b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3490b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Remove the exposition of src,dst (if present) */
3491b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   {
3492b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      LAOGLinkExposition *fm_expo;
3493b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3494b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      LAOGLinkExposition expo;
3495b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      expo.src_ga = src->guestaddr;
3496b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      expo.dst_ga = dst->guestaddr;
3497b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      expo.src_ec = NULL;
3498b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      expo.dst_ec = NULL;
3499b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3500b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (VG_(delFromFM) (laog_exposition,
3501b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          (UWord*)&fm_expo, NULL, (UWord)&expo )) {
3502b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         HG_(free) (fm_expo);
3503b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
3504b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
3505b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3506b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* deleting edges can increase nr of of WS so check for gc. */
3507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      univ_laog_do_GC();
3509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0) VG_(printf)("laog__del_edge exit\n");
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordSetID /* in univ_laog */ laog__succs ( Lock* lk ) {
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       keyW;
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)lk )) {
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)lk);
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return links->outs;
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return HG_(emptyWS)( univ_laog );
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordSetID /* in univ_laog */ laog__preds ( Lock* lk ) {
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       keyW;
3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   keyW  = 0;
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)lk )) {
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(keyW == (Word)lk);
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return links->inns;
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return HG_(emptyWS)( univ_laog );
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__sanity_check ( Char* who ) {
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word i, ws_size;
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord* ws_words;
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* me;
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LAOGLinks* links;
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(initIterFM)( laog );
3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   me = NULL;
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   links = NULL;
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("laog sanity check\n");
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (VG_(nextIterFM)( laog, (Word*)&me,
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Word*)&links )) {
3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(me);
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(links);
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < ws_size; i++) {
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ( ! HG_(elemWS)( univ_laog,
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             laog__succs( (Lock*)ws_words[i] ),
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Word)me ))
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto bad;
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < ws_size; i++) {
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ( ! HG_(elemWS)( univ_laog,
3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             laog__preds( (Lock*)ws_words[i] ),
3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Word)me ))
3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto bad;
3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      me = NULL;
3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      links = NULL;
3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(doneIterFM)( laog );
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  bad:
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   laog__show(who);
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(0);
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* If there is a path in laog from 'src' to any of the elements in
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'dst', return an arbitrarily chosen element of 'dst' reachable from
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'src'.  If no path exist from 'src' to any element in 'dst', return
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NULL. */
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownLock* laog__do_dfs_from_to ( Lock* src, WordSetID dsts /* univ_lsets */ )
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*     ret;
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word      i, ssz;
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray*   stack;   /* of Lock* */
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM*   visited; /* Lock* -> void, iow, Set(Lock*) */
3594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*     here;
3595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordSetID succs;
3596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word      succs_size;
3597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord*    succs_words;
3598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //laog__sanity_check();
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the destination set is empty, we can never get there from
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      'src' :-), so don't bother to try */
3602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(isEmptyWS)( univ_lsets, dsts ))
3603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
3604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ret     = NULL;
3606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack   = VG_(newXA)( HG_(zalloc), "hg.lddft.1", HG_(free), sizeof(Lock*) );
3607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   visited = VG_(newFM)( HG_(zalloc), "hg.lddft.2", HG_(free), NULL/*unboxedcmp*/ );
3608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void) VG_(addToXA)( stack, &src );
3610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
3612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ssz = VG_(sizeXA)( stack );
3614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ssz == 0) { ret = NULL; break; }
3616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      here = *(Lock**) VG_(indexXA)( stack, ssz-1 );
3618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(dropTailXA)( stack, 1 );
3619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (HG_(elemWS)( univ_lsets, dsts, (Word)here )) { ret = here; break; }
3621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(lookupFM)( visited, NULL, NULL, (Word)here ))
3623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToFM)( visited, (Word)here, 0 );
3626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      succs = laog__succs( here );
3628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < succs_size; i++)
3630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (void) VG_(addToXA)( stack, &succs_words[i] );
3631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(deleteFM)( visited, NULL, NULL );
3634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(deleteXA)( stack );
3635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ret;
3636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thread 'thr' is acquiring 'lk'.  Check for inconsistent ordering
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   between 'lk' and the locks already held by 'thr' and issue a
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   complaint if so.  Also, update the ordering graph appropriately.
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__pre_thread_acquires_lock (
3645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Thread* thr, /* NB: BEFORE lock is added */
3646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Lock*   lk
3647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
3648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord*   ls_words;
3650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word     ls_size, i;
3651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock*    other;
3652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* It may be that 'thr' already holds 'lk' and is recursively
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      relocking in.  In this case we just ignore the call. */
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NB: univ_lsets really is correct here */
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lk ))
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First, the check.  Complain if there is any path in laog from lk
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to any of the locks already held by thr, since if any such path
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      existed, it would mean that previously lk was acquired before
3662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (rather than after, as we are doing here) at least one of those
3663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      locks.
3664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   other = laog__do_dfs_from_to(lk, thr->locksetA);
3666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (other) {
3667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LAOGLinkExposition key, *found;
3668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* So we managed to find a path lk --*--> other in the graph,
3669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         which implies that 'lk' should have been acquired before
3670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         'other' but is in fact being acquired afterwards.  We present
3671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the lk/other arguments to record_error_LockOrder in the order
3672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in which they should have been acquired. */
3673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Go look in the laog_exposition mapping, to find the allocation
3674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         points for this edge, so we can show the user. */
3675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      key.src_ga = lk->guestaddr;
3676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      key.dst_ga = other->guestaddr;
3677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      key.src_ec = NULL;
3678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      key.dst_ec = NULL;
3679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      found = NULL;
3680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(lookupFM)( laog_exposition,
3681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (Word*)&found, NULL, (Word)&key )) {
3682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found != &key);
3683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found->src_ga == key.src_ga);
3684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found->dst_ga == key.dst_ga);
3685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found->src_ec);
3686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found->dst_ec);
3687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_LockOrder)(
3688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, lk->guestaddr, other->guestaddr,
3689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 found->src_ec, found->dst_ec, other->acquired_at );
3690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Hmm.  This can't happen (can it?) */
3692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_LockOrder)(
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thr, lk->guestaddr, other->guestaddr,
3694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 NULL, NULL, NULL );
3695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Second, add to laog the pairs
3699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        (old, lk)  |  old <- locks already held by thr
3700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Since both old and lk are currently held by thr, their acquired_at
3701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fields must be non-NULL.
3702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
3703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(lk->acquired_at);
3704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, thr->locksetA );
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < ls_size; i++) {
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Lock* old = (Lock*)ls_words[i];
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(old->acquired_at);
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      laog__add_edge( old, lk );
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Why "except_Locks" ?  We're here because a lock is being
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      acquired by a thread, and we're in an inconsistent state here.
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      See the call points in evhH__post_thread_{r,w}_acquires_lock.
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      When called in this inconsistent state, locks__sanity_check duly
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      barfs. */
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags) & SCE_LAOG)
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all_except_Locks__sanity_check("laog__pre_thread_acquires_lock-post");
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3720b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Allocates a duplicate of words. Caller must HG_(free) the result. */
3721b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic UWord* UWordV_dup(UWord* words, Word words_size)
3722b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
3723b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt i;
3724b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3725b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (words_size == 0)
3726b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return NULL;
3727b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3728b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord *dup = HG_(zalloc) ("hg.dup.1", (SizeT) words_size * sizeof(UWord));
3729b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3730b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < words_size; i++)
3731b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      dup[i] = words[i];
3732b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3733b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return dup;
3734b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Delete from 'laog' any pair mentioning a lock in locksToDelete */
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void laog__handle_one_lock_deletion ( Lock* lk )
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordSetID preds, succs;
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word preds_size, succs_size, i, j;
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *preds_words, *succs_words;
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   preds = laog__preds( lk );
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   succs = laog__succs( lk );
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3748b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // We need to duplicate the payload, as these can be garbage collected
3749b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // during the del/add operations below.
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(getPayloadWS)( &preds_words, &preds_size, univ_laog, preds );
3751b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   preds_words = UWordV_dup(preds_words, preds_size);
3752b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3753b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3754b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   succs_words = UWordV_dup(succs_words, succs_size);
3755b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < preds_size; i++)
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      laog__del_edge( (Lock*)preds_words[i], lk );
3758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (j = 0; j < succs_size; j++)
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      laog__del_edge( lk, (Lock*)succs_words[j] );
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < preds_size; i++) {
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = 0; j < succs_size; j++) {
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (preds_words[i] != succs_words[j]) {
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This can pass unlocked locks to laog__add_edge, since
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               we're deleting stuff.  So their acquired_at fields may
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               be NULL. */
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            laog__add_edge( (Lock*)preds_words[i], (Lock*)succs_words[j] );
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3772b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (preds_words)
3774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      HG_(free) (preds_words);
3775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (succs_words)
3776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      HG_(free) (succs_words);
3777b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3778b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Remove lk information from laog links FM
3779b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   {
3780b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      LAOGLinks *links;
3781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Lock* linked_lk;
3782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
3783b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (VG_(delFromFM) (laog,
3784b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          (UWord*)&linked_lk, (UWord*)&links, (UWord)lk)) {
3785b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert (linked_lk == lk);
3786b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         HG_(free) (links);
3787b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
3788b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
3789b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* FIXME ??? What about removing lock lk data from EXPOSITION ??? */
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//__attribute__((noinline))
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//static void laog__handle_lock_deletions (
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//               WordSetID /* in univ_laog */ locksToDelete
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//            )
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//{
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Word   i, ws_size;
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   UWord* ws_words;
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
3801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
3802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//   UWordV_dup call needed here ...
3803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   for (i = 0; i < ws_size; i++)
3804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
3805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
3806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   if (HG_(clo_sanity_flags) & SCE_LAOG)
3807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      all__sanity_check("laog__handle_lock_deletions-post");
3808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//}
3809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Malloc/free replacements                               ---*/
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
3814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void*       next;    /* required by m_hashtable */
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr        payload; /* ptr to actual block    */
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT       szB;     /* size requested         */
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ExeContext* where;   /* where it was allocated */
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thread*     thr;     /* allocating thread      */
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta;
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A hash table of MallocMetas, used to track malloc'd blocks
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (obviously). */
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VgHashTable hg_mallocmeta_table = NULL;
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic MallocMeta* new_MallocMeta ( void ) {
3831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta* md = HG_(zalloc)( "hg.new_MallocMeta.1", sizeof(MallocMeta) );
3832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(md);
3833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return md;
3834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void delete_MallocMeta ( MallocMeta* md ) {
3836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(free)(md);
3837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate a client block and set up the metadata for it. */
3841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* handle_alloc ( ThreadId tid,
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     SizeT szB, SizeT alignB, Bool is_zeroed )
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr        p;
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta* md;
3848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( ((SSizeT)szB) >= 0 );
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = (Addr)VG_(cli_malloc)(alignB, szB);
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!p) {
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_zeroed)
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memset)((void*)p, 0, szB);
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note that map_threads_lookup must succeed (cannot assert), since
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      memory can only be allocated by currently alive threads, hence
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      they must have an entry in map_threads. */
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md = new_MallocMeta();
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md->payload = p;
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md->szB     = szB;
3863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md->where   = VG_(record_ExeContext)( tid, 0 );
3864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md->thr     = map_threads_lookup( tid );
3865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md );
3867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the lower level memory wranglers. */
3869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evh__new_mem_heap( p, szB, is_zeroed );
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (void*)p;
3872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Re the checks for less-than-zero (also in hg_cli__realloc below):
3875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Cast to a signed type to catch any unexpectedly negative args.
3876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We're assuming here that the size asked for is not greater than
3877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   2^31 bytes (for 32-bit platforms) or 2^63 bytes (for 64-bit
3878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platforms). */
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli__malloc ( ThreadId tid, SizeT n ) {
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((SSizeT)n) < 0) return NULL;
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handle_alloc ( tid, n, VG_(clo_alignment),
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*is_zeroed*/False );
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli____builtin_new ( ThreadId tid, SizeT n ) {
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((SSizeT)n) < 0) return NULL;
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handle_alloc ( tid, n, VG_(clo_alignment),
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*is_zeroed*/False );
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli____builtin_vec_new ( ThreadId tid, SizeT n ) {
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((SSizeT)n) < 0) return NULL;
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handle_alloc ( tid, n, VG_(clo_alignment),
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*is_zeroed*/False );
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli__memalign ( ThreadId tid, SizeT align, SizeT n ) {
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((SSizeT)n) < 0) return NULL;
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handle_alloc ( tid, n, align,
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*is_zeroed*/False );
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli__calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( ((SSizeT)nmemb) < 0 || ((SSizeT)size1) < 0 ) return NULL;
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handle_alloc ( tid, nmemb*size1, VG_(clo_alignment),
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*is_zeroed*/True );
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Free a client block, including getting rid of the relevant
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   metadata. */
3908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void handle_free ( ThreadId tid, void* p )
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta *md, *old_md;
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT      szB;
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First see if we can find the metadata for 'p'. */
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!md)
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* apparently freeing a bogus address.  Oh well. */
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(md->payload == (Addr)p);
3920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   szB = md->szB;
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Nuke the metadata block */
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_md = (MallocMeta*)
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(HT_remove)( hg_mallocmeta_table, (UWord)p );
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(old_md); /* it must be present - we just found it */
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(old_md == md);
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(old_md->payload == (Addr)p);
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(cli_free)((void*)old_md->payload);
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delete_MallocMeta(old_md);
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the lower level memory wranglers. */
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evh__die_mem_heap( (Addr)p, szB );
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_cli__free ( ThreadId tid, void* p ) {
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handle_free(tid, p);
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_cli____builtin_delete ( ThreadId tid, void* p ) {
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handle_free(tid, p);
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_cli____builtin_vec_delete ( ThreadId tid, void* p ) {
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handle_free(tid, p);
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* hg_cli__realloc ( ThreadId tid, void* payloadV, SizeT new_size )
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta *md, *md_new, *md_tmp;
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT      i;
3951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr payload = (Addr)payloadV;
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((SSizeT)new_size) < 0) return NULL;
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)payload );
3957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!md)
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL; /* apparently realloc-ing a bogus address.  Oh well. */
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(md->payload == payload);
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (md->szB == new_size) {
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* size unchanged */
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md->where = VG_(record_ExeContext)(tid, 0);
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return payloadV;
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (md->szB > new_size) {
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new size is smaller */
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md->szB   = new_size;
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md->where = VG_(record_ExeContext)(tid, 0);
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evh__die_mem_heap( md->payload + new_size, md->szB - new_size );
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return payloadV;
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* else */ {
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new size is bigger */
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* First half kept and copied, second half new */
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // FIXME: shouldn't we use a copier which implements the
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // memory state machine?
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evh__copy_mem( payload, p_new, md->szB );
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evh__new_mem_heap ( p_new + md->szB, new_size - md->szB,
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /*inited*/False );
3986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: can anything funny happen here?  specifically, if the
3987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old range contained a lock, then die_mem_heap will complain.
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Is that the correct behaviour?  Not sure. */
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      evh__die_mem_heap( payload, md->szB );
3990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Copy from old to new */
3992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < md->szB; i++)
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ((UChar*)p_new)[i] = ((UChar*)payload)[i];
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Because the metadata hash table is index by payload address,
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we have to get rid of the old hash table entry and make a new
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         one.  We can't just modify the existing metadata in place,
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         because then it would (almost certainly) be in the wrong hash
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         chain. */
4000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_new = new_MallocMeta();
4001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *md_new = *md;
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_tmp = VG_(HT_remove)( hg_mallocmeta_table, payload );
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(md_tmp);
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(md_tmp == md);
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(cli_free)((void*)md->payload);
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delete_MallocMeta(md);
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update fields */
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_new->where   = VG_(record_ExeContext)( tid, 0 );
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_new->szB     = new_size;
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_new->payload = p_new;
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      md_new->thr     = map_threads_lookup( tid );
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* and add */
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md_new );
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return (void*)p_new;
4020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT hg_cli_malloc_usable_size ( ThreadId tid, void* p )
4024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta *md = VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
4026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // There may be slop, but pretend there isn't because only the asked-for
4028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // area will have been shadowed properly.
4029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( md ? md->szB : 0 );
4030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For error creation: map 'data_addr' to a malloc'd chunk, if any.
4034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Slow linear search.  With a bit of hash table help if 'data_addr'
4035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is either the start of a block or up to 15 word-sized steps along
4036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from the start of a block. */
4037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Bool addr_is_in_MM_Chunk( MallocMeta* mm, Addr a )
4039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Accept 'a' as within 'mm' if 'mm's size is zero and 'a' points
4041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      right at it. */
4042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (UNLIKELY(mm->szB == 0 && a == mm->payload))
4043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return True;
4044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* else normal interval rules apply */
4045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (LIKELY(a < mm->payload)) return False;
4046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (LIKELY(a >= mm->payload + mm->szB)) return False;
4047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return True;
4048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
4051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*OUT*/Addr*        payload,
4052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*OUT*/SizeT*       szB,
4053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    Addr                data_addr )
4054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MallocMeta* mm;
4056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
4057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Int n_fast_check_words = 16;
4058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First, do a few fast searches on the basis that data_addr might
4060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      be exactly the start of a block or up to 15 words inside.  This
4061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      can happen commonly via the creq
4062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK. */
4063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_fast_check_words; i++) {
4064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mm = VG_(HT_lookup)( hg_mallocmeta_table,
4065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           data_addr - (UWord)(UInt)i * sizeof(UWord) );
4066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (UNLIKELY(mm && addr_is_in_MM_Chunk(mm, data_addr)))
4067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto found;
4068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Well, this totally sucks.  But without using an interval tree or
4071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      some such, it's hard to see how to do better.  We have to check
4072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      every block in the entire table. */
4073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_ResetIter)(hg_mallocmeta_table);
4074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (mm = VG_(HT_Next)(hg_mallocmeta_table)) ) {
4075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (UNLIKELY(addr_is_in_MM_Chunk(mm, data_addr)))
4076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto found;
4077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Not found.  Bah. */
4080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
4081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
4082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  found:
4084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(mm);
4085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(addr_is_in_MM_Chunk(mm, data_addr));
4086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (where)   *where   = mm->where;
4087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (payload) *payload = mm->payload;
4088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szB)     *szB     = mm->szB;
4089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
4090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
4094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Instrumentation                                        ---*/
4095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
4096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2))
4098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define mkexpr(_tmp)             IRExpr_RdTmp((_tmp))
4099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define mkU32(_n)                IRExpr_Const(IRConst_U32(_n))
4100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define mkU64(_n)                IRExpr_Const(IRConst_U64(_n))
4101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define assign(_t, _e)           IRStmt_WrTmp((_t), (_e))
4102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void instrument_mem_access ( IRSB*   sbOut,
4104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    IRExpr* addr,
4105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    Int     szB,
4106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    Bool    isStore,
4107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    Int     hWordTy_szB,
4108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    Int     goff_sp )
4109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType   tyAddr   = Ity_INVALID;
4111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*   hName    = NULL;
4112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*    hAddr    = NULL;
4113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      regparms = 0;
4114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** argv     = NULL;
4115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty* di       = NULL;
4116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // THRESH is the size of the window above SP (well,
4118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // mostly above) that we assume implies a stack reference.
4119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const Int THRESH = 4096 * 4; // somewhat arbitrary
4120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const Int rz_szB = VG_STACK_REDZONE_SZB;
4121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isIRAtom(addr));
4123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
4124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tyAddr = typeOfIRExpr( sbOut->tyenv, addr );
4126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
4127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So the effective address is in 'addr' now. */
4129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regparms = 1; // unless stated otherwise
4130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isStore) {
4131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (szB) {
4132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
4133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cwrite_1";
4134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cwrite_1;
4135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
4138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cwrite_2";
4139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cwrite_2;
4140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4:
4143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cwrite_4";
4144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cwrite_4;
4145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 8:
4148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cwrite_8";
4149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cwrite_8;
4150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
4153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(szB > 8 && szB <= 512); /* stay sane */
4154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regparms = 2;
4155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cwrite_N";
4156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cwrite_N;
4157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (szB) {
4162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
4163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cread_1";
4164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cread_1;
4165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
4168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cread_2";
4169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cread_2;
4170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4:
4173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cread_4";
4174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cread_4;
4175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 8:
4178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cread_8";
4179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cread_8;
4180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_1( addr );
4181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
4183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(szB > 8 && szB <= 512); /* stay sane */
4184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regparms = 2;
4185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hName = "evh__mem_help_cread_N";
4186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hAddr = &evh__mem_help_cread_N;
4187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Create the helper. */
4193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hName);
4194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hAddr);
4195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(argv);
4196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = unsafeIRDirty_0_N( regparms,
4197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           hName, VG_(fnptr_to_fnentry)( hAddr ),
4198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           argv );
4199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (! HG_(clo_check_stack_refs)) {
4201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* We're ignoring memory references which are (obviously) to the
4202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stack.  In fact just skip stack refs that are within 4 pages
4203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         of SP (SP - the redzone, really), as that's simple, easy, and
4204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         filters out most stack references. */
4205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Generate the guard condition: "(addr - (SP - RZ)) >u N", for
4206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         some arbitrary N.  If that is true then addr is outside the
4207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         range (SP - RZ .. SP + N - RZ).  If N is smallish (a few
4208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         pages) then we can say addr is within a few pages of SP and
4209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         so can't possibly be a heap access, and so can be skipped.
4210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Note that the condition simplifies to
4212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            (addr - SP + RZ) >u N
4213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         which generates better code in x86/amd64 backends, but it does
4214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         not unfortunately simplify to
4215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            (addr - SP) >u (N - RZ)
4216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (would be beneficial because N - RZ is a constant) because
4217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         wraparound arithmetic messes up the comparison.  eg.
4218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         20 >u 10 == True,
4219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         but (20 - 15) >u (10 - 15) == 5 >u (MAXINT-5) == False.
4220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      */
4221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp sp = newIRTemp(sbOut->tyenv, tyAddr);
4222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      addStmtToIRSB( sbOut, assign(sp, IRExpr_Get(goff_sp, tyAddr)));
4223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* "addr - SP" */
4225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp addr_minus_sp = newIRTemp(sbOut->tyenv, tyAddr);
4226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      addStmtToIRSB(
4227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         sbOut,
4228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(addr_minus_sp,
4229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                tyAddr == Ity_I32
4230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   ? binop(Iop_Sub32, addr, mkexpr(sp))
4231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   : binop(Iop_Sub64, addr, mkexpr(sp)))
4232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      );
4233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* "addr - SP + RZ" */
4235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp diff = newIRTemp(sbOut->tyenv, tyAddr);
4236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      addStmtToIRSB(
4237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         sbOut,
4238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(diff,
4239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                tyAddr == Ity_I32
4240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   ? binop(Iop_Add32, mkexpr(addr_minus_sp), mkU32(rz_szB))
4241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   : binop(Iop_Add64, mkexpr(addr_minus_sp), mkU64(rz_szB)))
4242b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      );
4243b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp guard = newIRTemp(sbOut->tyenv, Ity_I1);
4245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      addStmtToIRSB(
4246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         sbOut,
4247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(guard,
4248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                tyAddr == Ity_I32
4249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   ? binop(Iop_CmpLT32U, mkU32(THRESH), mkexpr(diff))
4250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   : binop(Iop_CmpLT64U, mkU64(THRESH), mkexpr(diff)))
4251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      );
4252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      di->guard = mkexpr(guard);
4253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Add the helper. */
4256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
4257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out if GA is a guest code address in the dynamic linker, and
4261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if so return True.  Otherwise (and in case of any doubt) return
4262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   False.  (sidedly safe w/ False as the safe value) */
4263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_in_dynamic_linker_shared_object( Addr64 ga )
4264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* dinfo;
4266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UChar* soname;
4267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) return False;
4268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dinfo = VG_(find_DebugInfo)( (Addr)ga );
4270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!dinfo) return False;
4271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   soname = VG_(DebugInfo_get_soname)(dinfo);
4273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(soname);
4274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("%s\n", soname);
4275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
4277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3))        return True;
4278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2))        return True;
4279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2)) return True;
4280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_LD64_SO_1))            return True;
4281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_LD_SO_1))              return True;
4282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
4283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ(soname, VG_U_DYLD)) return True;
4284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
4285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unsupported OS"
4286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
4287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
4288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRSB* hg_instrument ( VgCallbackClosure* closure,
4292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRSB* bbIn,
4293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestLayout* layout,
4294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestExtents* vge,
4295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRType gWordTy, IRType hWordTy )
4296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     i;
4298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB*   bbOut;
4299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64  cia; /* address of current insn */
4300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt* st;
4301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    inLDSO = False;
4302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64  inLDSOmask4K = 1; /* mismatches on first check */
4303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const Int goff_sp = layout->offset_SP;
4305b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gWordTy != hWordTy) {
4307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We don't currently support this case. */
4308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("host/guest word size mismatch");
4309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VKI_PAGE_SIZE < 4096 || VG_(log2)(VKI_PAGE_SIZE) == -1) {
4312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("implausible or too-small VKI_PAGE_SIZE");
4313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up BB */
4316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbOut           = emptyIRSB();
4317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbOut->tyenv    = deepCopyIRTypeEnv(bbIn->tyenv);
4318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbOut->next     = deepCopyIRExpr(bbIn->next);
4319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbOut->jumpkind = bbIn->jumpkind;
4320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Copy verbatim any IR preamble preceding the first IMark
4322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   i = 0;
4323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
4324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bbOut, bbIn->stmts[i] );
4325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      i++;
4326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Get the first statement, and initial cia from it
4329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(bbIn->stmts_used > 0);
4330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(i < bbIn->stmts_used);
4331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   st = bbIn->stmts[i];
4332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(Ist_IMark == st->tag);
4333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cia = st->Ist.IMark.addr;
4334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   st = NULL;
4335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (/*use current i*/; i < bbIn->stmts_used; i++) {
4337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st = bbIn->stmts[i];
4338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(st);
4339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(isFlatIRStmt(st));
4340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (st->tag) {
4341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_NoOp:
4342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_AbiHint:
4343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Put:
4344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_PutI:
4345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Exit:
4346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* None of these can contain any memory references. */
4347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_IMark:
4350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* no mem refs, but note the insn address. */
4351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cia = st->Ist.IMark.addr;
4352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Don't instrument the dynamic linker.  It generates a
4353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               lot of races which we just expensively suppress, so
4354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               it's pointless.
4355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Avoid flooding is_in_dynamic_linker_shared_object with
4357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               requests by only checking at transitions between 4K
4358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               pages. */
4359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((cia & ~(Addr64)0xFFF) != inLDSOmask4K) {
4360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) VG_(printf)("NEW %#lx\n", (Addr)cia);
4361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               inLDSOmask4K = cia & ~(Addr64)0xFFF;
4362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               inLDSO = is_in_dynamic_linker_shared_object(cia);
4363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) VG_(printf)("old %#lx\n", (Addr)cia);
4365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_MBE:
4369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (st->Ist.MBE.event) {
4370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Imbe_Fence:
4371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break; /* not interesting */
4372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
4373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  goto unhandled;
4374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_CAS: {
4378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Atomic read-modify-write cycle.  Just pretend it's a
4379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               read. */
4380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRCAS* cas    = st->Ist.CAS.details;
4381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool   isDCAS = cas->oldHi != IRTemp_INVALID;
4382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isDCAS) {
4383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(cas->expdHi);
4384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(cas->dataHi);
4385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(!cas->expdHi);
4387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(!cas->dataHi);
4388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Just be boring about it. */
4390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!inLDSO) {
4391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instrument_mem_access(
4392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  bbOut,
4393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  cas->addr,
4394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (isDCAS ? 2 : 1)
4395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     * sizeofIRType(typeOfIRExpr(bbIn->tyenv, cas->dataLo)),
4396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  False/*!isStore*/,
4397b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  sizeofIRType(hWordTy), goff_sp
4398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_LLSC: {
4404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We pretend store-conditionals don't exist, viz, ignore
4405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               them.  Whereas load-linked's are treated the same as
4406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               normal loads. */
4407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRType dataTy;
4408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (st->Ist.LLSC.storedata == NULL) {
4409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* LL */
4410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dataTy = typeOfIRTemp(bbIn->tyenv, st->Ist.LLSC.result);
4411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!inLDSO) {
4412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_mem_access(
4413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bbOut,
4414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     st->Ist.LLSC.addr,
4415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sizeofIRType(dataTy),
4416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     False/*!isStore*/,
4417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     sizeofIRType(hWordTy), goff_sp
4418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
4419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* SC */
4422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*ignore */
4423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Store:
4428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* It seems we pretend that store-conditionals don't
4429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               exist, viz, just ignore them ... */
4430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!inLDSO) {
4431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instrument_mem_access(
4432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  bbOut,
4433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  st->Ist.Store.addr,
4434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
4435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  True/*isStore*/,
4436b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  sizeofIRType(hWordTy), goff_sp
4437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
4438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_WrTmp: {
4442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* ... whereas here we don't care whether a load is a
4443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vanilla one or a load-linked. */
4444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* data = st->Ist.WrTmp.data;
4445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (data->tag == Iex_Load) {
4446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!inLDSO) {
4447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_mem_access(
4448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bbOut,
4449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     data->Iex.Load.addr,
4450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sizeofIRType(data->Iex.Load.ty),
4451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     False/*!isStore*/,
4452b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     sizeofIRType(hWordTy), goff_sp
4453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
4454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Dirty: {
4460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Int      dataSize;
4461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRDirty* d = st->Ist.Dirty.details;
4462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (d->mFx != Ifx_None) {
4463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This dirty helper accesses memory.  Collect the
4464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  details. */
4465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(d->mAddr != NULL);
4466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(d->mSize != 0);
4467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dataSize = d->mSize;
4468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
4469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (!inLDSO) {
4470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     instrument_mem_access(
4471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        bbOut, d->mAddr, dataSize, False/*!isStore*/,
4472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        sizeofIRType(hWordTy), goff_sp
4473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
4474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
4475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
4477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (!inLDSO) {
4478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     instrument_mem_access(
4479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        bbOut, d->mAddr, dataSize, True/*isStore*/,
4480b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        sizeofIRType(hWordTy), goff_sp
4481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
4482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
4483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(d->mAddr == NULL);
4486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(d->mSize == 0);
4487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
4492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unhandled:
4493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRStmt(st);
4494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(0);
4495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } /* switch (st->tag) */
4497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bbOut, st );
4499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* iterate over bbIn->stmts */
4500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return bbOut;
4502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4504b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef binop
4505b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef mkexpr
4506b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef mkU32
4507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef mkU64
4508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef assign
4509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
4512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Client requests                                          ---*/
4513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
4514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sheesh.  Yet another goddam finite map. */
4516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_pthread_t_to_Thread = NULL; /* pthread_t -> Thread* */
4517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void map_pthread_t_to_Thread_INIT ( void ) {
4519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(map_pthread_t_to_Thread == NULL)) {
4520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_pthread_t_to_Thread = VG_(newFM)( HG_(zalloc), "hg.mpttT.1",
4521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            HG_(free), NULL );
4522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_pthread_t_to_Thread != NULL);
4523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
4529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
4531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
4532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Anything that gets past the above check is one of ours, so we
4534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should be able to handle it. */
4535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* default, meaningless return value, unless otherwise set */
4537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ret = 0;
4538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (args[0]) {
4540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --- --- User-visible client requests --- --- */
4542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__HG_CLEAN_MEMORY:
4544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY(%#lx,%ld)\n",
4545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args[1], args[2]);
4546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Call die_mem to (expensively) tidy up properly, if there
4547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            are any held locks etc in the area.  Calling evh__die_mem
4548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            and then evh__new_mem is a bit inefficient; probably just
4549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            the latter would do. */
4550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (args[2] > 0) { /* length */
4551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            evh__die_mem(args[1], args[2]);
4552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* and then set it to New */
4553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            evh__new_mem(args[1], args[2]);
4554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK: {
4558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Addr  payload = 0;
4559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SizeT pszB = 0;
4560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK(%#lx)\n",
4561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args[1]);
4562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (HG_(mm_find_containing_block)(NULL, &payload, &pszB, args[1])) {
4563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pszB > 0) {
4564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               evh__die_mem(payload, pszB);
4565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               evh__new_mem(payload, pszB);
4566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *ret = pszB;
4568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *ret = (UWord)-1;
4570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED:
4575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) VG_(printf)("HG_ARANGE_MAKE_UNTRACKED(%#lx,%ld)\n",
4576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args[1], args[2]);
4577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (args[2] > 0) { /* length */
4578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            evh__untrack_mem(args[1], args[2]);
4579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_ARANGE_MAKE_TRACKED:
4583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) VG_(printf)("HG_ARANGE_MAKE_TRACKED(%#lx,%ld)\n",
4584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args[1], args[2]);
4585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (args[2] > 0) { /* length */
4586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            evh__new_mem(args[1], args[2]);
4587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --- --- Client requests for Helgrind's use only --- --- */
4591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Some thread is telling us its pthread_t value.  Record the
4593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binding between that and the associated Thread*, so we can
4594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         later find the Thread* again when notified of a join by the
4595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thread. */
4596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_SET_MY_PTHREAD_T: {
4597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Thread* my_thr = NULL;
4598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0)
4599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("SET_MY_PTHREAD_T (tid %d): pthread_t = %p\n", (Int)tid,
4600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (void*)args[1]);
4601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         map_pthread_t_to_Thread_INIT();
4602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         my_thr = map_threads_maybe_lookup( tid );
4603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This assertion should hold because the map_threads (tid to
4604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*) binding should have been made at the point of
4605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            low-level creation of this thread, which should have
4606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            happened prior to us getting this client request for it.
4607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            That's because this client request is sent from
4608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            client-world from the 'thread_wrapper' function, which
4609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            only runs once the thread has been low-level created. */
4610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(my_thr != NULL);
4611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* So now we know that (pthread_t)args[1] is associated with
4612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (Thread*)my_thr.  Note that down. */
4613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0)
4614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
4615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (void*)args[1], (void*)my_thr );
4616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToFM)( map_pthread_t_to_Thread, (Word)args[1], (Word)my_thr );
4617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTH_API_ERROR: {
4621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Thread* my_thr = NULL;
4622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         map_pthread_t_to_Thread_INIT();
4623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         my_thr = map_threads_maybe_lookup( tid );
4624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */
4625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_PthAPIerror)(
4626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my_thr, (HChar*)args[1], (Word)args[2], (HChar*)args[3] );
4627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This thread (tid) has completed a join with the quitting
4631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thread whose pthread_t is in args[1]. */
4632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_JOIN_POST: {
4633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Thread* thr_q = NULL; /* quitter Thread* */
4634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool    found = False;
4635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0)
4636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("NOTIFY_JOIN_COMPLETE (tid %d): quitter = %p\n", (Int)tid,
4637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (void*)args[1]);
4638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         map_pthread_t_to_Thread_INIT();
4639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         found = VG_(lookupFM)( map_pthread_t_to_Thread,
4640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                NULL, (Word*)&thr_q, (Word)args[1] );
4641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          /* Can this fail?  It would mean that our pthread_join
4642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             wrapper observed a successful join on args[1] yet that
4643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             thread never existed (or at least, it never lodged an
4644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             entry in the mapping (via SET_MY_PTHREAD_T)).  Which
4645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             sounds like a bug in the threads library. */
4646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: get rid of this assertion; handle properly
4647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(found);
4648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (found) {
4649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0)
4650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)(".................... quitter Thread* = %p\n",
4651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        thr_q);
4652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            evh__HG_PTHREAD_JOIN_POST( tid, thr_q );
4653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* EXPOSITION only: by intercepting lock init events we can show
4658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the user where the lock was initialised, rather than only
4659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         being able to show where it was first locked.  Intercepting
4660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lock initialisations is not necessary for the basic operation
4661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of the race checker. */
4662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST:
4663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_INIT_POST( tid, (void*)args[1], args[2] );
4664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE:
4667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, (void*)args[1] );
4668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE:   // pth_mx_t*
4671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
4672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST:  // pth_mx_t*
4675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
4676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE:     // pth_mx_t*, Word
4679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
4680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST:    // pth_mx_t*
4683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
4684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This thread is about to do pthread_cond_signal on the
4687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pthread_cond_t* in arg[1].  Ditto pthread_cond_broadcast. */
4688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
4689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
4690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
4691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
4694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Returns a flag indicating whether or not the mutex is believed to be
4695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid for this operation. */
4696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
4697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool mutex_is_valid
4698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1],
4699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  (void*)args[2] );
4700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *ret = mutex_is_valid ? 1 : 0;
4701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* cond=arg[1] */
4705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE:
4706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_COND_DESTROY_PRE( tid, (void*)args[1] );
4707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Thread successfully completed pthread_cond_wait, cond=arg[1],
4710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mutex=arg[2] */
4711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
4712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_COND_WAIT_POST( tid,
4713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         (void*)args[1], (void*)args[2] );
4714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
4717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_INIT_POST( tid, (void*)args[1] );
4718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE:
4721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( tid, (void*)args[1] );
4722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rwlock=arg[1], isW=arg[2], isTryLock=arg[3] */
4725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
4726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
4727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               args[2], args[3] );
4728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rwlock=arg[1], isW=arg[2] */
4731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
4732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
4733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
4736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
4737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
4740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
4741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_POSIX_SEM_INIT_POST: /* sem_t*, unsigned long */
4744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_POSIX_SEM_INIT_POST( tid, (void*)args[1], args[2] );
4745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE: /* sem_t* */
4748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_POSIX_SEM_DESTROY_PRE( tid, (void*)args[1] );
4749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_POSIX_SEM_POST_PRE: /* sem_t* */
4752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
4753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t* */
4756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
4757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE:
4760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_bar_t*, ulong count, ulong resizable */
4761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_BARRIER_INIT_PRE( tid, (void*)args[1],
4762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                args[2], args[3] );
4763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE:
4766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_bar_t*, ulong newcount */
4767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( tid, (void*)args[1],
4768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              args[2] );
4769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE:
4772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_bar_t* */
4773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_BARRIER_WAIT_PRE( tid, (void*)args[1] );
4774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE:
4777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_bar_t* */
4778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_BARRIER_DESTROY_PRE( tid, (void*)args[1] );
4779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE:
4782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_spinlock_t* */
4783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( tid, (void*)args[1] );
4784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST:
4787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_spinlock_t* */
4788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( tid, (void*)args[1] );
4789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE:
4792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_spinlock_t*, Word */
4793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_SPIN_LOCK_PRE( tid, (void*)args[1], args[2] );
4794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST:
4797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_spinlock_t* */
4798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_SPIN_LOCK_POST( tid, (void*)args[1] );
4799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE:
4802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* pth_spinlock_t* */
4803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_PTHREAD_SPIN_DESTROY_PRE( tid, (void*)args[1] );
4804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_CLIENTREQ_UNIMP: {
4807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* char* who */
4808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar*  who = (HChar*)args[1];
4809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar   buf[50 + 50];
4810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Thread* thr = map_threads_maybe_lookup( tid );
4811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert( thr ); /* I must be mapped */
4812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert( who );
4813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert( VG_(strlen)(who) <= 50 );
4814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(sprintf)(buf, "Unimplemented client request macro \"%s\"", who );
4815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* record_error_Misc strdup's buf, so this is safe: */
4816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(record_error_Misc)( thr, buf );
4817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_USERSO_SEND_PRE:
4821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* UWord arbitrary-SO-tag */
4822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_USERSO_SEND_PRE( tid, args[1] );
4823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case _VG_USERREQ__HG_USERSO_RECV_POST:
4826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* UWord arbitrary-SO-tag */
4827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         evh__HG_USERSO_RECV_POST( tid, args[1] );
4828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4830b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case _VG_USERREQ__HG_USERSO_FORGET_ALL:
4831b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* UWord arbitrary-SO-tag */
4832b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         evh__HG_USERSO_FORGET_ALL( tid, args[1] );
4833b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
4834b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
4836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unhandled Helgrind client request! */
4837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert2(0, "unhandled Helgrind client request 0x%lx",
4838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       args[0]);
4839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
4842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
4846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Setup                                                    ---*/
4847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
4848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool hg_process_cmd_line_option ( Char* arg )
4850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* tmp_str;
4852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if      VG_BOOL_CLO(arg, "--track-lockorders",
4854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            HG_(clo_track_lockorders)) {}
4855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--cmp-race-err-addrs",
4856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            HG_(clo_cmp_race_err_addrs)) {}
4857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--history-level=none",
4859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            HG_(clo_history_level), 0);
4860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--history-level=approx",
4861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            HG_(clo_history_level), 1);
4862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--history-level=full",
4863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            HG_(clo_history_level), 2);
4864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If you change the 10k/30mill limits, remember to also change
4866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      them in assertions at the top of event_map_maybe_GC. */
4867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BINT_CLO(arg, "--conflict-cache-size",
4868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       HG_(clo_conflict_cache_size), 10*1000, 30*1000*1000) {}
4869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* "stuvwx" --> stuvwx (binary) */
4871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO(arg, "--hg-sanity-flags", tmp_str) {
4872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int j;
4873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (6 != VG_(strlen)(tmp_str)) {
4875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
4876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "--hg-sanity-flags argument must have 6 digits\n");
4877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
4878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = 0; j < 6; j++) {
4880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if      ('0' == tmp_str[j]) { /* do nothing */ }
4881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
4882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
4883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can "
4884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     "only contain 0s and 1s\n");
4885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) VG_(printf)("XXX sanity flags: 0x%lx\n", HG_(clo_sanity_flags));
4889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4891b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if VG_BOOL_CLO(arg, "--free-is-write",
4892b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            HG_(clo_free_is_write)) {}
4893b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4894b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if VG_XACT_CLO(arg, "--vts-pruning=never",
4895b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            HG_(clo_vts_pruning), 0);
4896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if VG_XACT_CLO(arg, "--vts-pruning=auto",
4897b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            HG_(clo_vts_pruning), 1);
4898b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if VG_XACT_CLO(arg, "--vts-pruning=always",
4899b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            HG_(clo_vts_pruning), 2);
4900b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4901b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if VG_BOOL_CLO(arg, "--check-stack-refs",
4902b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            HG_(clo_check_stack_refs)) {}
4903b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
4904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
4905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VG_(replacement_malloc_process_cmd_line_option)(arg);
4906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
4908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_print_usage ( void )
4911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
4913b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"    --free-is-write=no|yes    treat heap frees as writes [no]\n"
4914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --track-lockorders=no|yes show lock ordering errors? [yes]\n"
4915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --history-level=none|approx|full [full]\n"
4916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"       full:   show both stack traces for a data race (can be very slow)\n"
4917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"       approx: full trace for one thread, approx for the other (faster)\n"
4918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"       none:   only show trace for one thread in a race (fastest)\n"
4919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --conflict-cache-size=N   size of 'full' history cache [1000000]\n"
4920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"    --check-stack-refs=no|yes race-check reads and writes on the\n"
4921b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"                              main stack and thread stacks? [yes]\n"
4922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
4923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_print_debug_usage ( void )
4926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("    --cmp-race-err-addrs=no|yes  are data addresses in "
4928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "race errors significant? [no]\n");
4929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("    --hg-sanity-flags=<XXXXXX>   sanity check "
4930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "  at events (X = 0|1) [000000]\n");
4931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("    --hg-sanity-flags values:\n");
4932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("       010000   after changes to "
4933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "lock-order-acquisition-graph\n");
4934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("       001000   at memory accesses (NB: not currently used)\n");
4935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("       000100   at mem permission setting for "
4936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "ranges >= %d bytes\n", SCE_BIGRANGE_T);
4937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("       000010   at lock/unlock events\n");
4938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("       000001   at thread create/join events\n");
4939b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(printf)(
4940b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"    --vts-pruning=never|auto|always [auto]\n"
4941b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"       never:   is never done (may cause big space leaks in Helgrind)\n"
4942b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"       auto:    done just often enough to keep space usage under control\n"
4943b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov"       always:  done after every VTS GC (mostly just a big time waster)\n"
4944b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    );
4945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void hg_fini ( Int exitcode )
4948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
4950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg,
4951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "For counts of detected and suppressed errors, "
4952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "rerun with: -v\n");
4953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)
4956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && HG_(clo_history_level) >= 2) {
4957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)(
4958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "Use --history-level=approx or =none to gain increased speed, at\n" );
4959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)(
4960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "the cost of reduced accuracy of conflicting-access information\n");
4961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (SHOW_DATA_STRUCTURES)
4964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_everything( PP_ALL, "SK_(fini)" );
4965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (HG_(clo_sanity_flags))
4966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all__sanity_check("SK_(fini)");
4967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_stats)) {
4969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (1) {
4971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("\n");
4972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HG_(ppWSUstats)( univ_lsets, "univ_lsets" );
4973b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (HG_(clo_track_lockorders)) {
4974b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("\n");
4975b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            HG_(ppWSUstats)( univ_laog,  "univ_laog" );
4976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
4977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)("\n");
4980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu queries\n",        stats__hbefore_queries);
4981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu cache 0 hits\n",   stats__hbefore_cache0s);
4982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu cache > 0 hits\n", stats__hbefore_cacheNs);
4983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu graph searches\n", stats__hbefore_gsearches);
4984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu   of which slow\n",
4985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz                   stats__hbefore_gsearches - stats__hbefore_gsearchFs);
4986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu stack high water mark\n",
4987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz                   stats__hbefore_stk_hwm);
4988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu cache invals\n",   stats__hbefore_invals);
4989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //zz       VG_(printf)(" hbefore: %'10lu probes\n",         stats__hbefore_probes);
4990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
4992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("        locksets: %'8d unique lock sets\n",
4993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)HG_(cardinalityWSU)( univ_lsets ));
4994b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (HG_(clo_track_lockorders)) {
4995b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(printf)("       univ_laog: %'8d unique lock sets\n",
4996b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     (Int)HG_(cardinalityWSU)( univ_laog ));
4997b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
4998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //VG_(printf)("L(ast)L(ock) map: %'8lu inserts (%d map size)\n",
5000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //            stats__ga_LL_adds,
5001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //            (Int)(ga_to_lastlock ? VG_(sizeFM)( ga_to_lastlock ) : 0) );
5002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("  LockN-to-P map: %'8llu queries (%llu map size)\n",
5004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  HG_(stats__LockN_to_P_queries),
5005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  HG_(stats__LockN_to_P_get_map_size)() );
5006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("string table map: %'8llu queries (%llu map size)\n",
5008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  HG_(stats__string_table_queries),
5009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  HG_(stats__string_table_get_map_size)() );
5010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (HG_(clo_track_lockorders)) {
5011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(printf)("            LAOG: %'8d map size\n",
5012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     (Int)(laog ? VG_(sizeFM)( laog ) : 0));
5013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(printf)(" LAOG exposition: %'8d map size\n",
5014b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     (Int)(laog_exposition ? VG_(sizeFM)( laog_exposition ) : 0));
5015b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
5016b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("           locks: %'8lu acquires, "
5018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "%'lu releases\n",
5019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  stats__lockN_acquires,
5020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  stats__lockN_releases
5021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
5022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("   sanity checks: %'8lu\n", stats__sanity_checks);
5023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
5025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      libhb_shutdown(True);
5026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* FIXME: move these somewhere sane */
5030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid for_libhb__get_stacktrace ( Thr* hbt, Addr* frames, UWord nRequest )
5033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*     thr;
5035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId    tid;
5036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord       nActual;
5037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbt);
5038b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   thr = libhb_get_Thr_hgthread( hbt );
5039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr);
5040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tid = map_threads_maybe_reverse_lookup_SLOW(thr);
5041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nActual = (UWord)VG_(get_StackTrace)( tid, frames, (UInt)nRequest,
5042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         NULL, NULL, 0 );
5043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(nActual <= nRequest);
5044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (; nActual < nRequest; nActual++)
5045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      frames[nActual] = 0;
5046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownExeContext* for_libhb__get_EC ( Thr* hbt )
5050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thread*     thr;
5052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId    tid;
5053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ExeContext* ec;
5054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(hbt);
5055b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   thr = libhb_get_Thr_hgthread( hbt );
5056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr);
5057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tid = map_threads_maybe_reverse_lookup_SLOW(thr);
5058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* this will assert if tid is invalid */
5059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ec = VG_(record_ExeContext)( tid, 0 );
5060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ec;
5061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5064b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void hg_post_clo_init ( void )
5065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thr* hbthr_root;
5067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5068b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /////////////////////////////////////////////
5069b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   hbthr_root = libhb_init( for_libhb__get_stacktrace,
5070b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            for_libhb__get_EC );
5071b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /////////////////////////////////////////////
5072b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5073b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5074b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (HG_(clo_track_lockorders))
5075b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      laog__init();
5076b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5077b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   initialise_data_structures(hbthr_root);
5078b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
5079b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5080b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void hg_pre_clo_init ( void )
5081b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
5082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_name)            ("Helgrind");
5083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_version)         (NULL);
5084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_description)     ("a thread error detector");
5085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_copyright_author)(
5086b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      "Copyright (C) 2007-2011, and GNU GPL'd, by OpenWorks LLP et al.");
5087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_bug_reports_to)  (VG_BUGS_TO);
5088b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(details_avg_translation_sizeB) ( 320 );
5089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(basic_tool_funcs)          (hg_post_clo_init,
5091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_instrument,
5092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_fini);
5093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_core_errors)         ();
5095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_tool_errors)         (HG_(eq_Error),
5096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(before_pp_Error),
5097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(pp_Error),
5098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   False,/*show TIDs for errors*/
5099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(update_extra),
5100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(recognised_suppression),
5101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(read_extra_suppression_info),
5102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(error_matches_suppression),
5103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(get_error_name),
5104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(get_extra_suppression_info));
5105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_xml_output)          ();
5107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_command_line_options)(hg_process_cmd_line_option,
5109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_print_usage,
5110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_print_debug_usage);
5111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_client_requests)     (hg_handle_client_request);
5112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME?
5114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //VG_(needs_sanity_checks)       (hg_cheap_sanity_check,
5115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //                                hg_expensive_sanity_check);
5116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_malloc_replacement)  (hg_cli__malloc,
5118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli____builtin_new,
5119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli____builtin_vec_new,
5120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli__memalign,
5121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli__calloc,
5122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli__free,
5123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli____builtin_delete,
5124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli____builtin_vec_delete,
5125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli__realloc,
5126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   hg_cli_malloc_usable_size,
5127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_CLI__MALLOC_REDZONE_SZB );
5128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 21 Dec 08: disabled this; it mostly causes H to start more
5130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      slowly and use significantly more memory, without very often
5131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      providing useful results.  The user can request to load this
5132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      information manually with --read-var-info=yes. */
5133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(needs_var_info)(); /* optional */
5134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_new_mem_startup)     ( evh__new_mem_w_perms );
5136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_new_mem_stack_signal)( evh__new_mem_w_tid );
5137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_new_mem_brk)         ( evh__new_mem_w_tid );
5138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_new_mem_mmap)        ( evh__new_mem_w_perms );
5139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_new_mem_stack)       ( evh__new_mem_stack );
5140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: surely this isn't thread-aware
5142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_copy_mem_remap)      ( evh__copy_mem );
5143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_change_mem_mprotect) ( evh__set_perms );
5145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_die_mem_stack_signal)( evh__die_mem );
5147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(track_die_mem_brk)         ( evh__die_mem_munmap );
5148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(track_die_mem_munmap)      ( evh__die_mem_munmap );
5149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_die_mem_stack)       ( evh__die_mem );
5150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: what is this for?
5152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_ban_mem_stack)       (NULL);
5153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_pre_mem_read)        ( evh__pre_mem_read );
5155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_pre_mem_read_asciiz) ( evh__pre_mem_read_asciiz );
5156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_pre_mem_write)       ( evh__pre_mem_write );
5157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_post_mem_write)      (NULL);
5158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////
5160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
5162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_pre_thread_ll_exit)  ( evh__pre_thread_ll_exit );
5163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_start_client_code)( evh__start_client_code );
5165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_stop_client_code)( evh__stop_client_code );
5166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ensure that requirements for "dodgy C-as-C++ style inheritance"
5168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      as described in comments at the top of pub_tool_hashtable.h, are
5169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      met.  Blargh. */
5170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( sizeof(void*) == sizeof(struct _MallocMeta*) );
5171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( sizeof(UWord) == sizeof(Addr) );
5172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hg_mallocmeta_table
5173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = VG_(HT_construct)( "hg_malloc_metadata_table" );
5174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5175f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   // add a callback to clean up on (threaded) fork.
5176f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   VG_(atfork)(NULL/*pre*/, NULL/*parent*/, evh__atfork_child/*child*/);
5177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
5180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                hg_main.c ---*/
5183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5184