1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Thread scheduling.                               scheduler.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2000-2011 Julian Seward
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Overview
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Valgrind tries to emulate the kernel's threading as closely as
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   possible.  The client does all threading via the normal syscalls
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (on Linux: clone, etc).  Valgrind emulates this by creating exactly
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the same process structure as would be created without Valgrind.
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are no extra threads.
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The main difference is that Valgrind only allows one client thread
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to run at once.  This is controlled with the CPU Big Lock,
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "the_BigLock".  Any time a thread wants to run client code or
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   manipulate any shared state (which is anything other than its own
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState entry), it must hold the_BigLock.
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When a thread is about to block in a blocking syscall, it releases
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the_BigLock, and re-takes it when it becomes runnable again (either
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   because the syscall finished, or we took a signal).
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(scheduler) therefore runs in each thread.  It returns only when
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the thread is exiting, either because it exited itself, or it was
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   told to exit by another thread.
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is almost entirely OS-independent.  The details of how
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the OS handles threading and signalling are abstracted away and
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implemented elsewhere.  [Some of the functions have worked their
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   way back for the moment, until we do an OS port in earnest...]
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h"
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vkiscnums.h"    // __NR_sched_yield
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h"   // to keep _threadstate.h happy
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clreq.h"         // for VG_USERREQ__*
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_dispatch.h"
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_errormgr.h"      // For VG_(get_n_errs_found)()
70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_gdbserver.h"     // for VG_(gdbserver) and VG_(gdbserver_activity)
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcsignal.h"
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mach.h"
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h"
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_replacemalloc.h"
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_signals.h"
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacks.h"
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacktrace.h"    // For VG_(get_and_pp_StackTrace)()
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h"
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syswrap.h"
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_translate.h"     // For VG_(translate)()
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_transtab.h"
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h"     // VG_(di_notify_pdb_debuginfo)
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_sema.h"
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_scheduler.h"     // self
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_redir.h"
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Types and globals for the scheduler.
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ThreadId and ThreadState are defined elsewhere*/
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Defines the thread-scheduling timeslice, in terms of the number of
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   basic blocks we attempt to run each thread for.  Smaller values
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   give finer interleaving but much increased scheduling overheads. */
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SCHEDULING_QUANTUM   100000
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* If False, a fault is Valgrind-internal (ie, a bug) */
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(in_generated_code) = False;
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Counts downwards in VG_(run_innerloop). */
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(dispatch_ctr);
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 64-bit counter for the number of basic blocks done. */
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong bbs_done = 0;
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Counter to see if vgdb activity is to be verified.
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   When nr of bbs done reaches vgdb_next_poll, scheduler will
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   poll for gdbserver activity. VG_(force_vgdb_poll) and
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(disable_vgdb_poll) allows the valgrind core (e.g. m_gdbserver)
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   to control when the next poll will be done. */
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic ULong vgdb_next_poll;
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Forwards */
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_client_request ( ThreadId tid );
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void scheduler_sanity ( ThreadId tid );
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mostly_clear_thread_record ( ThreadId tid );
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Stats. */
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_scheduling_events_MINOR = 0;
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_scheduling_events_MAJOR = 0;
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sanity checking counts. */
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt sanity_fast_count = 0;
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt sanity_slow_count = 0;
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(print_scheduler_stats)(void)
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "scheduler: %'llu jumps (bb entries).\n", bbs_done );
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "scheduler: %'llu/%'llu major/minor sched events.\n",
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_scheduling_events_MAJOR, n_scheduling_events_MINOR);
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                "   sanity: %d cheap, %d expensive checks.\n",
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sanity_fast_count, sanity_slow_count );
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CPU semaphore, so that threads can run exclusively */
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic vg_sema_t the_BigLock;
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Base address of the NaCl sandbox.
153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovUWord nacl_head;
154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Path to NaCl nexe.
156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovchar *nacl_file;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Helper functions for the scheduler.
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid print_sched_event ( ThreadId tid, Char* what )
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg, "  SCHED[%d]: %s\n", tid, what );
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* For showing SB counts, if the user asks to see them. */
169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define SHOW_SBCOUNT_EVERY (20ULL * 1000 * 1000)
170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic ULong bbs_done_lastcheck = 0;
171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
172b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid maybe_show_sb_counts ( void )
174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Long delta = bbs_done - bbs_done_lastcheck;
176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(delta >= 0);
177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (UNLIKELY(delta >= SHOW_SBCOUNT_EVERY)) {
178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("%'lld superblocks executed\n", bbs_done);
179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      bbs_done_lastcheck = bbs_done;
180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* name_of_sched_event ( UInt event )
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (event) {
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_SYSCALL:   return "SYSCALL";
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT32:     return "INT32";
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT128:    return "INT128";
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT129:    return "INT129";
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT130:    return "INT130";
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_SYSENTER:  return "SYSENTER";
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_CLIENTREQ:     return "CLIENTREQ";
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_YIELD:         return "YIELD";
195f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      case VEX_TRC_JMP_YIELD_NOREDIR: return "YIELD_NOREDIR";
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_NODECODE:      return "NODECODE";
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_MAPFAIL:       return "MAPFAIL";
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_NOREDIR:       return "NOREDIR";
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_EMWARN:        return "EMWARN";
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_TINVAL:        return "TINVAL";
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INVARIANT_FAILED:   return "INVFAILED";
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INNER_COUNTERZERO:  return "COUNTERZERO";
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INNER_FASTMISS:     return "FASTMISS";
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_FAULT_SIGNAL:       return "FAULTSIGNAL";
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:                        return "??UNKNOWN??";
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate a completely empty ThreadState record. */
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownThreadId VG_(alloc_ThreadState) ( void )
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < VG_N_THREADS; i++) {
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(threads)[i].status == VgTs_Empty) {
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(threads)[i].status = VgTs_Init;
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(threads)[i].exitreason = VgSrc_None;
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return i;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(core_panic)("VG_N_THREADS is too low");
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Mark a thread as Runnable.  This will block until the_BigLock is
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   available, so that we get exclusive access to all the shared
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   structures and the CPU.  Up until we get the_BigLock, we must not
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   touch any shared state.
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   When this returns, we'll actually be running.
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(acquire_BigLock)(ThreadId tid, HChar* who)
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst;
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if 0
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched)) {
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar buf[100];
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(VG_(strlen)(who) <= 100-50);
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(buf, "waiting for lock (%s)", who);
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, buf);
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First, acquire the_BigLock.  We can't do anything else safely
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prior to this point.  Even doing debug printing prior to this
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      point is, technically, wrong. */
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_down)(&the_BigLock, False/*not LL*/);
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->status != VgTs_Runnable);
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->status = VgTs_Runnable;
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(running_tid) != VG_INVALID_THREADID)
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("tid %d found %d running\n", tid, VG_(running_tid));
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(running_tid) == VG_INVALID_THREADID);
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(running_tid) = tid;
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { Addr gsp = VG_(get_SP)(tid);
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(unknown_SP_update)(gsp, gsp, 0/*unknown origin*/);
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched)) {
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar buf[150];
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(VG_(strlen)(who) <= 150-50);
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(buf, " acquired lock (%s)", who);
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, buf);
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Set a thread into a sleeping state, and give up exclusive access to
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the CPU.  On return, the thread must be prepared to block until it
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is ready to run again (generally this means blocking in a syscall,
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but it may mean that we remain in a Runnable state and we're just
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   yielding the CPU to another thread).
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(release_BigLock)(ThreadId tid, ThreadStatus sleepstate, HChar* who)
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst = VG_(get_ThreadState)(tid);
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->status == VgTs_Runnable);
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sleepstate == VgTs_WaitSys ||
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     sleepstate == VgTs_Yielding);
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->status = sleepstate;
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(running_tid) == tid);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(running_tid) = VG_INVALID_THREADID;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched)) {
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char buf[200];
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(VG_(strlen)(who) <= 200-100);
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(buf, "releasing lock (%s) -> %s",
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        who, VG_(name_of_ThreadStatus)(sleepstate));
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, buf);
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Release the_BigLock; this will reschedule any runnable
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread. */
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_up)(&the_BigLock, False/*not LL*/);
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* See pub_core_scheduler.h for description */
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(acquire_BigLock_LL) ( HChar* who )
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ML_(sema_down)(&the_BigLock, True/*LL*/);
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* See pub_core_scheduler.h for description */
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(release_BigLock_LL) ( HChar* who )
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_up)(&the_BigLock, True/*LL*/);
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Clear out the ThreadState and release the semaphore. Leaves the
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState in VgTs_Zombie state, so that it doesn't get
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reallocated until the caller is really ready. */
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(exit_thread)(ThreadId tid)
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_exiting)(tid));
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mostly_clear_thread_record(tid);
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(running_tid) = VG_INVALID_THREADID;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There should still be a valid exitreason for this thread */
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(threads)[tid].exitreason != VgSrc_None);
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched))
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, "release lock in VG_(exit_thread)");
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_up)(&the_BigLock, False/*not LL*/);
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* If 'tid' is blocked in a syscall, send it SIGVGKILL so as to get it
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   out of the syscall and onto doing the next thing, whatever that is.
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If it isn't blocked in a syscall, has no effect on the thread. */
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(get_thread_out_of_syscall)(ThreadId tid)
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!VG_(is_running_thread)(tid));
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(threads)[tid].status == VgTs_WaitSys) {
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals)) {
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(message)(Vg_DebugMsg,
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "get_thread_out_of_syscall zaps tid %d lwp %d\n",
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      tid, VG_(threads)[tid].os_state.lwpid);
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     if defined(VGO_darwin)
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme use mach primitives on darwin?
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme thread_abort_safely?
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme race for thread with WaitSys set but not in syscall yet?
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         extern kern_return_t thread_abort(mach_port_t);
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thread_abort(VG_(threads)[tid].os_state.lwpid);
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     else
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         __attribute__((unused))
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int r = VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VG_SIGVGKILL);
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* JRS 2009-Mar-20: should we assert for r==0 (tkill succeeded)?
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            I'm really not sure.  Here's a race scenario which argues
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that we shoudn't; but equally I'm not sure the scenario is
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            even possible, because of constraints caused by the question
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            of who holds the BigLock when.
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Target thread tid does sys_read on a socket and blocks.  This
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            function gets called, and we observe correctly that tid's
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            status is WaitSys but then for whatever reason this function
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goes very slowly for a while.  Then data arrives from
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wherever, tid's sys_read returns, tid exits.  Then we do
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tkill on tid, but tid no longer exists; tkill returns an
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            error code and the assert fails. */
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* vg_assert(r == 0); */
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     endif
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Yield the CPU for a short time to let some other thread run.
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(vg_yield)(void)
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid = VG_(running_tid);
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid != VG_INVALID_THREADID);
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(threads)[tid].os_state.lwpid == VG_(gettid)());
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(release_BigLock)(tid, VgTs_Yielding, "VG_(vg_yield)");
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Tell the kernel we're yielding.
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(do_syscall0)(__NR_sched_yield);
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(acquire_BigLock)(tid, "VG_(vg_yield)");
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the standard set of blocked signals, used whenever we're not
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   running a client syscall. */
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void block_signals(void)
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t mask;
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigfillset)(&mask);
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Don't block these because they're synchronous */
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGSEGV);
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGBUS);
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGFPE);
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGILL);
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGTRAP);
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Can't block these anyway */
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGSTOP);
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(&mask, VKI_SIGKILL);
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void os_state_clear(ThreadState *tst)
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.lwpid       = 0;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.threadgroup = 0;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* no other fields to clear */
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.post_mach_trap_fn = NULL;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.pthread           = 0;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.func_arg          = 0;
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&tst->os_state.child_go, 0, sizeof(tst->os_state.child_go));
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&tst->os_state.child_done, 0, sizeof(tst->os_state.child_done));
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.wq_jmpbuf_valid   = False;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.remote_port       = 0;
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.msgh_id           = 0;
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&tst->os_state.mach_args, 0, sizeof(tst->os_state.mach_args));
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void os_state_init(ThreadState *tst)
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.valgrind_stack_base    = 0;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.valgrind_stack_init_SP = 0;
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   os_state_clear(tst);
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid mostly_clear_thread_record ( ThreadId tid )
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t savedmask;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 0 && tid < VG_N_THREADS);
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(cleanup_thread)(&VG_(threads)[tid].arch);
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].tid = tid;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Leave the thread in Zombie, so that it doesn't get reallocated
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      until the caller is finally done with the thread stack. */
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].status               = VgTs_Zombie;
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigemptyset)(&VG_(threads)[tid].tmp_sig_mask);
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   os_state_clear(&VG_(threads)[tid]);
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* start with no altstack */
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].altstack.ss_sp = (void *)0xdeadbeef;
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].altstack.ss_size = 0;
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].altstack.ss_flags = VKI_SS_DISABLE;
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(clear_out_queued_signals)(tid, &savedmask);
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid].sched_jmpbuf_valid = False;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Called in the child after fork.  If the parent has multiple
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   threads, then we've inherited a VG_(threads) array describing them,
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but only the thread which called fork() is actually alive in the
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   child.  This functions needs to clean up all those other thread
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   structures.
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Whichever tid in the parent which called fork() becomes the
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   master_tid in the child.  That's because the only living slot in
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads) in the child after fork is VG_(threads)[tid], and it
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   would be too hard to try to re-number the thread and relocate the
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread state down to VG_(threads)[1].
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This function also needs to reinitialize the_BigLock, since
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   otherwise we may end up sharing its state with the parent, which
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   would be deeply confusing.
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sched_fork_cleanup(ThreadId me)
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid;
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(running_tid) == me);
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_darwin)
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme hack reset Mach ports
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(mach_init)();
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[me].os_state.lwpid = VG_(gettid)();
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* clear out all the unused thread slots */
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (tid = 1; tid < VG_N_THREADS; tid++) {
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (tid != me) {
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mostly_clear_thread_record(tid);
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(threads)[tid].status = VgTs_Empty;
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(clear_syscallInfo)(tid);
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* re-init and take the sema */
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_deinit)(&the_BigLock);
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_init)(&the_BigLock);
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_down)(&the_BigLock, False/*not LL*/);
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* First phase of initialisation of the scheduler.  Initialise the
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bigLock, zeroise the VG_(threads) structure and decide on the
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId of the root thread.
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownThreadId VG_(scheduler_init_phase1) ( void )
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid_main;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(1,"sched","sched_init_phase1\n");
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sema_init)(&the_BigLock);
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Paranoia .. completely zero it out. */
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memset)( & VG_(threads)[i], 0, sizeof( VG_(threads)[i] ) );
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[i].sig_queue = NULL;
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      os_state_init(&VG_(threads)[i]);
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mostly_clear_thread_record(i);
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[i].status                    = VgTs_Empty;
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[i].client_stack_szB          = 0;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[i].client_stack_highest_word = (Addr)NULL;
558b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(threads)[i].err_disablement_level     = 0;
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tid_main = VG_(alloc_ThreadState)();
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bleh.  Unfortunately there are various places in the system that
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assume that the main thread has a ThreadId of 1.
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - Helgrind (possibly)
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - stack overflow message in default_action() in m_signals.c
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - definitely a lot more places
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid_main == 1);
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tid_main;
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Second phase of initialisation of the scheduler.  Given the root
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId computed by first phase of initialisation, fill in stack
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   details and acquire bigLock.  Initialise the scheduler.  This is
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   called at startup.  The caller subsequently initialises the guest
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   state components of this main thread.
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(scheduler_init_phase2) ( ThreadId tid_main,
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Addr     clstack_end,
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  SizeT    clstack_size )
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(1,"sched","sched_init_phase2: tid_main=%d, "
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "cls_end=0x%lx, cls_sz=%ld\n",
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   tid_main, clstack_end, clstack_size);
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(clstack_size));
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid_main].client_stack_highest_word
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = clstack_end + 1 - sizeof(UWord);
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(threads)[tid_main].client_stack_szB
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = clstack_size;
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(atfork)(NULL, NULL, sched_fork_cleanup);
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Helpers for running translations.
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Use gcc's built-in setjmp/longjmp.  longjmp must not restore signal
606b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   mask state, but does need to pass "val" through.  jumped must be a
607b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   volatile UWord. */
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SCHEDSETJMP(tid, jumped, stmt)					\
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do {									\
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ThreadState * volatile _qq_tst = VG_(get_ThreadState)(tid);	\
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown									\
612b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (jumped) = VG_MINIMAL_SETJMP(_qq_tst->sched_jmpbuf);              \
613b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if ((jumped) == ((UWord)0)) {                                     \
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(!_qq_tst->sched_jmpbuf_valid);			\
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 _qq_tst->sched_jmpbuf_valid = True;				\
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 stmt;								\
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }	else if (VG_(clo_trace_sched))					\
618b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	 VG_(printf)("SCHEDSETJMP(line %d) tid %d, jumped=%ld\n",       \
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     __LINE__, tid, jumped);                            \
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(_qq_tst->sched_jmpbuf_valid);				\
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      _qq_tst->sched_jmpbuf_valid = False;				\
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while(0)
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do various guest state alignment checks prior to running a thread.
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Specifically, check that what we have matches Vex's guest state
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout requirements.  See libvex.h for details, but in short the
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   requirements are: There must be no holes in between the primary
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest state, its two copies, and the spill area.  In short, all 4
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   areas must have a 16-aligned size and be 16-aligned, and placed
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   back-to-back. */
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_pre_run_checks ( ThreadState* tst )
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr a_vex     = (Addr) & tst->arch.vex;
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr a_vexsh1  = (Addr) & tst->arch.vex_shadow1;
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr a_vexsh2  = (Addr) & tst->arch.vex_shadow2;
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr a_spill   = (Addr) & tst->arch.vex_spill;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt sz_vex    = (UInt) sizeof tst->arch.vex;
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt sz_vexsh1 = (UInt) sizeof tst->arch.vex_shadow1;
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt sz_vexsh2 = (UInt) sizeof tst->arch.vex_shadow2;
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt sz_spill  = (UInt) sizeof tst->arch.vex_spill;
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("gst %p %d, sh1 %p %d, "
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "sh2 %p %d, spill %p %d\n",
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)a_vex, sz_vex,
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)a_vexsh1, sz_vexsh1,
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)a_vexsh2, sz_vexsh2,
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)a_spill, sz_spill );
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sz_vex));
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sz_vexsh1));
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sz_vexsh2));
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sz_spill));
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(a_vex));
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(a_vexsh1));
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(a_vexsh2));
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(a_spill));
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check that the guest state and its two shadows have the same
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size, and that there are no holes in between.  The latter is
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      important because Memcheck assumes that it can reliably access
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the shadows by indexing off a pointer to the start of the
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      primary guest state area. */
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sz_vex == sz_vexsh1);
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sz_vex == sz_vexsh2);
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(a_vex + 1 * sz_vex == a_vexsh1);
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(a_vex + 2 * sz_vex == a_vexsh2);
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Also check there's no hole between the second shadow area and
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the spill area. */
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sz_spill == LibVEX_N_SPILL_BYTES);
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(a_vex + 3 * sz_vex == a_spill);
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_amd64)
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* x86/amd64 XMM regs must form an array, ie, have no
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      holes in between. */
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (offsetof(VexGuestAMD64State,guest_XMM16)
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       - offsetof(VexGuestAMD64State,guest_XMM0))
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      == (17/*#regs*/-1) * 16/*bytes per reg*/
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_ppc32) || defined(VGA_ppc64)
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ppc guest_state vector regs must be 16 byte aligned for
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      loads/stores.  This is important! */
688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex.guest_VSR0));
689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex_shadow1.guest_VSR0));
690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex_shadow2.guest_VSR0));
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* be extra paranoid .. */
692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex.guest_VSR1));
693b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex_shadow1.guest_VSR1));
694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(VG_IS_16_ALIGNED(& tst->arch.vex_shadow2.guest_VSR1));
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_arm)
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* arm guest_state VFP regs must be 8 byte aligned for
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      loads/stores. */
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex.guest_D0));
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex_shadow1.guest_D0));
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex_shadow2.guest_D0));
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* be extra paranoid .. */
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex.guest_D1));
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex_shadow1.guest_D1));
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_8_ALIGNED(& tst->arch.vex_shadow2.guest_D1));
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
708b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
709b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGA_s390x)
710b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* no special requirements */
711b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
714b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// NO_VGDB_POLL value ensures vgdb is not polled, while
715b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// VGDB_POLL_ASAP ensures that the next scheduler call
716b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// will cause a poll.
717b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define NO_VGDB_POLL    0xffffffffffffffffULL
718b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define VGDB_POLL_ASAP  0x0ULL
719b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
720b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid VG_(disable_vgdb_poll) (void )
721b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
722b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vgdb_next_poll = NO_VGDB_POLL;
723b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
724b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid VG_(force_vgdb_poll) ( void )
725b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
726b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vgdb_next_poll = VGDB_POLL_ASAP;
727b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Run the thread tid for a while, and return a VG_TRC_* value
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   indicating why VG_(run_innerloop) stopped. */
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt run_thread_for_a_while ( ThreadId tid )
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
733b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   volatile UWord        jumped;
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile ThreadState* tst = NULL; /* stop gcc complaining */
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile UInt         trc;
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile Int          dispatch_ctr_SAVED;
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile Int          done_this_time;
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Paranoia */
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!VG_(is_exiting)(tid));
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_pre_run_checks( (ThreadState*)tst );
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* end Paranoia */
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   trc = 0;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dispatch_ctr_SAVED = VG_(dispatch_ctr);
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* there should be no undealt-with signals */
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //vg_assert(VG_(threads)[tid].siginfo.si_signo == 0);
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) {
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vki_sigset_t m;
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int i, err = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &m);
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(err == 0);
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("tid %d: entering code with unblocked signals: ", tid);
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 1; i <= _VKI_NSIG; i++)
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!VG_(sigismember)(&m, i))
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("%d ", i);
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Tell the tool this thread is about to run client code
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( start_client_code, tid, bbs_done );
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(in_generated_code) == False);
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(in_generated_code) = True;
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SCHEDSETJMP(
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid,
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jumped,
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      trc = (UInt)VG_(run_innerloop)( (void*)&tst->arch.vex,
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      VG_(clo_profile_flags) > 0 ? 1 : 0 )
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(in_generated_code) == True);
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(in_generated_code) = False;
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (jumped != (UWord)0) {
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We get here if the client took a fault that caused our signal
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         handler to longjmp. */
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(trc == 0);
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      trc = VG_TRC_FAULT_SIGNAL;
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      block_signals();
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 0;
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(done_this_time >= 0);
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbs_done += (ULong)done_this_time;
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Tell the tool this thread has stopped running client code
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( stop_client_code, tid, bbs_done );
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
797b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (bbs_done >= vgdb_next_poll) {
798b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (VG_(clo_vgdb_poll))
799b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vgdb_next_poll = bbs_done + (ULong)VG_(clo_vgdb_poll);
800b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      else
801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* value was changed due to gdbserver invocation via ptrace */
802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vgdb_next_poll = NO_VGDB_POLL;
803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (VG_(gdbserver_activity) (tid))
804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(gdbserver) (tid);
805b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
806b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return trc;
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Run a no-redir translation just once, and return the resulting
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRC_* value. */
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt run_noredir_translation ( Addr hcode, ThreadId tid )
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
815b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   volatile UWord        jumped;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile ThreadState* tst;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile UWord        argblock[4];
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   volatile UInt         retval;
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Paranoia */
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!VG_(is_exiting)(tid));
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_pre_run_checks( (ThreadState*)tst );
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* end Paranoia */
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_ppc32) || defined(VGA_ppc64)
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* I don't think we need to clear this thread's guest_RESVN here,
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      because we can only get here if run_thread_for_a_while() has
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been used immediately before, on this same thread. */
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There can be 3 outcomes from VG_(run_a_noredir_translation):
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - a signal occurred and the sighandler longjmp'd.  Then both [2]
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        and [3] are unchanged - hence zero.
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - translation ran normally, set [2] (next guest IP) and set [3]
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        to whatever [1] was beforehand, indicating a normal (boring)
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        jump to the next block.
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - translation ran normally, set [2] (next guest IP) and set [3]
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        to something different from [1] beforehand, which indicates a
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TRC_ value.
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argblock[0] = (UWord)hcode;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argblock[1] = (UWord)&VG_(threads)[tid].arch.vex;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argblock[2] = 0; /* next guest IP is written here */
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argblock[3] = 0; /* guest state ptr afterwards is written here */
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Tell the tool this thread is about to run client code
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( start_client_code, tid, bbs_done );
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(in_generated_code) == False);
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(in_generated_code) = True;
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SCHEDSETJMP(
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid,
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jumped,
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(run_a_noredir_translation)( &argblock[0] )
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(in_generated_code) = False;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (jumped != (UWord)0) {
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We get here if the client took a fault that caused our signal
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         handler to longjmp. */
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(argblock[2] == 0); /* next guest IP was not written */
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(argblock[3] == 0); /* trc was not written */
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      block_signals();
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      retval = VG_TRC_FAULT_SIGNAL;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* store away the guest program counter */
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(set_IP)( tid, argblock[2] );
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (argblock[3] == argblock[1])
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* the guest state pointer afterwards was unchanged */
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         retval = VG_TRC_BORING;
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         retval = (UInt)argblock[3];
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbs_done++;
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Tell the tool this thread has stopped running client code
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( stop_client_code, tid, bbs_done );
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return retval;
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The scheduler proper.
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void handle_tt_miss ( ThreadId tid )
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool found;
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr ip = VG_(get_IP)(tid);
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Trivial event.  Miss in the fast-cache.  Do a full
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lookup for it. */
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   found = VG_(search_transtab)( NULL, ip, True/*upd_fast_cache*/ );
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(!found)) {
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Not found; we need to request a translation. */
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(translate)( tid, ip, /*debug*/False, 0/*not verbose*/,
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          bbs_done, True/*allow redirection*/ )) {
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 found = VG_(search_transtab)( NULL, ip, True );
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert2(found, "VG_TRC_INNER_FASTMISS: missing tt_fast entry");
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // If VG_(translate)() fails, it's because it had to throw a
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // signal because the client jumped to a bad address.  That
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // means that either a signal has been set up for delivery,
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // or the thread has been marked for termination.  Either
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // way, we just need to go back into the scheduler loop.
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void handle_syscall(ThreadId tid, UInt trc)
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState * volatile tst = VG_(get_ThreadState)(tid);
925b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   volatile UWord jumped;
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Syscall may or may not block; either way, it will be
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      complete by the time this call returns, and we'll be
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      runnable again.  We could take a signal while the
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall runs. */
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_sanity_level >= 3))
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(am_do_sync_check)("(BEFORE SYSCALL)",__FILE__,__LINE__);
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid, trc));
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_sanity_level >= 3))
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(am_do_sync_check)("(AFTER SYSCALL)",__FILE__,__LINE__);
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!VG_(is_running_thread)(tid))
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("tid %d not running; VG_(running_tid)=%d, tid %d status %d\n",
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  tid, VG_(running_tid), tid, tst->status);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (jumped != (UWord)0) {
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      block_signals();
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(poll_signals)(tid);
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* tid just requested a jump to the noredir version of its current
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   program counter.  So make up that translation if needed, run it,
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and return the resulting thread return code. */
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt/*trc*/ handle_noredir_jump ( ThreadId tid )
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AddrH hcode = 0;
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr  ip    = VG_(get_IP)(tid);
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  found = VG_(search_unredir_transtab)( &hcode, ip );
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!found) {
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Not found; we need to request a translation. */
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(translate)( tid, ip, /*debug*/False, 0/*not verbose*/, bbs_done,
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          False/*NO REDIRECTION*/ )) {
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         found = VG_(search_unredir_transtab)( &hcode, ip );
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert2(found, "unredir translation missing after creation?!");
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // If VG_(translate)() fails, it's because it had to throw a
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // signal because the client jumped to a bad address.  That
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // means that either a signal has been set up for delivery,
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // or the thread has been marked for termination.  Either
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 // way, we just need to go back into the scheduler loop.
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VG_TRC_BORING;
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(found);
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(hcode != 0);
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Otherwise run it and return the resulting VG_TRC_* value. */
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return run_noredir_translation( hcode, tid );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Run a thread until it wants to exit.
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   We assume that the caller has already called VG_(acquire_BigLock) for
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   us, so we own the VCPU.  Also, all signals are blocked.
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVgSchedReturnCode VG_(scheduler) ( ThreadId tid )
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
995b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt     trc = VG_TRC_BORING;
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst = VG_(get_ThreadState)(tid);
997b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   static Bool vgdb_startup_action_done = False;
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched))
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, "entering VG_(scheduler)");
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1002b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Do vgdb initialization (but once). Only the first (main) task
1003b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      starting up will do the below.
1004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Initialize gdbserver earlier than at the first
1005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      thread VG_(scheduler) is causing problems:
1006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      * at the end of VG_(scheduler_init_phase2) :
1007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        The main thread is in VgTs_Init state, but in a not yet
1008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        consistent state => the thread cannot be reported to gdb
1009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        (e.g. causes an assert in LibVEX_GuestX86_get_eflags when giving
1010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        back the guest registers to gdb).
1011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      * at end of valgrind_main, just
1012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        before VG_(main_thread_wrapper_NORETURN)(1) :
1013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        The main thread is still in VgTs_Init state but in a
1014b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        more advanced state. However, the thread state is not yet
1015b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        completely initialized : a.o., the os_state is not yet fully
1016b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        set => the thread is then not properly reported to gdb,
1017b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        which is then confused (causing e.g. a duplicate thread be
1018b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        shown, without thread id).
1019b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      * it would be possible to initialize gdbserver "lower" in the
1020b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        call stack (e.g. in VG_(main_thread_wrapper_NORETURN)) but
1021b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        these are platform dependent and the place at which
1022b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        the thread state is completely initialized is not
1023b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        specific anymore to the main thread (so a similar "do it only
1024b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        once" would be needed).
1025b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1026b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        => a "once only" initialization here is the best compromise. */
1027b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!vgdb_startup_action_done) {
1028b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(tid == 1); // it must be the main thread.
1029b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vgdb_startup_action_done = True;
1030b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (VG_(clo_vgdb) != Vg_VgdbNo) {
1031b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* If we have to poll, ensures we do an initial poll at first
1032b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            scheduler call. Otherwise, ensure no poll (unless interrupted
1033b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            by ptrace). */
1034b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (VG_(clo_vgdb_poll))
1035b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(force_vgdb_poll) ();
1036b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1037b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(disable_vgdb_poll) ();
1038b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1039b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vg_assert (VG_(dyn_vgdb_error) == VG_(clo_vgdb_error));
1040b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* As we are initializing, VG_(dyn_vgdb_error) can't have been
1041b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            changed yet. */
1042b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1043b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(gdbserver_prerun_action) (1);
1044b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else {
1045b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(disable_vgdb_poll) ();
1046b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
1047b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1048b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* set the proper running signal mask */
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   block_signals();
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (!VG_(is_exiting)(tid)) {
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(dispatch_ctr) == 1) {
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Our slice is done, so yield the CPU to another thread.  On
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Linux, this doesn't sleep between sleeping and running,
1062b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            since that would take too much time. */
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* 4 July 06: it seems that a zero-length nsleep is needed to
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cause async thread cancellation (canceller.c) to terminate
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            in finite time; else it is in some kind of race/starvation
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            situation and completion is arbitrarily delayed (although
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            this is not a deadlock).
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Unfortunately these sleeps cause MPI jobs not to terminate
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sometimes (some kind of livelock).  So sleeping once
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            every N opportunities appears to work. */
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* 3 Aug 06: doing sys__nsleep works but crashes some apps.
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sys_yield also helps the problem, whilst not crashing apps. */
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(release_BigLock)(tid, VgTs_Yielding,
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   "VG_(scheduler):timeslice");
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* ------------ now we don't have The Lock ------------ */
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1081f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         VG_(do_syscall0)(__NR_sched_yield);
1082f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(acquire_BigLock)(tid, "VG_(scheduler):timeslice");
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* ------------ now we do have The Lock ------------ */
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* OK, do some relatively expensive housekeeping stuff */
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 scheduler_sanity(tid);
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(sanity_check_general)(False);
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Look for any pending signals for this thread, and set them up
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    for delivery */
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(poll_signals)(tid);
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (VG_(is_exiting)(tid))
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    break;		/* poll_signals picked up a fatal signal */
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* For stats purposes only. */
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 n_scheduling_events_MAJOR++;
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Figure out how many bbs to ask vg_run_innerloop to do.  Note
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    that it decrements the counter before testing it for zero, so
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    that if tst->dispatch_ctr is set to N you get at most N-1
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    iterations.  Also this means that tst->dispatch_ctr must
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    exceed zero before entering the innerloop.  Also also, the
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    decrement is done before the bb is actually run, so you
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    always get at least one decrement even if nothing happens. */
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* paranoia ... */
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(tst->tid == tid);
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(tst->os_state.lwpid == VG_(gettid)());
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* For stats purposes only. */
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_scheduling_events_MINOR++;
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs\n",
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   tid, VG_(dispatch_ctr) - 1 );
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1121f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      if (trc == VEX_TRC_JMP_YIELD_NOREDIR) {
1122f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov        trc = handle_noredir_jump(tid);
1123f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      } else {
1124f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov        trc = run_thread_for_a_while ( tid );
1125f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      }
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_sched) && VG_(clo_verbosity) > 2) {
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Char buf[50];
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(sprintf)(buf, "TRC: %s", name_of_sched_event(trc));
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 print_sched_event(tid, buf);
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (trc == VEX_TRC_JMP_NOREDIR) {
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If we got a request to run a no-redir version of
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            something, do so now -- handle_noredir_jump just (creates
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            and) runs that one translation.  The flip side is that the
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            noredir translation can't itself return another noredir
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            request -- that would be nonsensical.  It can, however,
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return VG_TRC_BORING, which just means keep going as
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            normal. */
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         trc = handle_noredir_jump(tid);
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(trc != VEX_TRC_JMP_NOREDIR);
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (trc) {
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_BORING:
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* no special event, just keep going. */
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INNER_FASTMISS:
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(VG_(dispatch_ctr) > 1);
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 handle_tt_miss(tid);
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_CLIENTREQ:
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 do_client_request(tid);
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT128:  /* x86-linux */
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT129:  /* x86-darwin */
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_INT130:  /* x86-darwin */
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_SYSCALL: /* amd64-linux, ppc32-linux, amd64-darwin */
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 handle_syscall(tid, trc);
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (VG_(clo_sanity_level) > 2)
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(sanity_check_general)(True); /* sanity-check every syscall */
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_YIELD:
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Explicit yield, because this thread is in a spin-lock
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    or something.  Only let the thread run for a short while
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            longer.  Because swapping to another thread is expensive,
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we're prepared to let this thread eat a little more CPU
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            before swapping to another.  That means that short term
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            spins waiting for hardware to poke memory won't cause a
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            thread swap. */
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (VG_(dispatch_ctr) > 2000)
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(dispatch_ctr) = 2000;
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1180f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      case VEX_TRC_JMP_YIELD_NOREDIR:
1181f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         VG_(dispatch_ctr) = 1;
1182f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         break;
1183f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INNER_COUNTERZERO:
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Timeslice is out.  Let a new thread be scheduled. */
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert(VG_(dispatch_ctr) == 1);
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_FAULT_SIGNAL:
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Everything should be set up (either we're exiting, or
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    about to start in a signal handler). */
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_MAPFAIL:
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Failure of arch-specific address translation (x86/amd64
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            segment override use) */
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* jrs 2005 03 11: is this correct? */
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(synth_fault)(tid);
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_EMWARN: {
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         static Int  counts[EmWarn_NUMBER];
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         static Bool counts_initted = False;
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VexEmWarn ew;
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar*    what;
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool      show;
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int       q;
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!counts_initted) {
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            counts_initted = True;
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (q = 0; q < EmWarn_NUMBER; q++)
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               counts[q] = 0;
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ew   = (VexEmWarn)VG_(threads)[tid].arch.vex.guest_EMWARN;
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         what = (ew < 0 || ew >= EmWarn_NUMBER)
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ? "unknown (?!)"
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : LibVEX_EmWarn_string(ew);
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         show = (ew < 0 || ew >= EmWarn_NUMBER)
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ? True
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : counts[ew]++ < 3;
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (show && VG_(clo_show_emwarns) && !VG_(clo_xml)) {
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_UserMsg,
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "Emulation warning: unsupported action:\n");
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_UserMsg, "  %s\n", what);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_EMFAIL: {
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VexEmWarn ew;
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar*    what;
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ew   = (VexEmWarn)VG_(threads)[tid].arch.vex.guest_EMWARN;
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         what = (ew < 0 || ew >= EmWarn_NUMBER)
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ? "unknown (?!)"
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : LibVEX_EmWarn_string(ew);
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_UserMsg,
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "Emulation fatal error -- Valgrind cannot continue:\n");
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_UserMsg, "  %s\n", what);
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "\n");
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "Valgrind has to exit now.  Sorry.\n");
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "\n");
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(exit)(1);
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SIGTRAP:
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(synth_sigtrap)(tid);
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SIGSEGV:
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(synth_fault)(tid);
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SIGBUS:
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(synth_sigbus)(tid);
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_NODECODE:
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(umsg)(
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "valgrind: Unrecognised instruction at address %#lx.\n",
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(get_IP)(tid));
1263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(get_and_pp_StackTrace)(tid, 50);
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define M(a) VG_(umsg)(a "\n");
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("Your program just tried to execute an instruction that Valgrind" );
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("did not recognise.  There are two possible reasons for this."    );
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("1. Your program has a bug and erroneously jumped to a non-code"  );
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("   location.  If you are running Memcheck and you just saw a"    );
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("   warning about a bad jump, it's probably your program's fault.");
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("2. The instruction is legitimate but Valgrind doesn't handle it,");
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("   i.e. it's Valgrind's fault.  If you think this is the case or");
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("   you are not sure, please let us know and we'll try to fix it.");
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("Either way, Valgrind will now raise a SIGILL signal which will"  );
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   M("probably kill your program."                                     );
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef M
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(synth_sigill)(tid, VG_(get_IP)(tid));
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_TINVAL:
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (Addr64)VG_(threads)[tid].arch.vex.guest_TISTART,
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(threads)[tid].arch.vex.guest_TILEN,
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "scheduler(VEX_TRC_JMP_TINVAL)"
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0)
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("dump translations done.\n");
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_TRC_INVARIANT_FAILED:
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This typically happens if, after running generated code,
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            it is detected that host CPU settings (eg, FPU/Vector
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            control words) are not as they should be.  Vex's code
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            generation specifies the state such control words should
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            be in on entry to Vex-generated code, and they should be
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged on exit from it.  Failure of this assertion
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            usually means a bug in Vex's code generation. */
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //{ UInt xx;
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //  __asm__ __volatile__ (
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //     "\t.word 0xEEF12A10\n"  // fmrx r2,fpscr
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //     "\tmov %0, r2" : "=r"(xx) : : "r2" );
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //  VG_(printf)("QQQQ new fpscr = %08x\n", xx);
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         //}
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert2(0, "VG_(scheduler), phase 3: "
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "run_innerloop detected host "
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "state invariant failure", trc);
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VEX_TRC_JMP_SYS_SYSENTER:
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do whatever simulation is appropriate for an x86 sysenter
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            instruction.  Note that it is critical to set this thread's
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            guest_EIP to point at the code to execute after the
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sysenter, since Vex-generated code will not have set it --
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex does not know what it should be.  Vex sets the next
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            address to zero, so if you don't set guest_EIP, the thread
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            will jump to zero afterwards and probably die as a result. */
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        if defined(VGP_x86_linux)
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert2(0, "VG_(scheduler), phase 3: "
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "sysenter_x86 on x86-linux is not supported");
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        elif defined(VGP_x86_darwin)
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* return address in client edx */
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(threads)[tid].arch.vex.guest_EIP
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = VG_(threads)[tid].arch.vex.guest_EDX;
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         handle_syscall(tid, trc);
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        else
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert2(0, "VG_(scheduler), phase 3: "
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "sysenter_x86 on non-x86 platform?!?!");
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        endif
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 vg_assert2(0, "VG_(scheduler), phase 3: "
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "unexpected thread return code (%u)", trc);
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* NOTREACHED */
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } /* switch (trc) */
1336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (0)
1338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         maybe_show_sb_counts();
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_sched))
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_sched_event(tid, "exiting VG_(scheduler)");
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_exiting)(tid));
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tst->exitreason;
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This causes all threads to forceably exit.  They aren't actually
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dead by the time this returns; you need to call
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(reap_threads)() to wait for them.
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(nuke_all_threads_except) ( ThreadId me, VgSchedReturnCode src )
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid;
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(me));
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (tid = 1; tid < VG_N_THREADS; tid++) {
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (tid == me
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || VG_(threads)[tid].status == VgTs_Empty)
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[tid].exitreason = src;
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (src == VgSrc_FatalSig)
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(threads)[tid].os_state.fatalsig = VKI_SIGKILL;
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_thread_out_of_syscall)(tid);
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Specifying shadow register values
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGA_x86)
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_ARGS       guest_EAX
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_RET        guest_EDX
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGA_amd64)
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_ARGS       guest_RAX
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_RET        guest_RDX
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGA_ppc32) || defined(VGA_ppc64)
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_ARGS       guest_GPR4
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_RET        guest_GPR3
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGA_arm)
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_ARGS       guest_R4
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VG_CLREQ_RET        guest_R3
1393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined (VGA_s390x)
1394b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  define VG_CLREQ_ARGS       guest_r2
1395b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  define VG_CLREQ_RET        guest_r3
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error Unknown arch
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define CLREQ_ARGS(regs)   ((regs).vex.VG_CLREQ_ARGS)
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define CLREQ_RET(regs)    ((regs).vex.VG_CLREQ_RET)
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define O_CLREQ_RET        (offsetof(VexGuestArchState, VG_CLREQ_RET))
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// These macros write a value to a client's thread register, and tell the
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// tool that it's happened (if necessary).
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SET_CLREQ_RETVAL(zztid, zzval) \
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { CLREQ_RET(VG_(threads)[zztid].arch) = (zzval); \
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_TRACK( post_reg_write, \
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Vg_CoreClientReq, zztid, O_CLREQ_RET, sizeof(UWord)); \
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SET_CLCALL_RETVAL(zztid, zzval, f) \
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { CLREQ_RET(VG_(threads)[zztid].arch) = (zzval); \
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_TRACK( post_reg_write_clientcall_return, \
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zztid, O_CLREQ_RET, sizeof(UWord), f); \
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handle client requests.
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// OS-specific(?) client requests
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool os_client_request(ThreadId tid, UWord *args)
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool handled = True;
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch(args[0]) {
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_USERREQ__LIBC_FREERES_DONE:
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is equivalent to an exit() syscall, but we don't set the
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 exitcode (since it might already be set) */
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched))
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "__libc_freeres() done; really quitting!\n");
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(threads)[tid].exitreason = VgSrc_ExitThread;
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      handled = False;
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return handled;
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a client request for the thread tid.  After the request, tid may
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or may not still be runnable; if not, the scheduler will have to
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   choose a new thread to run.
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid do_client_request ( ThreadId tid )
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord* arg = (UWord*)(CLREQ_ARGS(VG_(threads)[tid].arch));
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord req_no = arg[0];
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("req no = 0x%llx, arg = %p\n", (ULong)req_no, arg);
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (req_no) {
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__CLIENT_CALL0: {
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UWord (*f)(ThreadId) = (void*)arg[1];
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (f == NULL)
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL0: func=%p\n", f);
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 else
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    SET_CLCALL_RETVAL(tid, f ( tid ), (Addr)f);
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__CLIENT_CALL1: {
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UWord (*f)(ThreadId, UWord) = (void*)arg[1];
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (f == NULL)
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL1: func=%p\n", f);
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 else
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    SET_CLCALL_RETVAL(tid, f ( tid, arg[2] ), (Addr)f );
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__CLIENT_CALL2: {
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UWord (*f)(ThreadId, UWord, UWord) = (void*)arg[1];
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (f == NULL)
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL2: func=%p\n", f);
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 else
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3] ), (Addr)f );
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__CLIENT_CALL3: {
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UWord (*f)(ThreadId, UWord, UWord, UWord) = (void*)arg[1];
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (f == NULL)
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL3: func=%p\n", f);
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 else
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3], arg[4] ), (Addr)f );
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Nb: this looks like a circular definition, because it kind of is.
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // See comment in valgrind.h to understand what's going on.
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__RUNNING_ON_VALGRIND:
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL(tid, RUNNING_ON_VALGRIND+1);
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__PRINTF: {
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* JRS 2010-Jan-28: this is DEPRECATED; use the
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            _VALIST_BY_REF version instead */
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sizeof(va_list) != sizeof(UWord))
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto va_list_casting_error_NORETURN;
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         union {
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            va_list vargs;
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unsigned long uw;
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } u;
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         u.uw = (unsigned long)arg[2];
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int count =
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], u.vargs );
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message_flush)();
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, count );
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__PRINTF_BACKTRACE: {
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* JRS 2010-Jan-28: this is DEPRECATED; use the
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            _VALIST_BY_REF version instead */
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sizeof(va_list) != sizeof(UWord))
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto va_list_casting_error_NORETURN;
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         union {
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            va_list vargs;
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unsigned long uw;
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } u;
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         u.uw = (unsigned long)arg[2];
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int count =
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], u.vargs );
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message_flush)();
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, count );
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__PRINTF_VALIST_BY_REF: {
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         va_list* vargsp = (va_list*)arg[2];
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int count =
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], *vargsp );
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message_flush)();
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, count );
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF: {
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         va_list* vargsp = (va_list*)arg[2];
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int count =
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], *vargsp );
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message_flush)();
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, count );
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__INTERNAL_PRINTF_VALIST_BY_REF: {
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         va_list* vargsp = (va_list*)arg[2];
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int count =
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(vmessage)( Vg_DebugMsg, (char *)arg[1], *vargsp );
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message_flush)();
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, count );
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__ADD_IFUNC_TARGET: {
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(redir_add_ifunc_target)( arg[1], arg[2] );
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0);
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break; }
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__STACK_REGISTER: {
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UWord sid = VG_(register_stack)((Addr)arg[1], (Addr)arg[2]);
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, sid );
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break; }
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__STACK_DEREGISTER: {
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(deregister_stack)(arg[1]);
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break; }
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__STACK_CHANGE: {
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(change_stack)(arg[1], (Addr)arg[2], (Addr)arg[3]);
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break; }
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__GET_MALLOCFUNCS: {
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 struct vg_mallocfunc_info *info = (struct vg_mallocfunc_info *)arg[1];
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl_malloc               = VG_(tdict).tool_malloc;
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl_calloc               = VG_(tdict).tool_calloc;
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl_realloc              = VG_(tdict).tool_realloc;
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl_memalign             = VG_(tdict).tool_memalign;
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl___builtin_new        = VG_(tdict).tool___builtin_new;
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl___builtin_vec_new    = VG_(tdict).tool___builtin_vec_new;
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl_free                 = VG_(tdict).tool_free;
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl___builtin_delete     = VG_(tdict).tool___builtin_delete;
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->tl___builtin_vec_delete = VG_(tdict).tool___builtin_vec_delete;
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         info->tl_malloc_usable_size   = VG_(tdict).tool_malloc_usable_size;
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->mallinfo                = VG_(mallinfo);
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 info->clo_trace_malloc        = VG_(clo_trace_malloc);
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Requests from the client program */
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__DISCARD_TRANSLATIONS:
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_verbosity) > 2)
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         " addr %p,  len %lu\n",
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         (void*)arg[1], arg[2] );
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg[1], arg[2], "scheduler(VG_USERREQ__DISCARD_TRANSLATIONS)"
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__COUNT_ERRORS:
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, VG_(get_n_errs_found)() );
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__LOAD_PDB_DEBUGINFO:
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(di_notify_pdb_debuginfo)( arg[1], arg[2], arg[3], arg[4] );
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__MAP_IP_TO_SRCLOC: {
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Addr   ip    = arg[1];
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar* buf64 = (UChar*)arg[2];
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)(buf64, 0, 64);
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt linenum = 0;
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool ok = VG_(get_filename_linenum)(
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ip, &buf64[0], 50, NULL, 0, NULL, &linenum
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   );
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ok) {
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Find the terminating zero in the first 50 bytes. */
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt i;
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i < 50; i++) {
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (buf64[i] == 0)
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We must find a zero somewhere in 0 .. 49.  Else
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(get_filename_linenum) is not properly zero
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               terminating. */
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(i < 50);
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(sprintf)(&buf64[i], ":%u", linenum);
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf64[0] = 0;
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1661b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case VG_USERREQ__CHANGE_ERR_DISABLEMENT: {
1662b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Word delta = arg[1];
1663b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vg_assert(delta == 1 || delta == -1);
1664b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         ThreadState* tst = VG_(get_ThreadState)(tid);
1665b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vg_assert(tst);
1666b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (delta == 1 && tst->err_disablement_level < 0xFFFFFFFF) {
1667b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            tst->err_disablement_level++;
1668b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
1669b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1670b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (delta == -1 && tst->err_disablement_level > 0) {
1671b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            tst->err_disablement_level--;
1672b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
1673b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
1674b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
1675b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
1676b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__MALLOCLIKE_BLOCK:
1678b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case VG_USERREQ__RESIZEINPLACE_BLOCK:
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_USERREQ__FREELIKE_BLOCK:
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Ignore them if the addr is NULL;  otherwise pass onto the tool.
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!arg[1]) {
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto my_default;
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1688f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      case VG_USERREQ__NACL_MEM_START: {
1689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Addr mem_start = arg[1];
1690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         nacl_head = mem_start;
1691b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(printf)("*********************** NaCl mem_start: %p\n", (void*)mem_start);
1692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1693b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // At this point all segments in the sandbox belong to nacl_file (the
1694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // first untrusted binary loaded by sel_ldr), and have correct
1695b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // permissions. Read its debug info.
1696b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         NSegment* seg = VG_(am_find_nsegment)(mem_start);
1697b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         int fnIdx = -1;
1698b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         while (seg) {
1699b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           if (seg->kind == SkFileC) {
1700b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             if (fnIdx == seg->fnIdx || fnIdx == -1) {
1701b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               fnIdx = seg->fnIdx;
1702b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               VG_(printf)("Segment at %p belongs to the loader\n", (void*)seg->start);
1703b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               VG_(di_notify_mmap)(seg->start, False, /*glider: don't use fd*/-1);
1704b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             }
1705b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           }
1706b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           seg = VG_(am_next_nsegment)((NSegment*)seg, True);
1707b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
1708f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         goto my_default;
1709f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      }
1710f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
1711f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      case VG_USERREQ__NACL_FILE: {
1712f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         VG_(printf)("*********************** NaCl nacl_file: %s\n", (void*)arg[1]);
1713f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         nacl_file = (char*) arg[1];
1714f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         goto my_default;
1715f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      }
1716f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
1717b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case VG_USERREQ__NACL_MMAP: {
1718b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // Simulate an mmap().
1719b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord vma = arg[1]; // Base VMA of the mapping.
1720b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord size = arg[2]; // Size of the mapping.
1721b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord file_offset = arg[3]; // File offset.
1722b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord access = arg[4]; // Access.
1723b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord clone_vma = arg[5]; // Another mapping of the same; only used to find the file name.
1724b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (!access)
1725b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           access = VKI_PROT_READ | VKI_PROT_EXEC;
1726b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(printf)("*********************** NaCl nacl_mmap: %lx %lx %lx %lx\n", vma, size, file_offset, clone_vma);
1727b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1728b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         char* file_name = NULL;
1729b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (clone_vma) {
1730b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           NSegment* seg = VG_(am_find_nsegment)(clone_vma);
1731b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           file_name = VG_(am_get_filename)(seg);
1732b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           VG_(printf)("*********************** NaCl DSO file_name: %s\n", file_name);
1733b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
1734b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1735b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord vma_end = vma + size;
1736b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord vma_aligned = VG_PGROUNDDN(vma);
1737b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UWord vma_end_aligned = VG_PGROUNDUP(vma_end);
1738b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         size = vma_end_aligned - vma_aligned;
1739b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         file_offset -= vma - vma_aligned;
1740b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(am_notify_fake_client_mmap)(vma_aligned, size, access,
1741b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             0, file_name ? file_name : (VG_(clo_nacl_file) ? VG_(clo_nacl_file) : nacl_file), file_offset);
1742b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // If file_name == NULL, then this is the main (sel_ldr-mapped) nexe,
1743b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // and has incorrect permissions at this point. In that case, wait for
1744b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // NACL_MEM_START to read the debug info.
1745b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (file_name)
1746b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           VG_(di_notify_mmap)(vma_aligned, False, /*glider: don't use fd*/-1);
1747b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto my_default;
1748b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
1749b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1750f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       my_default:
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (os_client_request(tid, arg)) {
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    // do nothing, os_client_request() handled it
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (VG_(needs).client_requests) {
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    UWord ret;
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (VG_(clo_verbosity) > 2)
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(printf)("client request: code %lx,  addr %p,  len %lu\n",
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           arg[0], (void*)arg[1], arg[2] );
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if ( VG_TDICT_CALL(tool_handle_client_request, tid, arg, &ret) )
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       SET_CLREQ_RETVAL(tid, ret);
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    static Bool whined = False;
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if (!whined && VG_(clo_verbosity) > 2) {
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // Allow for requests in core, but defined by tools, which
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // have 0 and 0 in their two high bytes.
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Char c1 = (arg[0] >> 24) & 0xff;
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Char c2 = (arg[0] >> 16) & 0xff;
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (c1 == 0) c1 = '_';
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (c2 == 0) c2 = '_';
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       VG_(message)(Vg_UserMsg, "Warning:\n"
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "  unhandled client request: 0x%lx (%c%c+0x%lx).  Perhaps\n"
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		   "  VG_(needs).client_requests should be set?\n",
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			    arg[0], c1, c2, arg[0] & 0xffff);
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       whined = True;
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  va_list_casting_error_NORETURN:
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(umsg)(
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "Valgrind: fatal error - cannot continue: use of the deprecated\n"
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "client requests VG_USERREQ__PRINTF or VG_USERREQ__PRINTF_BACKTRACE\n"
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "on a platform where they cannot be supported.  Please use the\n"
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "equivalent _VALIST_BY_REF versions instead.\n"
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\n"
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "This is a binary-incompatible change in Valgrind's client request\n"
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "mechanism.  It is unfortunate, but difficult to avoid.  End-users\n"
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "are expected to almost never see this message.  The only case in\n"
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "which you might see this message is if your code uses the macros\n"
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "VALGRIND_PRINTF or VALGRIND_PRINTF_BACKTRACE.  If so, you will need\n"
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "to recompile such code, using the header files from this version of\n"
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "Valgrind, and not any previous version.\n"
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\n"
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "If you see this mesage in any other circumstances, it is probably\n"
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "a bug in Valgrind.  In this case, please file a bug report at\n"
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\n"
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "   http://www.valgrind.org/support/bug_reports.html\n"
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\n"
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "Will now abort.\n"
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Sanity checking (permanently engaged)
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Internal consistency checks on the sched structures. */
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid scheduler_sanity ( ThreadId tid )
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool bad = False;
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt lasttime = 0;
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt now;
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int lwpid = VG_(gettid)();
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!VG_(is_running_thread)(tid)) {
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		   "Thread %d is supposed to be running, "
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "but doesn't own the_BigLock (owned by %d)\n",
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		   tid, VG_(running_tid));
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bad = True;
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lwpid != VG_(threads)[tid].os_state.lwpid) {
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "Thread %d supposed to be in LWP %d, but we're actually %d\n",
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   tid, VG_(threads)[tid].os_state.lwpid, VG_(gettid)());
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bad = True;
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if !defined(VGO_darwin)
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lwpid != the_BigLock.owner_lwpid) {
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "Thread (LWPID) %d doesn't own the_BigLock\n",
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   tid);
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bad = True;
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Periodically show the state of all threads, for debugging
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      purposes. */
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   now = VG_(read_millisecond_timer)();
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && (!bad) && (lasttime + 4000/*ms*/ <= now)) {
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lasttime = now;
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n------------ Sched State at %d ms ------------\n",
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)now);
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(show_sched_status)();
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* core_panic also shows the sched status, which is why we don't
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show it above if bad==True. */
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bad)
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(core_panic)("scheduler_sanity: failed");
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(sanity_check_general) ( Bool force_expensive )
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid;
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt next_slow_check_at = 1;
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt slow_check_interval = 25;
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_sanity_level) < 1) return;
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- First do all the tests that we can do quickly. ---*/
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_fast_count++;
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check stuff pertaining to the memory check system. */
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check that nobody has spuriously claimed that the first or
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      last 16 pages of memory have become accessible [...] */
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(needs).sanity_checks) {
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(VG_TDICT_CALL(tool_cheap_sanity_check));
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- Now some more expensive checks. ---*/
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Once every now and again, check some more expensive stuff.
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Gradually increase the interval between such checks so as not to
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      burden long-running programs too much. */
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( force_expensive
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || VG_(clo_sanity_level) > 1
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || (VG_(clo_sanity_level) == 1
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && sanity_fast_count == next_slow_check_at)) {
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) VG_(printf)("SLOW at %d\n", sanity_fast_count-1);
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      next_slow_check_at = sanity_fast_count - 1 + slow_check_interval;
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      slow_check_interval++;
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sanity_slow_count++;
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(needs).sanity_checks) {
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          vg_assert(VG_TDICT_CALL(tool_expensive_sanity_check));
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Look for stack overruns.  Visit all threads. */
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (tid = 1; tid < VG_N_THREADS; tid++) {
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 SizeT    remains;
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VgStack* stack;
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (VG_(threads)[tid].status == VgTs_Empty ||
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     VG_(threads)[tid].status == VgTs_Zombie)
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    continue;
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stack
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = (VgStack*)
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              VG_(get_ThreadState)(tid)->os_state.valgrind_stack_base;
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SizeT limit
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = 4096; // Let's say.  Checking more causes lots of L2 misses.
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 remains
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = VG_(am_get_VgStack_unused_szB)(stack, limit);
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (remains < limit)
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    VG_(message)(Vg_DebugMsg,
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         "WARNING: Thread %d is within %ld bytes "
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         "of running out of stack!\n",
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		         tid, remains);
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_sanity_level) > 1) {
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Check sanity of the low-level memory manager.  Note that bugs
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in the client's code can cause this to fail, so we don't do
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this check unless specially asked for.  And because it's
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         potentially very expensive. */
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sanity_check_malloc_all)();
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1943