blob: f907c746675270aff1cfe1dacbbd3f4c674df747 [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/*--------------------------------------------------------------------*/
njn278b3d62005-05-30 23:20:51 +00003/*--- Thread scheduling. scheduler.c ---*/
sewardje663cb92002-04-12 10:26:32 +00004/*--------------------------------------------------------------------*/
5
6/*
sewardjb5f6f512005-03-10 23:59:00 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardje663cb92002-04-12 10:26:32 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
sewardje663cb92002-04-12 10:26:32 +000011 jseward@acm.org
sewardje663cb92002-04-12 10:26:32 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardje663cb92002-04-12 10:26:32 +000029*/
30
sewardjb5f6f512005-03-10 23:59:00 +000031/*
32 Overview
33
34 Valgrind tries to emulate the kernel's threading as closely as
35 possible. The client does all threading via the normal syscalls
36 (on Linux: clone, etc). Valgrind emulates this by creating exactly
37 the same process structure as would be created without Valgrind.
38 There are no extra threads.
39
40 The main difference is that Valgrind only allows one client thread
41 to run at once. This is controlled with the VCPU semaphore,
42 "run_sema". Any time a thread wants to run client code or
43 manipulate any shared state (which is anything other than its own
44 ThreadState entry), it must hold the run_sema.
45
46 When a thread is about to block in a blocking syscall, it releases
47 run_sema, and re-takes it when it becomes runnable again (either
48 because the syscall finished, or we took a signal).
49
50 VG_(scheduler) therefore runs in each thread. It returns only when
51 the thread is exiting, either because it exited itself, or it was
52 told to exit by another thread.
53
54 This file is almost entirely OS-independent. The details of how
55 the OS handles threading and signalling are abstracted away and
56 implemented elsewhere.
57 */
58
njn25e49d8e72002-09-23 09:36:25 +000059#include "valgrind.h" /* for VG_USERREQ__RUNNING_ON_VALGRIND and
njn47363ab2003-04-21 13:24:40 +000060 VG_USERREQ__DISCARD_TRANSLATIONS, and others */
nethercotef1e5e152004-09-01 23:58:16 +000061#include "core.h"
sewardje663cb92002-04-12 10:26:32 +000062
njn04e16982005-05-31 00:23:43 +000063#include "pub_core_aspacemgr.h"
njn36b66df2005-05-12 05:13:04 +000064#include "pub_core_dispatch.h"
njnd2b17112005-04-19 04:10:25 +000065#include "pub_core_errormgr.h"
njn04e16982005-05-31 00:23:43 +000066#include "pub_core_main.h"
njn20242342005-05-16 23:31:24 +000067#include "pub_core_options.h"
njn31513b42005-06-01 03:09:59 +000068#include "pub_core_profile.h"
njn717cde52005-05-10 02:47:21 +000069#include "pub_core_replacemalloc.h"
njn278b3d62005-05-30 23:20:51 +000070#include "pub_core_scheduler.h"
njn0c246472005-05-31 01:00:08 +000071#include "pub_core_signals.h"
njn2521d322005-05-08 14:45:13 +000072#include "pub_core_stacktrace.h"
73#include "pub_core_syscalls.h"
njn43b9a8a2005-05-10 04:37:01 +000074#include "pub_core_tooliface.h"
njn3cbfbc12005-05-13 23:11:40 +000075#include "pub_core_translate.h"
njn8bddf582005-05-13 23:40:55 +000076#include "pub_core_transtab.h"
njn3c660b62005-05-13 22:18:47 +000077#include "vki_unistd.h"
njn278b3d62005-05-30 23:20:51 +000078#include "priv_sema.h"
sewardje663cb92002-04-12 10:26:32 +000079
80/* ---------------------------------------------------------------------
81 Types and globals for the scheduler.
82 ------------------------------------------------------------------ */
83
rjwalsh7109a8c2004-09-02 00:31:02 +000084/* ThreadId and ThreadState are defined in core.h. */
sewardje663cb92002-04-12 10:26:32 +000085
njn14319cc2005-03-13 06:26:22 +000086/* Defines the thread-scheduling timeslice, in terms of the number of
87 basic blocks we attempt to run each thread for. Smaller values
88 give finer interleaving but much increased scheduling overheads. */
89#define SCHEDULING_QUANTUM 50000
90
sewardj018f7622002-05-15 21:13:39 +000091/* Globals. A statically allocated array of threads. NOTE: [0] is
92 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000093 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000094ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000095
sewardjb5f6f512005-03-10 23:59:00 +000096/* If true, a fault is Valgrind-internal (ie, a bug) */
97Bool VG_(my_fault) = True;
njn25e49d8e72002-09-23 09:36:25 +000098
njnde583aa2005-05-11 18:57:02 +000099/* Counts downwards in VG_(run_innerloop). */
100UInt VG_(dispatch_ctr);
101
sewardje663cb92002-04-12 10:26:32 +0000102/* Forwards */
sewardjb5f6f512005-03-10 23:59:00 +0000103static void do_client_request ( ThreadId tid );
104static void scheduler_sanity ( ThreadId tid );
105static void mostly_clear_thread_record ( ThreadId tid );
106static const HChar *name_of_thread_state ( ThreadStatus );
sewardjd140e442002-05-29 01:21:19 +0000107
nethercote844e7122004-08-02 15:27:22 +0000108/* Stats. */
109static UInt n_scheduling_events_MINOR = 0;
110static UInt n_scheduling_events_MAJOR = 0;
111
sewardjb5f6f512005-03-10 23:59:00 +0000112
nethercote844e7122004-08-02 15:27:22 +0000113void VG_(print_scheduler_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " %d/%d major/minor sched events.",
117 n_scheduling_events_MAJOR, n_scheduling_events_MINOR);
118}
119
sewardjb5f6f512005-03-10 23:59:00 +0000120/* CPU semaphore, so that threads can run exclusively */
121static vg_sema_t run_sema;
122static ThreadId running_tid = VG_INVALID_THREADID;
123
124
sewardje663cb92002-04-12 10:26:32 +0000125/* ---------------------------------------------------------------------
126 Helper functions for the scheduler.
127 ------------------------------------------------------------------ */
128
sewardjb48e5002002-05-13 00:16:03 +0000129__inline__
130Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000131{
132 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000133 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000134 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000135 if (VG_(threads)[tid].status == VgTs_Empty) return False;
136 return True;
137}
138
139
sewardj1e8cdc92002-04-18 11:37:52 +0000140/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000141 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
sewardj2a99cf62004-11-24 10:44:19 +0000142 if none do.
sewardj1e8cdc92002-04-18 11:37:52 +0000143*/
njn43c799e2003-04-08 00:08:52 +0000144ThreadId VG_(first_matching_thread_stack)
thughes4ad52d02004-06-27 17:37:21 +0000145 ( Bool (*p) ( Addr stack_min, Addr stack_max, void* d ),
146 void* d )
sewardj1e8cdc92002-04-18 11:37:52 +0000147{
sewardjb5f6f512005-03-10 23:59:00 +0000148 ThreadId tid;
sewardj1e8cdc92002-04-18 11:37:52 +0000149
sewardj6072c362002-04-19 14:40:57 +0000150 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000151 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardjb5f6f512005-03-10 23:59:00 +0000152
njncf45fd42004-11-24 16:30:22 +0000153 if ( p ( STACK_PTR(VG_(threads)[tid].arch),
njn50ba34e2005-04-04 02:41:42 +0000154 VG_(threads)[tid].client_stack_highest_word, d ) )
sewardj1e8cdc92002-04-18 11:37:52 +0000155 return tid;
156 }
157 return VG_INVALID_THREADID;
158}
159
sewardjb5f6f512005-03-10 23:59:00 +0000160void VG_(mark_from_registers)(void (*mark_addr)(Addr))
161{
162 ThreadId tid;
163
164 for(tid = 1; tid < VG_N_THREADS; tid++) {
165 if (!VG_(is_valid_tid)(tid))
166 continue;
167 VGA_(mark_from_registers)(tid, mark_addr);
168 }
169}
sewardj1e8cdc92002-04-18 11:37:52 +0000170
sewardj15a43e12002-04-17 19:35:12 +0000171/* Print the scheduler status. */
172void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000173{
174 Int i;
175 VG_(printf)("\nsched status:\n");
sewardjb5f6f512005-03-10 23:59:00 +0000176 VG_(printf)(" running_tid=%d\n", running_tid);
sewardj6072c362002-04-19 14:40:57 +0000177 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000178 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardjb5f6f512005-03-10 23:59:00 +0000179 VG_(printf)("\nThread %d: status = %s\n", i, name_of_thread_state(VG_(threads)[i].status));
njnd01fef72005-03-25 23:35:48 +0000180 VG_(get_and_pp_StackTrace)( i, VG_(clo_backtrace_size) );
sewardje663cb92002-04-12 10:26:32 +0000181 }
182 VG_(printf)("\n");
183}
184
sewardje663cb92002-04-12 10:26:32 +0000185static
186void print_sched_event ( ThreadId tid, Char* what )
187{
sewardj45b4b372002-04-16 22:50:32 +0000188 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000189}
190
sewardj8937c812002-04-12 20:12:20 +0000191static
sewardjb5f6f512005-03-10 23:59:00 +0000192HChar* name_of_sched_event ( UInt event )
sewardje663cb92002-04-12 10:26:32 +0000193{
194 switch (event) {
sewardjd79ef682004-11-26 13:25:17 +0000195 case VEX_TRC_JMP_SYSCALL: return "SYSCALL";
196 case VEX_TRC_JMP_CLIENTREQ: return "CLIENTREQ";
197 case VEX_TRC_JMP_YIELD: return "YIELD";
sewardj45f02c42005-02-05 18:27:14 +0000198 case VEX_TRC_JMP_NODECODE: return "NODECODE";
sewardje663cb92002-04-12 10:26:32 +0000199 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
200 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
sewardjb5f6f512005-03-10 23:59:00 +0000201 case VG_TRC_FAULT_SIGNAL: return "FAULTSIGNAL";
sewardje663cb92002-04-12 10:26:32 +0000202 default: return "??UNKNOWN??";
203 }
204}
205
sewardjb5f6f512005-03-10 23:59:00 +0000206static
207const HChar* name_of_thread_state ( ThreadStatus state )
208{
209 switch (state) {
210 case VgTs_Empty: return "VgTs_Empty";
211 case VgTs_Init: return "VgTs_Init";
212 case VgTs_Runnable: return "VgTs_Runnable";
213 case VgTs_WaitSys: return "VgTs_WaitSys";
214 case VgTs_Yielding: return "VgTs_Yielding";
215 case VgTs_Zombie: return "VgTs_Zombie";
216 default: return "VgTs_???";
217 }
218}
sewardje663cb92002-04-12 10:26:32 +0000219
sewardje663cb92002-04-12 10:26:32 +0000220/* Allocate a completely empty ThreadState record. */
sewardjb5f6f512005-03-10 23:59:00 +0000221ThreadId VG_(alloc_ThreadState) ( void )
sewardje663cb92002-04-12 10:26:32 +0000222{
223 Int i;
sewardj6072c362002-04-19 14:40:57 +0000224 for (i = 1; i < VG_N_THREADS; i++) {
sewardjb5f6f512005-03-10 23:59:00 +0000225 if (VG_(threads)[i].status == VgTs_Empty) {
226 VG_(threads)[i].status = VgTs_Init;
227 VG_(threads)[i].exitreason = VgSrc_None;
sewardje663cb92002-04-12 10:26:32 +0000228 return i;
sewardjb5f6f512005-03-10 23:59:00 +0000229 }
sewardje663cb92002-04-12 10:26:32 +0000230 }
231 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
232 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000233 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000234 /*NOTREACHED*/
235}
236
jsgf855d93d2003-10-13 22:26:55 +0000237ThreadState *VG_(get_ThreadState)(ThreadId tid)
238{
239 vg_assert(tid >= 0 && tid < VG_N_THREADS);
240 return &VG_(threads)[tid];
241}
242
sewardjb5f6f512005-03-10 23:59:00 +0000243/* Given an LWP id (ie, real kernel thread id), find the corresponding
244 ThreadId */
245ThreadId VG_(get_lwp_tid)(Int lwp)
njn25e49d8e72002-09-23 09:36:25 +0000246{
sewardjb5f6f512005-03-10 23:59:00 +0000247 ThreadId tid;
nethercote75d26242004-08-01 22:59:18 +0000248
njn742929d2005-05-24 20:07:20 +0000249 for(tid = 1; tid < VG_N_THREADS; tid++)
sewardjb5f6f512005-03-10 23:59:00 +0000250 if (VG_(threads)[tid].status != VgTs_Empty && VG_(threads)[tid].os_state.lwpid == lwp)
251 return tid;
252
253 return VG_INVALID_THREADID;
254}
255
256/*
257 Mark a thread as Runnable. This will block until the run_sema is
258 available, so that we get exclusive access to all the shared
259 structures and the CPU. Up until we get the sema, we must not
260 touch any shared state.
261
262 When this returns, we'll actually be running.
263 */
264void VG_(set_running)(ThreadId tid)
265{
266 ThreadState *tst = VG_(get_ThreadState)(tid);
267
268 vg_assert(tst->status != VgTs_Runnable);
269
270 tst->status = VgTs_Runnable;
271
njn278b3d62005-05-30 23:20:51 +0000272 VG_(sema_down)(&run_sema);
sewardjb5f6f512005-03-10 23:59:00 +0000273 if (running_tid != VG_INVALID_THREADID)
274 VG_(printf)("tid %d found %d running\n", tid, running_tid);
275 vg_assert(running_tid == VG_INVALID_THREADID);
276 running_tid = tid;
277
278 if (VG_(clo_trace_sched))
279 print_sched_event(tid, "now running");
280}
281
282ThreadId VG_(get_running_tid)(void)
283{
284 return running_tid;
285}
286
287Bool VG_(is_running_thread)(ThreadId tid)
288{
289 ThreadState *tst = VG_(get_ThreadState)(tid);
290
291 return
292// tst->os_state.lwpid == VG_(gettid)() && /* check we're this tid */
293 running_tid == tid && /* and that we've got the lock */
294 tst->status == VgTs_Runnable; /* and we're runnable */
295}
296
297/* Return the number of non-dead Threads */
298Int VG_(count_living_threads)(void)
299{
300 Int count = 0;
301 ThreadId tid;
302
303 for(tid = 1; tid < VG_N_THREADS; tid++)
304 if (VG_(threads)[tid].status != VgTs_Empty &&
305 VG_(threads)[tid].status != VgTs_Zombie)
306 count++;
307
308 return count;
309}
310
311/*
312 Set a thread into a sleeping state, and give up exclusive access to
313 the CPU. On return, the thread must be prepared to block until it
314 is ready to run again (generally this means blocking in a syscall,
315 but it may mean that we remain in a Runnable state and we're just
316 yielding the CPU to another thread).
317 */
318void VG_(set_sleeping)(ThreadId tid, ThreadStatus sleepstate)
319{
320 ThreadState *tst = VG_(get_ThreadState)(tid);
321
322 vg_assert(tst->status == VgTs_Runnable);
323
324 vg_assert(sleepstate == VgTs_WaitSys ||
325 sleepstate == VgTs_Yielding);
326
327 tst->status = sleepstate;
328
329 vg_assert(running_tid == tid);
330 running_tid = VG_INVALID_THREADID;
331
332 /* Release the run_sema; this will reschedule any runnable
333 thread. */
njn278b3d62005-05-30 23:20:51 +0000334 VG_(sema_up)(&run_sema);
sewardjb5f6f512005-03-10 23:59:00 +0000335
336 if (VG_(clo_trace_sched)) {
337 Char buf[50];
338 VG_(sprintf)(buf, "now sleeping in state %s", name_of_thread_state(sleepstate));
339 print_sched_event(tid, buf);
nethercote75d26242004-08-01 22:59:18 +0000340 }
341}
342
sewardjb5f6f512005-03-10 23:59:00 +0000343/* Return true if the thread is still alive but in the process of
344 exiting. */
345inline Bool VG_(is_exiting)(ThreadId tid)
346{
347 vg_assert(VG_(is_valid_tid)(tid));
348 return VG_(threads)[tid].exitreason != VgSrc_None;
349}
sewardj2a99cf62004-11-24 10:44:19 +0000350
sewardjb5f6f512005-03-10 23:59:00 +0000351/* Clear out the ThreadState and release the semaphore. Leaves the
352 ThreadState in VgTs_Zombie state, so that it doesn't get
353 reallocated until the caller is really ready. */
354void VG_(exit_thread)(ThreadId tid)
355{
356 vg_assert(VG_(is_valid_tid)(tid));
357 vg_assert(VG_(is_running_thread)(tid));
358 vg_assert(VG_(is_exiting)(tid));
359
sewardjb5f6f512005-03-10 23:59:00 +0000360 mostly_clear_thread_record(tid);
361 running_tid = VG_INVALID_THREADID;
362
363 /* There should still be a valid exitreason for this thread */
364 vg_assert(VG_(threads)[tid].exitreason != VgSrc_None);
365
njn278b3d62005-05-30 23:20:51 +0000366 VG_(sema_up)(&run_sema);
sewardjb5f6f512005-03-10 23:59:00 +0000367}
368
369/* Kill a thread. This interrupts whatever a thread is doing, and
370 makes it exit ASAP. This does not set the exitreason or
371 exitcode. */
372void VG_(kill_thread)(ThreadId tid)
373{
374 vg_assert(VG_(is_valid_tid)(tid));
375 vg_assert(!VG_(is_running_thread)(tid));
376 vg_assert(VG_(is_exiting)(tid));
377
378 if (VG_(threads)[tid].status == VgTs_WaitSys) {
379 if (VG_(clo_trace_signals))
380 VG_(message)(Vg_DebugMsg, "kill_thread zaps tid %d lwp %d",
381 tid, VG_(threads)[tid].os_state.lwpid);
382 VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VKI_SIGVGKILL);
383 }
384}
385
386/*
387 Yield the CPU for a short time to let some other thread run.
388 */
389void VG_(vg_yield)(void)
390{
391 struct vki_timespec ts = { 0, 1 };
392 ThreadId tid = running_tid;
393
394 vg_assert(tid != VG_INVALID_THREADID);
395 vg_assert(VG_(threads)[tid].os_state.lwpid == VG_(gettid)());
396
397 VG_(set_sleeping)(tid, VgTs_Yielding);
398
399 //VG_(printf)("tid %d yielding EIP=%p\n", tid, VG_(threads)[tid].arch.m_eip);
400
401 /*
402 Tell the kernel we're yielding.
403 */
404 if (1)
405 VG_(do_syscall0)(__NR_sched_yield);
406 else
407 VG_(nanosleep)(&ts);
408
409 VG_(set_running)(tid);
410
411 VG_(poll_signals)(tid); /* something might have happened */
412}
413
414
415void VG_(resume_scheduler)(ThreadId tid)
416{
417 ThreadState *tst = VG_(get_ThreadState)(tid);
418
419 vg_assert(tst->os_state.lwpid == VG_(gettid)());
420
421 if (tst->sched_jmpbuf_valid) {
422 /* Can't continue; must longjmp back to the scheduler and thus
423 enter the sighandler immediately. */
424
njn4f6e3702005-05-16 20:50:52 +0000425 longjmp(tst->sched_jmpbuf, True);
sewardjb5f6f512005-03-10 23:59:00 +0000426 }
427}
428
njn9fc31122005-05-11 18:48:33 +0000429/* Set the standard set of blocked signals, used wheneever we're not
430 running a client syscall. */
431static void block_signals(ThreadId tid)
432{
433 vki_sigset_t mask;
434
435 VG_(sigfillset)(&mask);
436
437 /* Don't block these because they're synchronous */
438 VG_(sigdelset)(&mask, VKI_SIGSEGV);
439 VG_(sigdelset)(&mask, VKI_SIGBUS);
440 VG_(sigdelset)(&mask, VKI_SIGFPE);
441 VG_(sigdelset)(&mask, VKI_SIGILL);
442 VG_(sigdelset)(&mask, VKI_SIGTRAP);
443
444 /* Can't block these anyway */
445 VG_(sigdelset)(&mask, VKI_SIGSTOP);
446 VG_(sigdelset)(&mask, VKI_SIGKILL);
447
njn9fc31122005-05-11 18:48:33 +0000448 VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
449}
450
njn4f6e3702005-05-16 20:50:52 +0000451/* Use libc setjmp/longjmp. longjmp must not restore signal mask
452 state, but does need to pass "val" through. */
sewardjb5f6f512005-03-10 23:59:00 +0000453#define SCHEDSETJMP(tid, jumped, stmt) \
454 do { \
455 ThreadState * volatile _qq_tst = VG_(get_ThreadState)(tid); \
456 \
njn4f6e3702005-05-16 20:50:52 +0000457 (jumped) = setjmp(_qq_tst->sched_jmpbuf); \
sewardjb5f6f512005-03-10 23:59:00 +0000458 if ((jumped) == 0) { \
459 vg_assert(!_qq_tst->sched_jmpbuf_valid); \
460 _qq_tst->sched_jmpbuf_valid = True; \
461 stmt; \
462 } else if (VG_(clo_trace_sched)) \
463 VG_(printf)("SCHEDSETJMP(line %d) tid %d, jumped=%d\n", __LINE__, tid, jumped); \
464 vg_assert(_qq_tst->sched_jmpbuf_valid); \
465 _qq_tst->sched_jmpbuf_valid = False; \
466 } while(0)
467
468/* Run the thread tid for a while, and return a VG_TRC_* value to the
469 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000470static
sewardje663cb92002-04-12 10:26:32 +0000471UInt run_thread_for_a_while ( ThreadId tid )
472{
sewardjb5f6f512005-03-10 23:59:00 +0000473 volatile Bool jumped;
474 volatile ThreadState *tst = VG_(get_ThreadState)(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000475
sewardj7ccc5c22002-04-24 21:39:11 +0000476 volatile UInt trc = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000477 volatile Int dispatch_ctr_SAVED = VG_(dispatch_ctr);
478 volatile Int done_this_time;
sewardj8b635a42004-11-22 19:01:47 +0000479
sewardj873b3132004-11-25 22:50:17 +0000480 /* For paranoia purposes only */
481 volatile Addr a_vex = (Addr) & VG_(threads)[tid].arch.vex;
482 volatile Addr a_vexsh = (Addr) & VG_(threads)[tid].arch.vex_shadow;
483 volatile Addr a_spill = (Addr) & VG_(threads)[tid].arch.vex_spill;
484 volatile UInt sz_vex = (UInt) sizeof VG_(threads)[tid].arch.vex;
485 volatile UInt sz_vexsh = (UInt) sizeof VG_(threads)[tid].arch.vex_shadow;
486 volatile UInt sz_spill = (UInt) sizeof VG_(threads)[tid].arch.vex_spill;
487
488 /* Paranoia */
sewardjb48e5002002-05-13 00:16:03 +0000489 vg_assert(VG_(is_valid_tid)(tid));
sewardjb5f6f512005-03-10 23:59:00 +0000490 vg_assert(VG_(is_valid_tid)(tid));
491 vg_assert(VG_(is_running_thread)(tid));
492 vg_assert(!VG_(is_exiting)(tid));
sewardje663cb92002-04-12 10:26:32 +0000493
sewardj873b3132004-11-25 22:50:17 +0000494 /* Even more paranoia. Check that what we have matches
495 Vex's guest state layout requirements. */
sewardj12a74b52004-11-26 11:57:41 +0000496 if (0)
497 VG_(printf)("%p %d %p %d %p %d\n",
sewardjb5f6f512005-03-10 23:59:00 +0000498 (void*)a_vex, sz_vex, (void*)a_vexsh, sz_vexsh,
499 (void*)a_spill, sz_spill );
sewardj873b3132004-11-25 22:50:17 +0000500
njnbe91aae2005-03-27 01:42:41 +0000501 vg_assert(VG_IS_8_ALIGNED(sz_vex));
502 vg_assert(VG_IS_8_ALIGNED(sz_vexsh));
503 vg_assert(VG_IS_16_ALIGNED(sz_spill));
sewardj12a74b52004-11-26 11:57:41 +0000504
njnbe91aae2005-03-27 01:42:41 +0000505 vg_assert(VG_IS_4_ALIGNED(a_vex));
506 vg_assert(VG_IS_4_ALIGNED(a_vexsh));
507 vg_assert(VG_IS_4_ALIGNED(a_spill));
sewardj873b3132004-11-25 22:50:17 +0000508
509 vg_assert(sz_vex == sz_vexsh);
510 vg_assert(a_vex + sz_vex == a_vexsh);
511
512 vg_assert(sz_spill == LibVEX_N_SPILL_BYTES);
513 vg_assert(a_vex + 2 * sz_vex == a_spill);
514
sewardj671ff542002-05-07 09:25:30 +0000515 VGP_PUSHCC(VgpRun);
jsgf855d93d2003-10-13 22:26:55 +0000516
517 /* there should be no undealt-with signals */
sewardjb5f6f512005-03-10 23:59:00 +0000518 //vg_assert(VG_(threads)[tid].siginfo.si_signo == 0);
jsgf855d93d2003-10-13 22:26:55 +0000519
sewardjb5f6f512005-03-10 23:59:00 +0000520 //VG_(printf)("running EIP = %p ESP=%p\n", VG_(threads)[tid].arch.m_eip, VG_(threads)[tid].arch.m_esp);
521
522 vg_assert(VG_(my_fault));
523 VG_(my_fault) = False;
524
sewardj0312f512005-03-30 19:04:29 +0000525 SCHEDSETJMP(tid, jumped,
526 trc = (UInt)VG_(run_innerloop)( (void*)&tst->arch.vex ));
sewardjb5f6f512005-03-10 23:59:00 +0000527
528 //nextEIP = tst->arch.m_eip;
529 //if (nextEIP >= VG_(client_end))
530 // VG_(printf)("trc=%d jump to %p from %p\n",
531 // trc, nextEIP, EIP);
532
533 VG_(my_fault) = True;
534
535 if (jumped) {
sewardje663cb92002-04-12 10:26:32 +0000536 /* We get here if the client took a fault, which caused our
537 signal handler to longjmp. */
538 vg_assert(trc == 0);
sewardjb5f6f512005-03-10 23:59:00 +0000539 trc = VG_TRC_FAULT_SIGNAL;
njn9fc31122005-05-11 18:48:33 +0000540 block_signals(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000541 }
sewardj5390e662005-01-10 16:51:14 +0000542
sewardj8b635a42004-11-22 19:01:47 +0000543 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 0;
544
545 vg_assert(done_this_time >= 0);
546 VG_(bbs_done) += (ULong)done_this_time;
547
njn25e49d8e72002-09-23 09:36:25 +0000548 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000549 return trc;
550}
551
552
sewardj20917d82002-05-28 01:36:45 +0000553static
554void mostly_clear_thread_record ( ThreadId tid )
555{
sewardjb5f6f512005-03-10 23:59:00 +0000556 vki_sigset_t savedmask;
557
sewardj20917d82002-05-28 01:36:45 +0000558 vg_assert(tid >= 0 && tid < VG_N_THREADS);
njn2335d112005-05-15 20:52:04 +0000559 VGP_(cleanup_thread)(&VG_(threads)[tid].arch);
sewardjb5f6f512005-03-10 23:59:00 +0000560 VG_(threads)[tid].tid = tid;
561
562 /* Leave the thread in Zombie, so that it doesn't get reallocated
563 until the caller is finally done with the thread stack. */
564 VG_(threads)[tid].status = VgTs_Zombie;
565
566 VG_(threads)[tid].syscallno = -1;
567
nethercote73b526f2004-10-31 18:48:21 +0000568 VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
sewardjb5f6f512005-03-10 23:59:00 +0000569 VG_(sigemptyset)(&VG_(threads)[tid].tmp_sig_mask);
jsgf855d93d2003-10-13 22:26:55 +0000570
sewardj1d887112005-05-30 21:44:08 +0000571 VGO_(os_state_clear)(&VG_(threads)[tid]);
fitzhardinge28428592004-03-16 22:07:12 +0000572
573 /* start with no altstack */
574 VG_(threads)[tid].altstack.ss_sp = (void *)0xdeadbeef;
575 VG_(threads)[tid].altstack.ss_size = 0;
576 VG_(threads)[tid].altstack.ss_flags = VKI_SS_DISABLE;
sewardjb5f6f512005-03-10 23:59:00 +0000577
njn444eba12005-05-12 03:47:31 +0000578 VG_(clear_out_queued_signals)(tid, &savedmask);
sewardjb5f6f512005-03-10 23:59:00 +0000579
580 VG_(threads)[tid].sched_jmpbuf_valid = False;
sewardj20917d82002-05-28 01:36:45 +0000581}
582
njn3f8c4372005-03-13 04:43:10 +0000583/*
584 Called in the child after fork. If the parent has multiple
585 threads, then we've inhereted a VG_(threads) array describing them,
586 but only the thread which called fork() is actually alive in the
587 child. This functions needs to clean up all those other thread
588 structures.
589
590 Whichever tid in the parent which called fork() becomes the
591 master_tid in the child. That's because the only living slot in
592 VG_(threads) in the child after fork is VG_(threads)[tid], and it
593 would be too hard to try to re-number the thread and relocate the
594 thread state down to VG_(threads)[1].
595
596 This function also needs to reinitialize the run_sema, since
597 otherwise we may end up sharing its state with the parent, which
598 would be deeply confusing.
599*/
sewardjb5f6f512005-03-10 23:59:00 +0000600static void sched_fork_cleanup(ThreadId me)
601{
602 ThreadId tid;
603 vg_assert(running_tid == me);
604
sewardjb5f6f512005-03-10 23:59:00 +0000605 VG_(threads)[me].os_state.lwpid = VG_(gettid)();
606 VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
607
608 /* clear out all the unused thread slots */
609 for (tid = 1; tid < VG_N_THREADS; tid++) {
njn3f8c4372005-03-13 04:43:10 +0000610 if (tid != me) {
611 mostly_clear_thread_record(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000612 VG_(threads)[tid].status = VgTs_Empty;
njn3f8c4372005-03-13 04:43:10 +0000613 }
sewardjb5f6f512005-03-10 23:59:00 +0000614 }
615
616 /* re-init and take the sema */
njn278b3d62005-05-30 23:20:51 +0000617 VG_(sema_deinit)(&run_sema);
618 VG_(sema_init)(&run_sema);
619 VG_(sema_down)(&run_sema);
sewardjb5f6f512005-03-10 23:59:00 +0000620}
sewardj20917d82002-05-28 01:36:45 +0000621
jsgf855d93d2003-10-13 22:26:55 +0000622
sewardje663cb92002-04-12 10:26:32 +0000623/* Initialise the scheduler. Create a single "main" thread ready to
sewardj2a99cf62004-11-24 10:44:19 +0000624 run, with special ThreadId of one. This is called at startup. The
sewardjb5f6f512005-03-10 23:59:00 +0000625 caller subsequently initialises the guest state components of this
626 main thread, thread 1.
sewardje663cb92002-04-12 10:26:32 +0000627*/
628void VG_(scheduler_init) ( void )
629{
thughesc37184f2004-09-11 14:16:57 +0000630 Int i;
sewardje663cb92002-04-12 10:26:32 +0000631 ThreadId tid_main;
632
njn278b3d62005-05-30 23:20:51 +0000633 VG_(sema_init)(&run_sema);
sewardjb5f6f512005-03-10 23:59:00 +0000634
sewardj6072c362002-04-19 14:40:57 +0000635 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardjc793fd32005-05-31 17:24:49 +0000636
637 /* Paranoia .. completely zero it out. */
638 VG_(memset)( & VG_(threads)[i], 0, sizeof( VG_(threads)[i] ) );
639
640 VG_(threads)[i].sig_queue = NULL;
sewardjb5f6f512005-03-10 23:59:00 +0000641
sewardj1d887112005-05-30 21:44:08 +0000642 VGO_(os_state_init)(&VG_(threads)[i]);
sewardj20917d82002-05-28 01:36:45 +0000643 mostly_clear_thread_record(i);
sewardjb5f6f512005-03-10 23:59:00 +0000644
njn50ba34e2005-04-04 02:41:42 +0000645 VG_(threads)[i].status = VgTs_Empty;
646 VG_(threads)[i].client_stack_szB = 0;
647 VG_(threads)[i].client_stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000648 }
649
sewardjb5f6f512005-03-10 23:59:00 +0000650 tid_main = VG_(alloc_ThreadState)();
sewardj5f07b662002-04-23 16:52:51 +0000651
sewardjb5f6f512005-03-10 23:59:00 +0000652 /* Initial thread's stack is the original process stack */
njn50ba34e2005-04-04 02:41:42 +0000653 VG_(threads)[tid_main].client_stack_highest_word
njn90eecea2005-04-04 02:48:32 +0000654 = VG_(clstk_end) - sizeof(UWord);
njn50ba34e2005-04-04 02:41:42 +0000655 VG_(threads)[tid_main].client_stack_szB = VG_(client_rlimit_stack).rlim_cur;
sewardjbf290b92002-05-01 02:28:01 +0000656
sewardjb5f6f512005-03-10 23:59:00 +0000657 VG_(atfork)(NULL, NULL, sched_fork_cleanup);
sewardje663cb92002-04-12 10:26:32 +0000658}
659
660
sewardje663cb92002-04-12 10:26:32 +0000661/* ---------------------------------------------------------------------
662 The scheduler proper.
663 ------------------------------------------------------------------ */
664
sewardjb5f6f512005-03-10 23:59:00 +0000665static void handle_tt_miss ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +0000666{
sewardjb5f6f512005-03-10 23:59:00 +0000667 Bool found;
668 Addr ip = INSTR_PTR(VG_(threads)[tid].arch);
669
670 /* Trivial event. Miss in the fast-cache. Do a full
671 lookup for it. */
672 found = VG_(search_transtab)( NULL,
673 ip, True/*upd_fast_cache*/ );
674 if (!found) {
675 /* Not found; we need to request a translation. */
676 if (VG_(translate)( tid, ip, /*debug*/False, 0/*not verbose*/ )) {
677 found = VG_(search_transtab)( NULL, ip, True );
njn50ae1a72005-04-08 23:28:23 +0000678 vg_assert2(found, "VG_TRC_INNER_FASTMISS: missing tt_fast entry");
679
sewardjb5f6f512005-03-10 23:59:00 +0000680 } else {
681 // If VG_(translate)() fails, it's because it had to throw a
682 // signal because the client jumped to a bad address. That
683 // means that either a signal has been set up for delivery,
684 // or the thread has been marked for termination. Either
685 // way, we just need to go back into the scheduler loop.
686 }
687 }
688}
689
690static void handle_syscall(ThreadId tid)
691{
692 ThreadState *tst = VG_(get_ThreadState)(tid);
693 Bool jumped;
694
695 /* Syscall may or may not block; either way, it will be
696 complete by the time this call returns, and we'll be
697 runnable again. We could take a signal while the
698 syscall runs. */
699 SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
700
701 if (!VG_(is_running_thread)(tid))
702 VG_(printf)("tid %d not running; running_tid=%d, tid %d status %d\n",
703 tid, running_tid, tid, tst->status);
704 vg_assert(VG_(is_running_thread)(tid));
705
706 if (jumped) {
njn9fc31122005-05-11 18:48:33 +0000707 block_signals(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000708 VG_(poll_signals)(tid);
709 }
710}
711
712/*
713 Run a thread until it wants to exit.
714
715 We assume that the caller has already called VG_(set_running) for
716 us, so we own the VCPU. Also, all signals are blocked.
717 */
718VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
719{
sewardje663cb92002-04-12 10:26:32 +0000720 UInt trc;
sewardjb5f6f512005-03-10 23:59:00 +0000721 ThreadState *tst = VG_(get_ThreadState)(tid);
sewardje663cb92002-04-12 10:26:32 +0000722
sewardjc24be7a2005-03-15 01:40:12 +0000723 if (VG_(clo_trace_sched))
724 print_sched_event(tid, "entering VG_(scheduler)");
725
sewardjb5f6f512005-03-10 23:59:00 +0000726 VGP_PUSHCC(VgpSched);
sewardje663cb92002-04-12 10:26:32 +0000727
sewardjb5f6f512005-03-10 23:59:00 +0000728 /* set the proper running signal mask */
njn9fc31122005-05-11 18:48:33 +0000729 block_signals(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000730
731 vg_assert(VG_(is_running_thread)(tid));
sewardje663cb92002-04-12 10:26:32 +0000732
njn14319cc2005-03-13 06:26:22 +0000733 VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
sewardj6072c362002-04-19 14:40:57 +0000734
sewardjb5f6f512005-03-10 23:59:00 +0000735 while(!VG_(is_exiting)(tid)) {
sewardjb5f6f512005-03-10 23:59:00 +0000736 if (VG_(dispatch_ctr) == 1) {
737 /* Our slice is done, so yield the CPU to another thread. This
738 doesn't sleep between sleeping and running, since that would
739 take too much time. */
740 VG_(set_sleeping)(tid, VgTs_Yielding);
741 /* nothing */
742 VG_(set_running)(tid);
743 //VG_(tm_thread_switchto)(tid);
sewardje663cb92002-04-12 10:26:32 +0000744
sewardjb5f6f512005-03-10 23:59:00 +0000745 /* OK, do some relatively expensive housekeeping stuff */
746 scheduler_sanity(tid);
747 VG_(sanity_check_general)(False);
sewardje663cb92002-04-12 10:26:32 +0000748
sewardjb5f6f512005-03-10 23:59:00 +0000749 /* Look for any pending signals for this thread, and set them up
750 for delivery */
751 VG_(poll_signals)(tid);
sewardje663cb92002-04-12 10:26:32 +0000752
sewardjb5f6f512005-03-10 23:59:00 +0000753 if (VG_(is_exiting)(tid))
754 break; /* poll_signals picked up a fatal signal */
sewardje663cb92002-04-12 10:26:32 +0000755
sewardjb5f6f512005-03-10 23:59:00 +0000756 /* For stats purposes only. */
757 n_scheduling_events_MAJOR++;
sewardje663cb92002-04-12 10:26:32 +0000758
sewardjb5f6f512005-03-10 23:59:00 +0000759 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
760 that it decrements the counter before testing it for zero, so
761 that if tst->dispatch_ctr is set to N you get at most N-1
762 iterations. Also this means that tst->dispatch_ctr must
763 exceed zero before entering the innerloop. Also also, the
764 decrement is done before the bb is actually run, so you
765 always get at least one decrement even if nothing happens. */
njn14319cc2005-03-13 06:26:22 +0000766 VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
jsgf855d93d2003-10-13 22:26:55 +0000767
sewardjb5f6f512005-03-10 23:59:00 +0000768 /* paranoia ... */
769 vg_assert(tst->tid == tid);
770 vg_assert(tst->os_state.lwpid == VG_(gettid)());
sewardje663cb92002-04-12 10:26:32 +0000771 }
772
sewardjb5f6f512005-03-10 23:59:00 +0000773 /* For stats purposes only. */
774 n_scheduling_events_MINOR++;
sewardje663cb92002-04-12 10:26:32 +0000775
776 if (0)
sewardjb5f6f512005-03-10 23:59:00 +0000777 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
778 tid, VG_(dispatch_ctr) - 1 );
sewardje663cb92002-04-12 10:26:32 +0000779
sewardjb5f6f512005-03-10 23:59:00 +0000780 trc = run_thread_for_a_while ( tid );
sewardje663cb92002-04-12 10:26:32 +0000781
sewardjb5f6f512005-03-10 23:59:00 +0000782 if (VG_(clo_trace_sched) && VG_(clo_verbosity) > 2) {
783 Char buf[50];
784 VG_(sprintf)(buf, "TRC: %s", name_of_sched_event(trc));
785 print_sched_event(tid, buf);
sewardje663cb92002-04-12 10:26:32 +0000786 }
787
sewardjb5f6f512005-03-10 23:59:00 +0000788 switch(trc) {
789 case VG_TRC_INNER_FASTMISS:
790 vg_assert(VG_(dispatch_ctr) > 1);
791 handle_tt_miss(tid);
792 break;
793
794 case VEX_TRC_JMP_CLIENTREQ:
795 do_client_request(tid);
796 break;
797
798 case VEX_TRC_JMP_SYSCALL:
799 handle_syscall(tid);
800 if (VG_(clo_sanity_level) > 2)
801 VG_(sanity_check_general)(True); /* sanity-check every syscall */
802 break;
sewardje663cb92002-04-12 10:26:32 +0000803
sewardjb5f6f512005-03-10 23:59:00 +0000804 case VEX_TRC_JMP_YIELD:
805 /* Explicit yield, because this thread is in a spin-lock
sewardj3fc75752005-03-12 15:16:31 +0000806 or something. Only let the thread run for a short while
807 longer. Because swapping to another thread is expensive,
808 we're prepared to let this thread eat a little more CPU
809 before swapping to another. That means that short term
810 spins waiting for hardware to poke memory won't cause a
811 thread swap. */
812 if (VG_(dispatch_ctr) > 100)
813 VG_(dispatch_ctr) = 100;
sewardjb5f6f512005-03-10 23:59:00 +0000814 break;
sewardje663cb92002-04-12 10:26:32 +0000815
sewardjb5f6f512005-03-10 23:59:00 +0000816 case VG_TRC_INNER_COUNTERZERO:
817 /* Timeslice is out. Let a new thread be scheduled. */
818 vg_assert(VG_(dispatch_ctr) == 1);
819 break;
sewardje663cb92002-04-12 10:26:32 +0000820
sewardjb5f6f512005-03-10 23:59:00 +0000821 case VG_TRC_FAULT_SIGNAL:
822 /* Everything should be set up (either we're exiting, or
823 about to start in a signal handler). */
824 break;
sewardj9d1b5d32002-04-17 19:40:49 +0000825
sewardj07bdc5e2005-03-11 13:19:47 +0000826 case VEX_TRC_JMP_MAPFAIL:
827 /* Failure of arch-specific address translation (x86/amd64
828 segment override use) */
829 /* jrs 2005 03 11: is this correct? */
830 VG_(synth_fault)(tid);
831 break;
832
sewardjb5f6f512005-03-10 23:59:00 +0000833 case VEX_TRC_JMP_EMWARN: {
834 static Int counts[EmWarn_NUMBER];
835 static Bool counts_initted = False;
836 VexEmWarn ew;
837 HChar* what;
838 Bool show;
839 Int q;
840 if (!counts_initted) {
841 counts_initted = True;
842 for (q = 0; q < EmWarn_NUMBER; q++)
843 counts[q] = 0;
844 }
845 ew = (VexEmWarn)VG_(threads)[tid].arch.vex.guest_EMWARN;
846 what = (ew < 0 || ew >= EmWarn_NUMBER)
847 ? "unknown (?!)"
848 : LibVEX_EmWarn_string(ew);
849 show = (ew < 0 || ew >= EmWarn_NUMBER)
850 ? True
851 : counts[ew]++ < 3;
sewardjb1131a82005-03-19 15:12:21 +0000852 if (show && VG_(clo_show_emwarns)) {
sewardjb5f6f512005-03-10 23:59:00 +0000853 VG_(message)( Vg_UserMsg,
854 "Emulation warning: unsupported action:");
855 VG_(message)( Vg_UserMsg, " %s", what);
njnd01fef72005-03-25 23:35:48 +0000856 VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
sewardjb5f6f512005-03-10 23:59:00 +0000857 }
858 break;
859 }
sewardje663cb92002-04-12 10:26:32 +0000860
sewardjb5f6f512005-03-10 23:59:00 +0000861 case VEX_TRC_JMP_NODECODE:
862 VG_(synth_sigill)(tid, INSTR_PTR(VG_(threads)[tid].arch));
863 break;
sewardje663cb92002-04-12 10:26:32 +0000864
sewardjb5f6f512005-03-10 23:59:00 +0000865 default:
njn50ae1a72005-04-08 23:28:23 +0000866 vg_assert2(0, "VG_(scheduler), phase 3: "
867 "unexpected thread return code (%u)", trc);
sewardjb5f6f512005-03-10 23:59:00 +0000868 /* NOTREACHED */
869 break;
sewardje663cb92002-04-12 10:26:32 +0000870
871 } /* switch (trc) */
nethercote238a3c32004-08-09 13:13:31 +0000872 }
sewardjc24be7a2005-03-15 01:40:12 +0000873
874 if (VG_(clo_trace_sched))
875 print_sched_event(tid, "exiting VG_(scheduler)");
876
sewardjb5f6f512005-03-10 23:59:00 +0000877 vg_assert(VG_(is_exiting)(tid));
thughes513197c2004-06-13 12:07:53 +0000878
sewardjb5f6f512005-03-10 23:59:00 +0000879 VGP_POPCC(VgpSched);
thughes513197c2004-06-13 12:07:53 +0000880
sewardjb5f6f512005-03-10 23:59:00 +0000881 //if (VG_(clo_model_pthreads))
882 // VG_(tm_thread_exit)(tid);
883
884 return tst->exitreason;
sewardj20917d82002-05-28 01:36:45 +0000885}
886
887
sewardjb5f6f512005-03-10 23:59:00 +0000888/*
889 This causes all threads to forceably exit. They aren't actually
890 dead by the time this returns; you need to call
891 VGA_(reap_threads)() to wait for them.
892 */
893void VG_(nuke_all_threads_except) ( ThreadId me, VgSchedReturnCode src )
sewardjccef2e62002-05-29 19:26:32 +0000894{
895 ThreadId tid;
sewardjb5f6f512005-03-10 23:59:00 +0000896
897 vg_assert(VG_(is_running_thread)(me));
sewardj45f02c42005-02-05 18:27:14 +0000898
sewardjccef2e62002-05-29 19:26:32 +0000899 for (tid = 1; tid < VG_N_THREADS; tid++) {
900 if (tid == me
jsgf855d93d2003-10-13 22:26:55 +0000901 || VG_(threads)[tid].status == VgTs_Empty)
sewardjccef2e62002-05-29 19:26:32 +0000902 continue;
sewardjb5f6f512005-03-10 23:59:00 +0000903 if (0)
sewardjef037c72002-05-30 00:40:03 +0000904 VG_(printf)(
905 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjb5f6f512005-03-10 23:59:00 +0000906
907 VG_(threads)[tid].exitreason = src;
908 VG_(kill_thread)(tid);
sewardjccef2e62002-05-29 19:26:32 +0000909 }
910}
911
912
njnd3040452003-05-19 15:04:06 +0000913/* ---------------------------------------------------------------------
sewardjb5f6f512005-03-10 23:59:00 +0000914 Specifying shadow register values
njnd3040452003-05-19 15:04:06 +0000915 ------------------------------------------------------------------ */
916
njn502badb2005-05-08 02:04:49 +0000917// These macros write a value to a client's thread register, and tell the
918// tool that it's happened (if necessary).
919
920#define SET_CLREQ_RETVAL(zztid, zzval) \
921 do { CLREQ_RET(VG_(threads)[zztid].arch) = (zzval); \
922 VG_TRACK( post_reg_write, \
923 Vg_CoreClientReq, zztid, O_CLREQ_RET, sizeof(UWord)); \
924 } while (0)
925
926#define SET_CLCALL_RETVAL(zztid, zzval, f) \
927 do { CLREQ_RET(VG_(threads)[zztid].arch) = (zzval); \
928 VG_TRACK( post_reg_write_clientcall_return, \
929 zztid, O_CLREQ_RET, sizeof(UWord), f); \
930 } while (0)
931
sewardjb5f6f512005-03-10 23:59:00 +0000932void VG_(set_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
njncf45fd42004-11-24 16:30:22 +0000933 const UChar* area )
njnd3040452003-05-19 15:04:06 +0000934{
njncf45fd42004-11-24 16:30:22 +0000935 ThreadState* tst;
936
937 vg_assert(VG_(is_valid_tid)(tid));
938 tst = & VG_(threads)[tid];
939
940 // Bounds check
941 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
942 vg_assert(offset + size <= sizeof(VexGuestArchState));
943
944 VG_(memcpy)( (void*)(((Addr)(&tst->arch.vex_shadow)) + offset), area, size);
945}
946
sewardjb5f6f512005-03-10 23:59:00 +0000947void VG_(get_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
njncf45fd42004-11-24 16:30:22 +0000948 UChar* area )
949{
950 ThreadState* tst;
951
952 vg_assert(VG_(is_valid_tid)(tid));
953 tst = & VG_(threads)[tid];
954
955 // Bounds check
956 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
957 vg_assert(offset + size <= sizeof(VexGuestArchState));
958
959 VG_(memcpy)( area, (void*)(((Addr)&(tst->arch.vex_shadow)) + offset), size);
960}
961
sewardje663cb92002-04-12 10:26:32 +0000962/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +0000963 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +0000964 ------------------------------------------------------------------ */
965
sewardj124ca2a2002-06-20 10:19:38 +0000966/* Do a client request for the thread tid. After the request, tid may
967 or may not still be runnable; if not, the scheduler will have to
968 choose a new thread to run.
969*/
sewardje663cb92002-04-12 10:26:32 +0000970static
sewardjb5f6f512005-03-10 23:59:00 +0000971void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +0000972{
sewardjb5f6f512005-03-10 23:59:00 +0000973 UWord* arg = (UWord*)(CLREQ_ARGS(VG_(threads)[tid].arch));
nethercoted1b64b22004-11-04 18:22:28 +0000974 UWord req_no = arg[0];
sewardj124ca2a2002-06-20 10:19:38 +0000975
fitzhardinge98abfc72003-12-16 02:05:15 +0000976 if (0)
nethercoted1b64b22004-11-04 18:22:28 +0000977 VG_(printf)("req no = 0x%llx, arg = %p\n", (ULong)req_no, arg);
sewardje663cb92002-04-12 10:26:32 +0000978 switch (req_no) {
979
njn3e884182003-04-15 13:03:23 +0000980 case VG_USERREQ__CLIENT_CALL0: {
njn2ac95242005-03-13 23:07:30 +0000981 UWord (*f)(ThreadId) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000982 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000983 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL0: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +0000984 else
njn2ac95242005-03-13 23:07:30 +0000985 SET_CLCALL_RETVAL(tid, f ( tid ), (Addr)f);
njn3e884182003-04-15 13:03:23 +0000986 break;
987 }
988 case VG_USERREQ__CLIENT_CALL1: {
njn2ac95242005-03-13 23:07:30 +0000989 UWord (*f)(ThreadId, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000990 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000991 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL1: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +0000992 else
njn2ac95242005-03-13 23:07:30 +0000993 SET_CLCALL_RETVAL(tid, f ( tid, arg[2] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +0000994 break;
995 }
996 case VG_USERREQ__CLIENT_CALL2: {
njn2ac95242005-03-13 23:07:30 +0000997 UWord (*f)(ThreadId, UWord, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000998 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000999 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL2: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +00001000 else
njn2ac95242005-03-13 23:07:30 +00001001 SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +00001002 break;
1003 }
1004 case VG_USERREQ__CLIENT_CALL3: {
njn2ac95242005-03-13 23:07:30 +00001005 UWord (*f)(ThreadId, UWord, UWord, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +00001006 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +00001007 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL3: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +00001008 else
njn2ac95242005-03-13 23:07:30 +00001009 SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3], arg[4] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +00001010 break;
1011 }
1012
njnf09745a2005-05-10 03:01:23 +00001013 // Nb: this looks like a circular definition, because it kind of is.
1014 // See comment in valgrind.h to understand what's going on.
sewardj124ca2a2002-06-20 10:19:38 +00001015 case VG_USERREQ__RUNNING_ON_VALGRIND:
sewardjb5f6f512005-03-10 23:59:00 +00001016 SET_CLREQ_RETVAL(tid, RUNNING_ON_VALGRIND+1);
sewardj124ca2a2002-06-20 10:19:38 +00001017 break;
1018
fitzhardinge39de4b42003-10-31 07:12:21 +00001019 case VG_USERREQ__PRINTF: {
1020 int count =
nethercote3e901a22004-09-11 13:17:02 +00001021 VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );
fitzhardinge39de4b42003-10-31 07:12:21 +00001022 SET_CLREQ_RETVAL( tid, count );
1023 break; }
1024
1025 case VG_USERREQ__INTERNAL_PRINTF: {
1026 int count =
njnaa3c26b2005-03-12 05:32:28 +00001027 VG_(vmessage)( Vg_DebugMsg, (char *)arg[1], (void*)arg[2] );
fitzhardinge39de4b42003-10-31 07:12:21 +00001028 SET_CLREQ_RETVAL( tid, count );
1029 break; }
1030
1031 case VG_USERREQ__PRINTF_BACKTRACE: {
fitzhardinge39de4b42003-10-31 07:12:21 +00001032 int count =
nethercote3e901a22004-09-11 13:17:02 +00001033 VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );
njnd01fef72005-03-25 23:35:48 +00001034 VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
fitzhardinge39de4b42003-10-31 07:12:21 +00001035 SET_CLREQ_RETVAL( tid, count );
1036 break; }
1037
fitzhardinge98abfc72003-12-16 02:05:15 +00001038 case VG_USERREQ__GET_MALLOCFUNCS: {
1039 struct vg_mallocfunc_info *info = (struct vg_mallocfunc_info *)arg[1];
1040
njncf81d552005-03-31 04:52:26 +00001041 info->tl_malloc = VG_(tdict).malloc_malloc;
1042 info->tl_calloc = VG_(tdict).malloc_calloc;
1043 info->tl_realloc = VG_(tdict).malloc_realloc;
1044 info->tl_memalign = VG_(tdict).malloc_memalign;
1045 info->tl___builtin_new = VG_(tdict).malloc___builtin_new;
1046 info->tl___builtin_vec_new = VG_(tdict).malloc___builtin_vec_new;
1047 info->tl_free = VG_(tdict).malloc_free;
1048 info->tl___builtin_delete = VG_(tdict).malloc___builtin_delete;
1049 info->tl___builtin_vec_delete = VG_(tdict).malloc___builtin_vec_delete;
fitzhardinge98abfc72003-12-16 02:05:15 +00001050
njncf81d552005-03-31 04:52:26 +00001051 info->arena_payload_szB = VG_(arena_payload_szB);
sewardjb5f6f512005-03-10 23:59:00 +00001052 info->clo_trace_malloc = VG_(clo_trace_malloc);
fitzhardinge98abfc72003-12-16 02:05:15 +00001053
1054 SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
1055
1056 break;
1057 }
1058
njn25e49d8e72002-09-23 09:36:25 +00001059 /* Requests from the client program */
1060
1061 case VG_USERREQ__DISCARD_TRANSLATIONS:
1062 if (VG_(clo_verbosity) > 2)
1063 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
1064 " addr %p, len %d\n",
1065 (void*)arg[1], arg[2] );
1066
sewardjfa8ec112005-01-19 11:55:34 +00001067 VG_(discard_translations)( arg[1], arg[2] );
njn25e49d8e72002-09-23 09:36:25 +00001068
njnd3040452003-05-19 15:04:06 +00001069 SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
njn25e49d8e72002-09-23 09:36:25 +00001070 break;
1071
njn47363ab2003-04-21 13:24:40 +00001072 case VG_USERREQ__COUNT_ERRORS:
nethercotef2b11482004-08-02 12:36:01 +00001073 SET_CLREQ_RETVAL( tid, VG_(get_n_errs_found)() );
njn47363ab2003-04-21 13:24:40 +00001074 break;
1075
sewardje663cb92002-04-12 10:26:32 +00001076 default:
sewardjb5f6f512005-03-10 23:59:00 +00001077 if (VGA_(client_request)(tid, arg)) {
1078 /* architecture handled the client request */
1079 } else if (VG_(needs).client_requests) {
nethercoted1b64b22004-11-04 18:22:28 +00001080 UWord ret;
sewardj34042512002-10-22 04:14:35 +00001081
njn25e49d8e72002-09-23 09:36:25 +00001082 if (VG_(clo_verbosity) > 2)
fitzhardinge98abfc72003-12-16 02:05:15 +00001083 VG_(printf)("client request: code %x, addr %p, len %d\n",
njn25e49d8e72002-09-23 09:36:25 +00001084 arg[0], (void*)arg[1], arg[2] );
1085
njn51d827b2005-05-09 01:02:08 +00001086 if ( VG_TDICT_CALL(tool_handle_client_request, tid, arg, &ret) )
sewardjb5f6f512005-03-10 23:59:00 +00001087 SET_CLREQ_RETVAL(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00001088 } else {
sewardj34042512002-10-22 04:14:35 +00001089 static Bool whined = False;
1090
sewardjb5f6f512005-03-10 23:59:00 +00001091 if (!whined && VG_(clo_verbosity) > 2) {
nethercote7cc9c232004-01-21 15:08:04 +00001092 // Allow for requests in core, but defined by tools, which
njnd7994182003-10-02 13:44:04 +00001093 // have 0 and 0 in their two high bytes.
1094 Char c1 = (arg[0] >> 24) & 0xff;
1095 Char c2 = (arg[0] >> 16) & 0xff;
1096 if (c1 == 0) c1 = '_';
1097 if (c2 == 0) c2 = '_';
sewardj34042512002-10-22 04:14:35 +00001098 VG_(message)(Vg_UserMsg, "Warning:\n"
njnd7994182003-10-02 13:44:04 +00001099 " unhandled client request: 0x%x (%c%c+0x%x). Perhaps\n"
1100 " VG_(needs).client_requests should be set?\n",
1101 arg[0], c1, c2, arg[0] & 0xffff);
sewardj34042512002-10-22 04:14:35 +00001102 whined = True;
1103 }
njn25e49d8e72002-09-23 09:36:25 +00001104 }
sewardje663cb92002-04-12 10:26:32 +00001105 break;
1106 }
1107}
1108
1109
sewardj6072c362002-04-19 14:40:57 +00001110/* ---------------------------------------------------------------------
1111 Sanity checking.
1112 ------------------------------------------------------------------ */
1113
sewardjb5f6f512005-03-10 23:59:00 +00001114/* Internal consistency checks on the sched structures. */
sewardj6072c362002-04-19 14:40:57 +00001115static
sewardjb5f6f512005-03-10 23:59:00 +00001116void scheduler_sanity ( ThreadId tid )
sewardj6072c362002-04-19 14:40:57 +00001117{
sewardjb5f6f512005-03-10 23:59:00 +00001118 Bool bad = False;
jsgf855d93d2003-10-13 22:26:55 +00001119
sewardjb5f6f512005-03-10 23:59:00 +00001120 if (!VG_(is_running_thread)(tid)) {
1121 VG_(message)(Vg_DebugMsg,
1122 "Thread %d is supposed to be running, but doesn't own run_sema (owned by %d)\n",
1123 tid, running_tid);
1124 bad = True;
jsgf855d93d2003-10-13 22:26:55 +00001125 }
sewardj5f07b662002-04-23 16:52:51 +00001126
sewardjb5f6f512005-03-10 23:59:00 +00001127 if (VG_(gettid)() != VG_(threads)[tid].os_state.lwpid) {
1128 VG_(message)(Vg_DebugMsg,
njnd06ed472005-03-13 05:12:31 +00001129 "Thread %d supposed to be in LWP %d, but we're actually %d\n",
1130 tid, VG_(threads)[tid].os_state.lwpid, VG_(gettid)());
sewardjb5f6f512005-03-10 23:59:00 +00001131 bad = True;
sewardj5f07b662002-04-23 16:52:51 +00001132 }
sewardj6072c362002-04-19 14:40:57 +00001133}
1134
1135
sewardje663cb92002-04-12 10:26:32 +00001136/*--------------------------------------------------------------------*/
njn278b3d62005-05-30 23:20:51 +00001137/*--- end ---*/
sewardje663cb92002-04-12 10:26:32 +00001138/*--------------------------------------------------------------------*/