blob: 66eba36655521a3d16819cab7d6dd93ccadd1934 [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/*--------------------------------------------------------------------*/
sewardjb5f6f512005-03-10 23:59:00 +00003/*--- Thread scheduling. vg_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
njnd01fef72005-03-25 23:35:48 +000063#include "pub_core_stacktrace.h"
64
sewardje663cb92002-04-12 10:26:32 +000065
66/* ---------------------------------------------------------------------
67 Types and globals for the scheduler.
68 ------------------------------------------------------------------ */
69
rjwalsh7109a8c2004-09-02 00:31:02 +000070/* ThreadId and ThreadState are defined in core.h. */
sewardje663cb92002-04-12 10:26:32 +000071
njn14319cc2005-03-13 06:26:22 +000072/* Defines the thread-scheduling timeslice, in terms of the number of
73 basic blocks we attempt to run each thread for. Smaller values
74 give finer interleaving but much increased scheduling overheads. */
75#define SCHEDULING_QUANTUM 50000
76
sewardj018f7622002-05-15 21:13:39 +000077/* Globals. A statically allocated array of threads. NOTE: [0] is
78 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000079 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000080ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000081
sewardjb5f6f512005-03-10 23:59:00 +000082/* If true, a fault is Valgrind-internal (ie, a bug) */
83Bool VG_(my_fault) = True;
njn25e49d8e72002-09-23 09:36:25 +000084
sewardje663cb92002-04-12 10:26:32 +000085/* Forwards */
sewardjb5f6f512005-03-10 23:59:00 +000086static void do_client_request ( ThreadId tid );
87static void scheduler_sanity ( ThreadId tid );
88static void mostly_clear_thread_record ( ThreadId tid );
89static const HChar *name_of_thread_state ( ThreadStatus );
sewardjd140e442002-05-29 01:21:19 +000090
nethercote844e7122004-08-02 15:27:22 +000091/* Stats. */
92static UInt n_scheduling_events_MINOR = 0;
93static UInt n_scheduling_events_MAJOR = 0;
94
sewardjb5f6f512005-03-10 23:59:00 +000095
nethercote844e7122004-08-02 15:27:22 +000096void VG_(print_scheduler_stats)(void)
97{
98 VG_(message)(Vg_DebugMsg,
99 " %d/%d major/minor sched events.",
100 n_scheduling_events_MAJOR, n_scheduling_events_MINOR);
101}
102
sewardjb5f6f512005-03-10 23:59:00 +0000103/* CPU semaphore, so that threads can run exclusively */
104static vg_sema_t run_sema;
105static ThreadId running_tid = VG_INVALID_THREADID;
106
107
sewardje663cb92002-04-12 10:26:32 +0000108/* ---------------------------------------------------------------------
109 Helper functions for the scheduler.
110 ------------------------------------------------------------------ */
111
sewardjb48e5002002-05-13 00:16:03 +0000112__inline__
113Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000114{
115 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000116 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000117 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000118 if (VG_(threads)[tid].status == VgTs_Empty) return False;
119 return True;
120}
121
122
123__inline__
sewardjb5f6f512005-03-10 23:59:00 +0000124static Bool is_valid_or_empty_tid ( ThreadId tid )
sewardj018f7622002-05-15 21:13:39 +0000125{
126 /* tid is unsigned, hence no < 0 test. */
127 if (tid == 0) return False;
128 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000129 return True;
130}
131
132
sewardj1e8cdc92002-04-18 11:37:52 +0000133/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000134 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
sewardj2a99cf62004-11-24 10:44:19 +0000135 if none do.
sewardj1e8cdc92002-04-18 11:37:52 +0000136*/
njn43c799e2003-04-08 00:08:52 +0000137ThreadId VG_(first_matching_thread_stack)
thughes4ad52d02004-06-27 17:37:21 +0000138 ( Bool (*p) ( Addr stack_min, Addr stack_max, void* d ),
139 void* d )
sewardj1e8cdc92002-04-18 11:37:52 +0000140{
sewardjb5f6f512005-03-10 23:59:00 +0000141 ThreadId tid;
sewardj1e8cdc92002-04-18 11:37:52 +0000142
sewardj6072c362002-04-19 14:40:57 +0000143 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000144 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardjb5f6f512005-03-10 23:59:00 +0000145
njncf45fd42004-11-24 16:30:22 +0000146 if ( p ( STACK_PTR(VG_(threads)[tid].arch),
thughes4ad52d02004-06-27 17:37:21 +0000147 VG_(threads)[tid].stack_highest_word, d ) )
sewardj1e8cdc92002-04-18 11:37:52 +0000148 return tid;
149 }
150 return VG_INVALID_THREADID;
151}
152
sewardjb5f6f512005-03-10 23:59:00 +0000153void VG_(mark_from_registers)(void (*mark_addr)(Addr))
154{
155 ThreadId tid;
156
157 for(tid = 1; tid < VG_N_THREADS; tid++) {
158 if (!VG_(is_valid_tid)(tid))
159 continue;
160 VGA_(mark_from_registers)(tid, mark_addr);
161 }
162}
sewardj1e8cdc92002-04-18 11:37:52 +0000163
sewardj15a43e12002-04-17 19:35:12 +0000164/* Print the scheduler status. */
165void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000166{
167 Int i;
168 VG_(printf)("\nsched status:\n");
sewardjb5f6f512005-03-10 23:59:00 +0000169 VG_(printf)(" running_tid=%d\n", running_tid);
sewardj6072c362002-04-19 14:40:57 +0000170 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000171 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardjb5f6f512005-03-10 23:59:00 +0000172 VG_(printf)("\nThread %d: status = %s\n", i, name_of_thread_state(VG_(threads)[i].status));
njnd01fef72005-03-25 23:35:48 +0000173 VG_(get_and_pp_StackTrace)( i, VG_(clo_backtrace_size) );
sewardje663cb92002-04-12 10:26:32 +0000174 }
175 VG_(printf)("\n");
176}
177
sewardje663cb92002-04-12 10:26:32 +0000178static
179void print_sched_event ( ThreadId tid, Char* what )
180{
sewardj45b4b372002-04-16 22:50:32 +0000181 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000182}
183
sewardj8937c812002-04-12 20:12:20 +0000184static
sewardjb5f6f512005-03-10 23:59:00 +0000185HChar* name_of_sched_event ( UInt event )
sewardje663cb92002-04-12 10:26:32 +0000186{
187 switch (event) {
sewardjd79ef682004-11-26 13:25:17 +0000188 case VEX_TRC_JMP_SYSCALL: return "SYSCALL";
189 case VEX_TRC_JMP_CLIENTREQ: return "CLIENTREQ";
190 case VEX_TRC_JMP_YIELD: return "YIELD";
sewardj45f02c42005-02-05 18:27:14 +0000191 case VEX_TRC_JMP_NODECODE: return "NODECODE";
sewardje663cb92002-04-12 10:26:32 +0000192 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
193 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
sewardjb5f6f512005-03-10 23:59:00 +0000194 case VG_TRC_FAULT_SIGNAL: return "FAULTSIGNAL";
sewardje663cb92002-04-12 10:26:32 +0000195 default: return "??UNKNOWN??";
196 }
197}
198
sewardjb5f6f512005-03-10 23:59:00 +0000199static
200const HChar* name_of_thread_state ( ThreadStatus state )
201{
202 switch (state) {
203 case VgTs_Empty: return "VgTs_Empty";
204 case VgTs_Init: return "VgTs_Init";
205 case VgTs_Runnable: return "VgTs_Runnable";
206 case VgTs_WaitSys: return "VgTs_WaitSys";
207 case VgTs_Yielding: return "VgTs_Yielding";
208 case VgTs_Zombie: return "VgTs_Zombie";
209 default: return "VgTs_???";
210 }
211}
sewardje663cb92002-04-12 10:26:32 +0000212
sewardje663cb92002-04-12 10:26:32 +0000213/* Allocate a completely empty ThreadState record. */
sewardjb5f6f512005-03-10 23:59:00 +0000214ThreadId VG_(alloc_ThreadState) ( void )
sewardje663cb92002-04-12 10:26:32 +0000215{
216 Int i;
sewardj6072c362002-04-19 14:40:57 +0000217 for (i = 1; i < VG_N_THREADS; i++) {
sewardjb5f6f512005-03-10 23:59:00 +0000218 if (VG_(threads)[i].status == VgTs_Empty) {
219 VG_(threads)[i].status = VgTs_Init;
220 VG_(threads)[i].exitreason = VgSrc_None;
sewardje663cb92002-04-12 10:26:32 +0000221 return i;
sewardjb5f6f512005-03-10 23:59:00 +0000222 }
sewardje663cb92002-04-12 10:26:32 +0000223 }
224 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
225 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000226 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000227 /*NOTREACHED*/
228}
229
jsgf855d93d2003-10-13 22:26:55 +0000230ThreadState *VG_(get_ThreadState)(ThreadId tid)
231{
232 vg_assert(tid >= 0 && tid < VG_N_THREADS);
233 return &VG_(threads)[tid];
234}
235
sewardjb5f6f512005-03-10 23:59:00 +0000236/* Given an LWP id (ie, real kernel thread id), find the corresponding
237 ThreadId */
238ThreadId VG_(get_lwp_tid)(Int lwp)
njn25e49d8e72002-09-23 09:36:25 +0000239{
sewardjb5f6f512005-03-10 23:59:00 +0000240 ThreadId tid;
nethercote75d26242004-08-01 22:59:18 +0000241
sewardjb5f6f512005-03-10 23:59:00 +0000242 for(tid = 1; tid <= VG_N_THREADS; tid++)
243 if (VG_(threads)[tid].status != VgTs_Empty && VG_(threads)[tid].os_state.lwpid == lwp)
244 return tid;
245
246 return VG_INVALID_THREADID;
247}
248
249/*
250 Mark a thread as Runnable. This will block until the run_sema is
251 available, so that we get exclusive access to all the shared
252 structures and the CPU. Up until we get the sema, we must not
253 touch any shared state.
254
255 When this returns, we'll actually be running.
256 */
257void VG_(set_running)(ThreadId tid)
258{
259 ThreadState *tst = VG_(get_ThreadState)(tid);
260
261 vg_assert(tst->status != VgTs_Runnable);
262
263 tst->status = VgTs_Runnable;
264
265 VG_(sema_down)(&run_sema);
266 if (running_tid != VG_INVALID_THREADID)
267 VG_(printf)("tid %d found %d running\n", tid, running_tid);
268 vg_assert(running_tid == VG_INVALID_THREADID);
269 running_tid = tid;
270
271 if (VG_(clo_trace_sched))
272 print_sched_event(tid, "now running");
273}
274
275ThreadId VG_(get_running_tid)(void)
276{
277 return running_tid;
278}
279
280Bool VG_(is_running_thread)(ThreadId tid)
281{
282 ThreadState *tst = VG_(get_ThreadState)(tid);
283
284 return
285// tst->os_state.lwpid == VG_(gettid)() && /* check we're this tid */
286 running_tid == tid && /* and that we've got the lock */
287 tst->status == VgTs_Runnable; /* and we're runnable */
288}
289
290/* Return the number of non-dead Threads */
291Int VG_(count_living_threads)(void)
292{
293 Int count = 0;
294 ThreadId tid;
295
296 for(tid = 1; tid < VG_N_THREADS; tid++)
297 if (VG_(threads)[tid].status != VgTs_Empty &&
298 VG_(threads)[tid].status != VgTs_Zombie)
299 count++;
300
301 return count;
302}
303
304/*
305 Set a thread into a sleeping state, and give up exclusive access to
306 the CPU. On return, the thread must be prepared to block until it
307 is ready to run again (generally this means blocking in a syscall,
308 but it may mean that we remain in a Runnable state and we're just
309 yielding the CPU to another thread).
310 */
311void VG_(set_sleeping)(ThreadId tid, ThreadStatus sleepstate)
312{
313 ThreadState *tst = VG_(get_ThreadState)(tid);
314
315 vg_assert(tst->status == VgTs_Runnable);
316
317 vg_assert(sleepstate == VgTs_WaitSys ||
318 sleepstate == VgTs_Yielding);
319
320 tst->status = sleepstate;
321
322 vg_assert(running_tid == tid);
323 running_tid = VG_INVALID_THREADID;
324
325 /* Release the run_sema; this will reschedule any runnable
326 thread. */
327 VG_(sema_up)(&run_sema);
328
329 if (VG_(clo_trace_sched)) {
330 Char buf[50];
331 VG_(sprintf)(buf, "now sleeping in state %s", name_of_thread_state(sleepstate));
332 print_sched_event(tid, buf);
nethercote75d26242004-08-01 22:59:18 +0000333 }
334}
335
sewardjb5f6f512005-03-10 23:59:00 +0000336/* Return true if the thread is still alive but in the process of
337 exiting. */
338inline Bool VG_(is_exiting)(ThreadId tid)
339{
340 vg_assert(VG_(is_valid_tid)(tid));
341 return VG_(threads)[tid].exitreason != VgSrc_None;
342}
sewardj2a99cf62004-11-24 10:44:19 +0000343
sewardjb5f6f512005-03-10 23:59:00 +0000344/* Clear out the ThreadState and release the semaphore. Leaves the
345 ThreadState in VgTs_Zombie state, so that it doesn't get
346 reallocated until the caller is really ready. */
347void VG_(exit_thread)(ThreadId tid)
348{
349 vg_assert(VG_(is_valid_tid)(tid));
350 vg_assert(VG_(is_running_thread)(tid));
351 vg_assert(VG_(is_exiting)(tid));
352
353 /* It's stack is now off-limits
354
355 XXX Don't do this - the client thread implementation can touch
356 the stack after thread death... */
357 if (0 && VG_(threads)[tid].stack_base) {
358 Segment *seg = VG_(find_segment)( VG_(threads)[tid].stack_base );
359 if (seg)
360 VG_TRACK( die_mem_stack, seg->addr, seg->len );
361 }
362
363 VGA_(cleanup_thread)( &VG_(threads)[tid].arch );
364
365 mostly_clear_thread_record(tid);
366 running_tid = VG_INVALID_THREADID;
367
368 /* There should still be a valid exitreason for this thread */
369 vg_assert(VG_(threads)[tid].exitreason != VgSrc_None);
370
371 VG_(sema_up)(&run_sema);
372}
373
374/* Kill a thread. This interrupts whatever a thread is doing, and
375 makes it exit ASAP. This does not set the exitreason or
376 exitcode. */
377void VG_(kill_thread)(ThreadId tid)
378{
379 vg_assert(VG_(is_valid_tid)(tid));
380 vg_assert(!VG_(is_running_thread)(tid));
381 vg_assert(VG_(is_exiting)(tid));
382
383 if (VG_(threads)[tid].status == VgTs_WaitSys) {
384 if (VG_(clo_trace_signals))
385 VG_(message)(Vg_DebugMsg, "kill_thread zaps tid %d lwp %d",
386 tid, VG_(threads)[tid].os_state.lwpid);
387 VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VKI_SIGVGKILL);
388 }
389}
390
391/*
392 Yield the CPU for a short time to let some other thread run.
393 */
394void VG_(vg_yield)(void)
395{
396 struct vki_timespec ts = { 0, 1 };
397 ThreadId tid = running_tid;
398
399 vg_assert(tid != VG_INVALID_THREADID);
400 vg_assert(VG_(threads)[tid].os_state.lwpid == VG_(gettid)());
401
402 VG_(set_sleeping)(tid, VgTs_Yielding);
403
404 //VG_(printf)("tid %d yielding EIP=%p\n", tid, VG_(threads)[tid].arch.m_eip);
405
406 /*
407 Tell the kernel we're yielding.
408 */
409 if (1)
410 VG_(do_syscall0)(__NR_sched_yield);
411 else
412 VG_(nanosleep)(&ts);
413
414 VG_(set_running)(tid);
415
416 VG_(poll_signals)(tid); /* something might have happened */
417}
418
419
420void VG_(resume_scheduler)(ThreadId tid)
421{
422 ThreadState *tst = VG_(get_ThreadState)(tid);
423
424 vg_assert(tst->os_state.lwpid == VG_(gettid)());
425
426 if (tst->sched_jmpbuf_valid) {
427 /* Can't continue; must longjmp back to the scheduler and thus
428 enter the sighandler immediately. */
429
430 LONGJMP(tst->sched_jmpbuf, True);
431 }
432}
433
434#define SCHEDSETJMP(tid, jumped, stmt) \
435 do { \
436 ThreadState * volatile _qq_tst = VG_(get_ThreadState)(tid); \
437 \
438 (jumped) = SETJMP(_qq_tst->sched_jmpbuf); \
439 if ((jumped) == 0) { \
440 vg_assert(!_qq_tst->sched_jmpbuf_valid); \
441 _qq_tst->sched_jmpbuf_valid = True; \
442 stmt; \
443 } else if (VG_(clo_trace_sched)) \
444 VG_(printf)("SCHEDSETJMP(line %d) tid %d, jumped=%d\n", __LINE__, tid, jumped); \
445 vg_assert(_qq_tst->sched_jmpbuf_valid); \
446 _qq_tst->sched_jmpbuf_valid = False; \
447 } while(0)
448
449/* Run the thread tid for a while, and return a VG_TRC_* value to the
450 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000451static
sewardje663cb92002-04-12 10:26:32 +0000452UInt run_thread_for_a_while ( ThreadId tid )
453{
sewardjb5f6f512005-03-10 23:59:00 +0000454 volatile Bool jumped;
455 volatile ThreadState *tst = VG_(get_ThreadState)(tid);
456 //volatile Addr EIP = tst->arch.m_eip;
457 //volatile Addr nextEIP;
458
sewardj7ccc5c22002-04-24 21:39:11 +0000459 volatile UInt trc = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000460 volatile Int dispatch_ctr_SAVED = VG_(dispatch_ctr);
461 volatile Int done_this_time;
sewardj8b635a42004-11-22 19:01:47 +0000462
sewardj873b3132004-11-25 22:50:17 +0000463 /* For paranoia purposes only */
464 volatile Addr a_vex = (Addr) & VG_(threads)[tid].arch.vex;
465 volatile Addr a_vexsh = (Addr) & VG_(threads)[tid].arch.vex_shadow;
466 volatile Addr a_spill = (Addr) & VG_(threads)[tid].arch.vex_spill;
467 volatile UInt sz_vex = (UInt) sizeof VG_(threads)[tid].arch.vex;
468 volatile UInt sz_vexsh = (UInt) sizeof VG_(threads)[tid].arch.vex_shadow;
469 volatile UInt sz_spill = (UInt) sizeof VG_(threads)[tid].arch.vex_spill;
470
471 /* Paranoia */
sewardjb48e5002002-05-13 00:16:03 +0000472 vg_assert(VG_(is_valid_tid)(tid));
sewardjb5f6f512005-03-10 23:59:00 +0000473 vg_assert(VG_(is_valid_tid)(tid));
474 vg_assert(VG_(is_running_thread)(tid));
475 vg_assert(!VG_(is_exiting)(tid));
sewardje663cb92002-04-12 10:26:32 +0000476
sewardj873b3132004-11-25 22:50:17 +0000477 /* Even more paranoia. Check that what we have matches
478 Vex's guest state layout requirements. */
sewardj12a74b52004-11-26 11:57:41 +0000479 if (0)
480 VG_(printf)("%p %d %p %d %p %d\n",
sewardjb5f6f512005-03-10 23:59:00 +0000481 (void*)a_vex, sz_vex, (void*)a_vexsh, sz_vexsh,
482 (void*)a_spill, sz_spill );
sewardj873b3132004-11-25 22:50:17 +0000483
484 vg_assert(IS_8_ALIGNED(sz_vex));
485 vg_assert(IS_8_ALIGNED(sz_vexsh));
sewardj12a74b52004-11-26 11:57:41 +0000486 vg_assert(IS_16_ALIGNED(sz_spill));
487
488 vg_assert(IS_4_ALIGNED(a_vex));
489 vg_assert(IS_4_ALIGNED(a_vexsh));
490 vg_assert(IS_4_ALIGNED(a_spill));
sewardj873b3132004-11-25 22:50:17 +0000491
492 vg_assert(sz_vex == sz_vexsh);
493 vg_assert(a_vex + sz_vex == a_vexsh);
494
495 vg_assert(sz_spill == LibVEX_N_SPILL_BYTES);
496 vg_assert(a_vex + 2 * sz_vex == a_spill);
497
sewardj45f02c42005-02-05 18:27:14 +0000498 vg_assert(VG_(instr_ptr_offset) >= 0);
499 vg_assert(VG_(instr_ptr_offset) <= 10000); /* let's say */
500 vg_assert(sizeof VG_(instr_ptr_offset) == sizeof(HWord));
501
sewardj671ff542002-05-07 09:25:30 +0000502 VGP_PUSHCC(VgpRun);
jsgf855d93d2003-10-13 22:26:55 +0000503
504 /* there should be no undealt-with signals */
sewardjb5f6f512005-03-10 23:59:00 +0000505 //vg_assert(VG_(threads)[tid].siginfo.si_signo == 0);
jsgf855d93d2003-10-13 22:26:55 +0000506
sewardjb5f6f512005-03-10 23:59:00 +0000507 //VG_(printf)("running EIP = %p ESP=%p\n", VG_(threads)[tid].arch.m_eip, VG_(threads)[tid].arch.m_esp);
508
509 vg_assert(VG_(my_fault));
510 VG_(my_fault) = False;
511
njn84ba89b2005-03-15 01:20:08 +0000512 SCHEDSETJMP(tid, jumped, trc = VG_(run_innerloop)( (void*)&tst->arch.vex ));
sewardjb5f6f512005-03-10 23:59:00 +0000513
514 //nextEIP = tst->arch.m_eip;
515 //if (nextEIP >= VG_(client_end))
516 // VG_(printf)("trc=%d jump to %p from %p\n",
517 // trc, nextEIP, EIP);
518
519 VG_(my_fault) = True;
520
521 if (jumped) {
sewardje663cb92002-04-12 10:26:32 +0000522 /* We get here if the client took a fault, which caused our
523 signal handler to longjmp. */
524 vg_assert(trc == 0);
sewardjb5f6f512005-03-10 23:59:00 +0000525 trc = VG_TRC_FAULT_SIGNAL;
526 VG_(block_signals)(tid);
527 }
sewardj5390e662005-01-10 16:51:14 +0000528
sewardj8b635a42004-11-22 19:01:47 +0000529 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 0;
530
531 vg_assert(done_this_time >= 0);
532 VG_(bbs_done) += (ULong)done_this_time;
533
njn25e49d8e72002-09-23 09:36:25 +0000534 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000535 return trc;
536}
537
538
sewardj20917d82002-05-28 01:36:45 +0000539static
540void mostly_clear_thread_record ( ThreadId tid )
541{
sewardjb5f6f512005-03-10 23:59:00 +0000542 vki_sigset_t savedmask;
543
sewardj20917d82002-05-28 01:36:45 +0000544 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj19fc30e2004-12-13 10:52:08 +0000545 VGA_(cleanup_thread)(&VG_(threads)[tid].arch);
sewardjb5f6f512005-03-10 23:59:00 +0000546 VG_(threads)[tid].tid = tid;
547
548 /* Leave the thread in Zombie, so that it doesn't get reallocated
549 until the caller is finally done with the thread stack. */
550 VG_(threads)[tid].status = VgTs_Zombie;
551
552 VG_(threads)[tid].syscallno = -1;
553
nethercote73b526f2004-10-31 18:48:21 +0000554 VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
sewardjb5f6f512005-03-10 23:59:00 +0000555 VG_(sigemptyset)(&VG_(threads)[tid].tmp_sig_mask);
jsgf855d93d2003-10-13 22:26:55 +0000556
sewardjb5f6f512005-03-10 23:59:00 +0000557 VGA_(os_state_clear)(&VG_(threads)[tid]);
fitzhardinge28428592004-03-16 22:07:12 +0000558
559 /* start with no altstack */
560 VG_(threads)[tid].altstack.ss_sp = (void *)0xdeadbeef;
561 VG_(threads)[tid].altstack.ss_size = 0;
562 VG_(threads)[tid].altstack.ss_flags = VKI_SS_DISABLE;
sewardjb5f6f512005-03-10 23:59:00 +0000563
564 /* clear out queued signals */
565 VG_(block_all_host_signals)(&savedmask);
566 if (VG_(threads)[tid].sig_queue != NULL) {
567 VG_(arena_free)(VG_AR_CORE, VG_(threads)[tid].sig_queue);
568 VG_(threads)[tid].sig_queue = NULL;
569 }
570 VG_(restore_all_host_signals)(&savedmask);
571
572 VG_(threads)[tid].sched_jmpbuf_valid = False;
sewardj20917d82002-05-28 01:36:45 +0000573}
574
njn3f8c4372005-03-13 04:43:10 +0000575/*
576 Called in the child after fork. If the parent has multiple
577 threads, then we've inhereted a VG_(threads) array describing them,
578 but only the thread which called fork() is actually alive in the
579 child. This functions needs to clean up all those other thread
580 structures.
581
582 Whichever tid in the parent which called fork() becomes the
583 master_tid in the child. That's because the only living slot in
584 VG_(threads) in the child after fork is VG_(threads)[tid], and it
585 would be too hard to try to re-number the thread and relocate the
586 thread state down to VG_(threads)[1].
587
588 This function also needs to reinitialize the run_sema, since
589 otherwise we may end up sharing its state with the parent, which
590 would be deeply confusing.
591*/
sewardjb5f6f512005-03-10 23:59:00 +0000592static void sched_fork_cleanup(ThreadId me)
593{
594 ThreadId tid;
595 vg_assert(running_tid == me);
596
597 VG_(master_tid) = me;
598
599 VG_(threads)[me].os_state.lwpid = VG_(gettid)();
600 VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
601
602 /* clear out all the unused thread slots */
603 for (tid = 1; tid < VG_N_THREADS; tid++) {
njn3f8c4372005-03-13 04:43:10 +0000604 if (tid != me) {
605 mostly_clear_thread_record(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000606 VG_(threads)[tid].status = VgTs_Empty;
njn3f8c4372005-03-13 04:43:10 +0000607 }
sewardjb5f6f512005-03-10 23:59:00 +0000608 }
609
610 /* re-init and take the sema */
611 VG_(sema_deinit)(&run_sema);
612 VG_(sema_init)(&run_sema);
613 VG_(sema_down)(&run_sema);
614}
sewardj20917d82002-05-28 01:36:45 +0000615
jsgf855d93d2003-10-13 22:26:55 +0000616
sewardje663cb92002-04-12 10:26:32 +0000617/* Initialise the scheduler. Create a single "main" thread ready to
sewardj2a99cf62004-11-24 10:44:19 +0000618 run, with special ThreadId of one. This is called at startup. The
sewardjb5f6f512005-03-10 23:59:00 +0000619 caller subsequently initialises the guest state components of this
620 main thread, thread 1.
sewardje663cb92002-04-12 10:26:32 +0000621*/
622void VG_(scheduler_init) ( void )
623{
thughesc37184f2004-09-11 14:16:57 +0000624 Int i;
sewardje663cb92002-04-12 10:26:32 +0000625 ThreadId tid_main;
626
sewardjb5f6f512005-03-10 23:59:00 +0000627 VG_(sema_init)(&run_sema);
628
sewardj6072c362002-04-19 14:40:57 +0000629 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardjb5f6f512005-03-10 23:59:00 +0000630 VG_(threads)[i].sig_queue = NULL;
631
632 VGA_(os_state_init)(&VG_(threads)[i]);
sewardj20917d82002-05-28 01:36:45 +0000633 mostly_clear_thread_record(i);
sewardjb5f6f512005-03-10 23:59:00 +0000634
635 VG_(threads)[i].status = VgTs_Empty;
sewardj20917d82002-05-28 01:36:45 +0000636 VG_(threads)[i].stack_size = 0;
637 VG_(threads)[i].stack_base = (Addr)NULL;
638 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000639 }
640
sewardjb5f6f512005-03-10 23:59:00 +0000641 tid_main = VG_(alloc_ThreadState)();
sewardj5f07b662002-04-23 16:52:51 +0000642
sewardjb5f6f512005-03-10 23:59:00 +0000643 VG_(master_tid) = tid_main;
sewardj2cb00342002-06-28 01:46:26 +0000644
sewardjb5f6f512005-03-10 23:59:00 +0000645 /* Initial thread's stack is the original process stack */
646 VG_(threads)[tid_main].stack_highest_word = VG_(clstk_end) - sizeof(UInt);
fitzhardinge98abfc72003-12-16 02:05:15 +0000647 VG_(threads)[tid_main].stack_base = VG_(clstk_base);
thughesc37184f2004-09-11 14:16:57 +0000648 VG_(threads)[tid_main].stack_size = VG_(client_rlimit_stack).rlim_cur;
sewardjbf290b92002-05-01 02:28:01 +0000649
sewardjb5f6f512005-03-10 23:59:00 +0000650 VG_(atfork)(NULL, NULL, sched_fork_cleanup);
sewardje663cb92002-04-12 10:26:32 +0000651}
652
653
sewardje663cb92002-04-12 10:26:32 +0000654/* ---------------------------------------------------------------------
655 The scheduler proper.
656 ------------------------------------------------------------------ */
657
sewardjb5f6f512005-03-10 23:59:00 +0000658static void handle_tt_miss ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +0000659{
sewardjb5f6f512005-03-10 23:59:00 +0000660 Bool found;
661 Addr ip = INSTR_PTR(VG_(threads)[tid].arch);
662
663 /* Trivial event. Miss in the fast-cache. Do a full
664 lookup for it. */
665 found = VG_(search_transtab)( NULL,
666 ip, True/*upd_fast_cache*/ );
667 if (!found) {
668 /* Not found; we need to request a translation. */
669 if (VG_(translate)( tid, ip, /*debug*/False, 0/*not verbose*/ )) {
670 found = VG_(search_transtab)( NULL, ip, True );
671 if (!found)
672 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
673 } else {
674 // If VG_(translate)() fails, it's because it had to throw a
675 // signal because the client jumped to a bad address. That
676 // means that either a signal has been set up for delivery,
677 // or the thread has been marked for termination. Either
678 // way, we just need to go back into the scheduler loop.
679 }
680 }
681}
682
683static void handle_syscall(ThreadId tid)
684{
685 ThreadState *tst = VG_(get_ThreadState)(tid);
686 Bool jumped;
687
688 /* Syscall may or may not block; either way, it will be
689 complete by the time this call returns, and we'll be
690 runnable again. We could take a signal while the
691 syscall runs. */
692 SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
693
694 if (!VG_(is_running_thread)(tid))
695 VG_(printf)("tid %d not running; running_tid=%d, tid %d status %d\n",
696 tid, running_tid, tid, tst->status);
697 vg_assert(VG_(is_running_thread)(tid));
698
699 if (jumped) {
700 VG_(block_signals)(tid);
701 VG_(poll_signals)(tid);
702 }
703}
704
705/*
706 Run a thread until it wants to exit.
707
708 We assume that the caller has already called VG_(set_running) for
709 us, so we own the VCPU. Also, all signals are blocked.
710 */
711VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
712{
sewardje663cb92002-04-12 10:26:32 +0000713 UInt trc;
sewardjb5f6f512005-03-10 23:59:00 +0000714 ThreadState *tst = VG_(get_ThreadState)(tid);
sewardje663cb92002-04-12 10:26:32 +0000715
sewardjc24be7a2005-03-15 01:40:12 +0000716 if (VG_(clo_trace_sched))
717 print_sched_event(tid, "entering VG_(scheduler)");
718
sewardjb5f6f512005-03-10 23:59:00 +0000719 VGP_PUSHCC(VgpSched);
sewardje663cb92002-04-12 10:26:32 +0000720
sewardjb5f6f512005-03-10 23:59:00 +0000721 /* set the proper running signal mask */
722 VG_(block_signals)(tid);
723
724 vg_assert(VG_(is_running_thread)(tid));
sewardje663cb92002-04-12 10:26:32 +0000725
njn14319cc2005-03-13 06:26:22 +0000726 VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
sewardj6072c362002-04-19 14:40:57 +0000727
sewardjb5f6f512005-03-10 23:59:00 +0000728 while(!VG_(is_exiting)(tid)) {
sewardjb5f6f512005-03-10 23:59:00 +0000729 if (VG_(dispatch_ctr) == 1) {
730 /* Our slice is done, so yield the CPU to another thread. This
731 doesn't sleep between sleeping and running, since that would
732 take too much time. */
733 VG_(set_sleeping)(tid, VgTs_Yielding);
734 /* nothing */
735 VG_(set_running)(tid);
736 //VG_(tm_thread_switchto)(tid);
sewardje663cb92002-04-12 10:26:32 +0000737
sewardjb5f6f512005-03-10 23:59:00 +0000738 /* OK, do some relatively expensive housekeeping stuff */
739 scheduler_sanity(tid);
740 VG_(sanity_check_general)(False);
sewardje663cb92002-04-12 10:26:32 +0000741
sewardjb5f6f512005-03-10 23:59:00 +0000742 /* Look for any pending signals for this thread, and set them up
743 for delivery */
744 VG_(poll_signals)(tid);
sewardje663cb92002-04-12 10:26:32 +0000745
sewardjb5f6f512005-03-10 23:59:00 +0000746 if (VG_(is_exiting)(tid))
747 break; /* poll_signals picked up a fatal signal */
sewardje663cb92002-04-12 10:26:32 +0000748
sewardjb5f6f512005-03-10 23:59:00 +0000749 /* For stats purposes only. */
750 n_scheduling_events_MAJOR++;
sewardje663cb92002-04-12 10:26:32 +0000751
sewardjb5f6f512005-03-10 23:59:00 +0000752 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
753 that it decrements the counter before testing it for zero, so
754 that if tst->dispatch_ctr is set to N you get at most N-1
755 iterations. Also this means that tst->dispatch_ctr must
756 exceed zero before entering the innerloop. Also also, the
757 decrement is done before the bb is actually run, so you
758 always get at least one decrement even if nothing happens. */
njn14319cc2005-03-13 06:26:22 +0000759 VG_(dispatch_ctr) = SCHEDULING_QUANTUM + 1;
jsgf855d93d2003-10-13 22:26:55 +0000760
sewardjb5f6f512005-03-10 23:59:00 +0000761 /* paranoia ... */
762 vg_assert(tst->tid == tid);
763 vg_assert(tst->os_state.lwpid == VG_(gettid)());
sewardje663cb92002-04-12 10:26:32 +0000764 }
765
sewardjb5f6f512005-03-10 23:59:00 +0000766 /* For stats purposes only. */
767 n_scheduling_events_MINOR++;
sewardje663cb92002-04-12 10:26:32 +0000768
769 if (0)
sewardjb5f6f512005-03-10 23:59:00 +0000770 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
771 tid, VG_(dispatch_ctr) - 1 );
sewardje663cb92002-04-12 10:26:32 +0000772
sewardjb5f6f512005-03-10 23:59:00 +0000773 trc = run_thread_for_a_while ( tid );
sewardje663cb92002-04-12 10:26:32 +0000774
sewardjb5f6f512005-03-10 23:59:00 +0000775 if (VG_(clo_trace_sched) && VG_(clo_verbosity) > 2) {
776 Char buf[50];
777 VG_(sprintf)(buf, "TRC: %s", name_of_sched_event(trc));
778 print_sched_event(tid, buf);
sewardje663cb92002-04-12 10:26:32 +0000779 }
780
sewardjb5f6f512005-03-10 23:59:00 +0000781 switch(trc) {
782 case VG_TRC_INNER_FASTMISS:
783 vg_assert(VG_(dispatch_ctr) > 1);
784 handle_tt_miss(tid);
785 break;
786
787 case VEX_TRC_JMP_CLIENTREQ:
788 do_client_request(tid);
789 break;
790
791 case VEX_TRC_JMP_SYSCALL:
792 handle_syscall(tid);
793 if (VG_(clo_sanity_level) > 2)
794 VG_(sanity_check_general)(True); /* sanity-check every syscall */
795 break;
sewardje663cb92002-04-12 10:26:32 +0000796
sewardjb5f6f512005-03-10 23:59:00 +0000797 case VEX_TRC_JMP_YIELD:
798 /* Explicit yield, because this thread is in a spin-lock
sewardj3fc75752005-03-12 15:16:31 +0000799 or something. Only let the thread run for a short while
800 longer. Because swapping to another thread is expensive,
801 we're prepared to let this thread eat a little more CPU
802 before swapping to another. That means that short term
803 spins waiting for hardware to poke memory won't cause a
804 thread swap. */
805 if (VG_(dispatch_ctr) > 100)
806 VG_(dispatch_ctr) = 100;
sewardjb5f6f512005-03-10 23:59:00 +0000807 break;
sewardje663cb92002-04-12 10:26:32 +0000808
sewardjb5f6f512005-03-10 23:59:00 +0000809 case VG_TRC_INNER_COUNTERZERO:
810 /* Timeslice is out. Let a new thread be scheduled. */
811 vg_assert(VG_(dispatch_ctr) == 1);
812 break;
sewardje663cb92002-04-12 10:26:32 +0000813
sewardjb5f6f512005-03-10 23:59:00 +0000814 case VG_TRC_FAULT_SIGNAL:
815 /* Everything should be set up (either we're exiting, or
816 about to start in a signal handler). */
817 break;
sewardj9d1b5d32002-04-17 19:40:49 +0000818
sewardj07bdc5e2005-03-11 13:19:47 +0000819 case VEX_TRC_JMP_MAPFAIL:
820 /* Failure of arch-specific address translation (x86/amd64
821 segment override use) */
822 /* jrs 2005 03 11: is this correct? */
823 VG_(synth_fault)(tid);
824 break;
825
sewardjb5f6f512005-03-10 23:59:00 +0000826 case VEX_TRC_JMP_EMWARN: {
827 static Int counts[EmWarn_NUMBER];
828 static Bool counts_initted = False;
829 VexEmWarn ew;
830 HChar* what;
831 Bool show;
832 Int q;
833 if (!counts_initted) {
834 counts_initted = True;
835 for (q = 0; q < EmWarn_NUMBER; q++)
836 counts[q] = 0;
837 }
838 ew = (VexEmWarn)VG_(threads)[tid].arch.vex.guest_EMWARN;
839 what = (ew < 0 || ew >= EmWarn_NUMBER)
840 ? "unknown (?!)"
841 : LibVEX_EmWarn_string(ew);
842 show = (ew < 0 || ew >= EmWarn_NUMBER)
843 ? True
844 : counts[ew]++ < 3;
sewardjb1131a82005-03-19 15:12:21 +0000845 if (show && VG_(clo_show_emwarns)) {
sewardjb5f6f512005-03-10 23:59:00 +0000846 VG_(message)( Vg_UserMsg,
847 "Emulation warning: unsupported action:");
848 VG_(message)( Vg_UserMsg, " %s", what);
njnd01fef72005-03-25 23:35:48 +0000849 VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
sewardjb5f6f512005-03-10 23:59:00 +0000850 }
851 break;
852 }
sewardje663cb92002-04-12 10:26:32 +0000853
sewardjb5f6f512005-03-10 23:59:00 +0000854 case VEX_TRC_JMP_NODECODE:
855 VG_(synth_sigill)(tid, INSTR_PTR(VG_(threads)[tid].arch));
856 break;
sewardje663cb92002-04-12 10:26:32 +0000857
sewardjb5f6f512005-03-10 23:59:00 +0000858 default:
859 VG_(printf)("\ntrc = %d\n", trc);
860 VG_(core_panic)("VG_(scheduler), phase 3: "
861 "unexpected thread return code");
862 /* NOTREACHED */
863 break;
sewardje663cb92002-04-12 10:26:32 +0000864
865 } /* switch (trc) */
nethercote238a3c32004-08-09 13:13:31 +0000866 }
sewardjc24be7a2005-03-15 01:40:12 +0000867
868 if (VG_(clo_trace_sched))
869 print_sched_event(tid, "exiting VG_(scheduler)");
870
sewardjb5f6f512005-03-10 23:59:00 +0000871 vg_assert(VG_(is_exiting)(tid));
thughes513197c2004-06-13 12:07:53 +0000872
sewardjb5f6f512005-03-10 23:59:00 +0000873 VGP_POPCC(VgpSched);
thughes513197c2004-06-13 12:07:53 +0000874
sewardjb5f6f512005-03-10 23:59:00 +0000875 //if (VG_(clo_model_pthreads))
876 // VG_(tm_thread_exit)(tid);
877
878 return tst->exitreason;
sewardj20917d82002-05-28 01:36:45 +0000879}
880
881
sewardjb5f6f512005-03-10 23:59:00 +0000882/*
883 This causes all threads to forceably exit. They aren't actually
884 dead by the time this returns; you need to call
885 VGA_(reap_threads)() to wait for them.
886 */
887void VG_(nuke_all_threads_except) ( ThreadId me, VgSchedReturnCode src )
sewardjccef2e62002-05-29 19:26:32 +0000888{
889 ThreadId tid;
sewardjb5f6f512005-03-10 23:59:00 +0000890
891 vg_assert(VG_(is_running_thread)(me));
sewardj45f02c42005-02-05 18:27:14 +0000892
sewardjccef2e62002-05-29 19:26:32 +0000893 for (tid = 1; tid < VG_N_THREADS; tid++) {
894 if (tid == me
jsgf855d93d2003-10-13 22:26:55 +0000895 || VG_(threads)[tid].status == VgTs_Empty)
sewardjccef2e62002-05-29 19:26:32 +0000896 continue;
sewardjb5f6f512005-03-10 23:59:00 +0000897 if (0)
sewardjef037c72002-05-30 00:40:03 +0000898 VG_(printf)(
899 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjb5f6f512005-03-10 23:59:00 +0000900
901 VG_(threads)[tid].exitreason = src;
902 VG_(kill_thread)(tid);
sewardjccef2e62002-05-29 19:26:32 +0000903 }
904}
905
906
njnd3040452003-05-19 15:04:06 +0000907/* ---------------------------------------------------------------------
sewardjb5f6f512005-03-10 23:59:00 +0000908 Specifying shadow register values
njnd3040452003-05-19 15:04:06 +0000909 ------------------------------------------------------------------ */
910
sewardjb5f6f512005-03-10 23:59:00 +0000911void VG_(set_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
njncf45fd42004-11-24 16:30:22 +0000912 const UChar* area )
njnd3040452003-05-19 15:04:06 +0000913{
njncf45fd42004-11-24 16:30:22 +0000914 ThreadState* tst;
915
916 vg_assert(VG_(is_valid_tid)(tid));
917 tst = & VG_(threads)[tid];
918
919 // Bounds check
920 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
921 vg_assert(offset + size <= sizeof(VexGuestArchState));
922
923 VG_(memcpy)( (void*)(((Addr)(&tst->arch.vex_shadow)) + offset), area, size);
924}
925
sewardjb5f6f512005-03-10 23:59:00 +0000926void VG_(get_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
njncf45fd42004-11-24 16:30:22 +0000927 UChar* area )
928{
929 ThreadState* tst;
930
931 vg_assert(VG_(is_valid_tid)(tid));
932 tst = & VG_(threads)[tid];
933
934 // Bounds check
935 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
936 vg_assert(offset + size <= sizeof(VexGuestArchState));
937
938 VG_(memcpy)( area, (void*)(((Addr)&(tst->arch.vex_shadow)) + offset), size);
939}
940
941
942void VG_(set_return_from_syscall_shadow) ( ThreadId tid, UWord ret_shadow )
943{
944 VG_(set_shadow_regs_area)(tid, O_SYSCALL_RET, sizeof(UWord),
945 (UChar*)&ret_shadow);
njnd3040452003-05-19 15:04:06 +0000946}
947
sewardj2a99cf62004-11-24 10:44:19 +0000948UInt VG_(get_exit_status_shadow) ( ThreadId tid )
njnd3040452003-05-19 15:04:06 +0000949{
njncf45fd42004-11-24 16:30:22 +0000950 UInt ret;
951 VG_(get_shadow_regs_area)(tid, O_SYSCALL_ARG1, sizeof(UInt),
952 (UChar*)&ret);
953 return ret;
njnd3040452003-05-19 15:04:06 +0000954}
955
sewardj2cb00342002-06-28 01:46:26 +0000956
sewardje663cb92002-04-12 10:26:32 +0000957/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +0000958 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +0000959 ------------------------------------------------------------------ */
960
sewardj124ca2a2002-06-20 10:19:38 +0000961/* Do a client request for the thread tid. After the request, tid may
962 or may not still be runnable; if not, the scheduler will have to
963 choose a new thread to run.
964*/
sewardje663cb92002-04-12 10:26:32 +0000965static
sewardjb5f6f512005-03-10 23:59:00 +0000966void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +0000967{
sewardjb5f6f512005-03-10 23:59:00 +0000968 UWord* arg = (UWord*)(CLREQ_ARGS(VG_(threads)[tid].arch));
nethercoted1b64b22004-11-04 18:22:28 +0000969 UWord req_no = arg[0];
sewardj124ca2a2002-06-20 10:19:38 +0000970
fitzhardinge98abfc72003-12-16 02:05:15 +0000971 if (0)
nethercoted1b64b22004-11-04 18:22:28 +0000972 VG_(printf)("req no = 0x%llx, arg = %p\n", (ULong)req_no, arg);
sewardje663cb92002-04-12 10:26:32 +0000973 switch (req_no) {
974
njn3e884182003-04-15 13:03:23 +0000975 case VG_USERREQ__CLIENT_CALL0: {
njn2ac95242005-03-13 23:07:30 +0000976 UWord (*f)(ThreadId) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000977 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000978 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL0: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +0000979 else
njn2ac95242005-03-13 23:07:30 +0000980 SET_CLCALL_RETVAL(tid, f ( tid ), (Addr)f);
njn3e884182003-04-15 13:03:23 +0000981 break;
982 }
983 case VG_USERREQ__CLIENT_CALL1: {
njn2ac95242005-03-13 23:07:30 +0000984 UWord (*f)(ThreadId, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000985 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000986 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL1: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +0000987 else
njn2ac95242005-03-13 23:07:30 +0000988 SET_CLCALL_RETVAL(tid, f ( tid, arg[2] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +0000989 break;
990 }
991 case VG_USERREQ__CLIENT_CALL2: {
njn2ac95242005-03-13 23:07:30 +0000992 UWord (*f)(ThreadId, UWord, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +0000993 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +0000994 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL2: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +0000995 else
njn2ac95242005-03-13 23:07:30 +0000996 SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +0000997 break;
998 }
999 case VG_USERREQ__CLIENT_CALL3: {
njn2ac95242005-03-13 23:07:30 +00001000 UWord (*f)(ThreadId, UWord, UWord, UWord) = (void*)arg[1];
fitzhardinge98abfc72003-12-16 02:05:15 +00001001 if (f == NULL)
nethercote66b3af62004-09-11 13:06:55 +00001002 VG_(message)(Vg_DebugMsg, "VG_USERREQ__CLIENT_CALL3: func=%p\n", f);
fitzhardinge98abfc72003-12-16 02:05:15 +00001003 else
njn2ac95242005-03-13 23:07:30 +00001004 SET_CLCALL_RETVAL(tid, f ( tid, arg[2], arg[3], arg[4] ), (Addr)f );
njn3e884182003-04-15 13:03:23 +00001005 break;
1006 }
1007
nethercote7cc9c232004-01-21 15:08:04 +00001008 /* Note: for tools that replace malloc() et al, we want to call
njn3e884182003-04-15 13:03:23 +00001009 the replacement versions. For those that don't, we want to call
sewardjb5f6f512005-03-10 23:59:00 +00001010 VG_(cli_malloc)() et al. We do this by calling SK_(malloc)(), which
nethercote3ced0e32004-01-26 14:50:45 +00001011 malloc-replacing tools must replace, but have the default definition
sewardjb5f6f512005-03-10 23:59:00 +00001012 of SK_(malloc)() call VG_(cli_malloc)(). */
njn3e884182003-04-15 13:03:23 +00001013
1014 /* Note: for MALLOC and FREE, must set the appropriate "lock"... see
sewardjb5f6f512005-03-10 23:59:00 +00001015 the comment in vg_defaults.c/SK_(malloc)() for why. */
sewardj124ca2a2002-06-20 10:19:38 +00001016 case VG_USERREQ__MALLOC:
njnd2252832004-11-26 10:53:33 +00001017 VG_(tl_malloc_called_by_scheduler) = True;
njnd3040452003-05-19 15:04:06 +00001018 SET_PTHREQ_RETVAL(
sewardj2a99cf62004-11-24 10:44:19 +00001019 tid, (Addr)TL_(malloc) ( tid, arg[1] )
sewardj124ca2a2002-06-20 10:19:38 +00001020 );
njnd2252832004-11-26 10:53:33 +00001021 VG_(tl_malloc_called_by_scheduler) = False;
sewardj124ca2a2002-06-20 10:19:38 +00001022 break;
1023
1024 case VG_USERREQ__FREE:
njnd2252832004-11-26 10:53:33 +00001025 VG_(tl_malloc_called_by_scheduler) = True;
sewardj2a99cf62004-11-24 10:44:19 +00001026 TL_(free) ( tid, (void*)arg[1] );
njnd2252832004-11-26 10:53:33 +00001027 VG_(tl_malloc_called_by_scheduler) = False;
njnd3040452003-05-19 15:04:06 +00001028 SET_PTHREQ_RETVAL(tid, 0); /* irrelevant */
sewardj124ca2a2002-06-20 10:19:38 +00001029 break;
1030
sewardj124ca2a2002-06-20 10:19:38 +00001031 case VG_USERREQ__RUNNING_ON_VALGRIND:
sewardjb5f6f512005-03-10 23:59:00 +00001032 SET_CLREQ_RETVAL(tid, RUNNING_ON_VALGRIND+1);
sewardj124ca2a2002-06-20 10:19:38 +00001033 break;
1034
1035 case VG_USERREQ__READ_MILLISECOND_TIMER:
njnd3040452003-05-19 15:04:06 +00001036 SET_PTHREQ_RETVAL(tid, VG_(read_millisecond_timer)());
sewardj124ca2a2002-06-20 10:19:38 +00001037 break;
1038
fitzhardinge39de4b42003-10-31 07:12:21 +00001039 case VG_USERREQ__PRINTF: {
1040 int count =
nethercote3e901a22004-09-11 13:17:02 +00001041 VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );
fitzhardinge39de4b42003-10-31 07:12:21 +00001042 SET_CLREQ_RETVAL( tid, count );
1043 break; }
1044
1045 case VG_USERREQ__INTERNAL_PRINTF: {
1046 int count =
njnaa3c26b2005-03-12 05:32:28 +00001047 VG_(vmessage)( Vg_DebugMsg, (char *)arg[1], (void*)arg[2] );
fitzhardinge39de4b42003-10-31 07:12:21 +00001048 SET_CLREQ_RETVAL( tid, count );
1049 break; }
1050
1051 case VG_USERREQ__PRINTF_BACKTRACE: {
fitzhardinge39de4b42003-10-31 07:12:21 +00001052 int count =
nethercote3e901a22004-09-11 13:17:02 +00001053 VG_(vmessage)( Vg_ClientMsg, (char *)arg[1], (void*)arg[2] );
njnd01fef72005-03-25 23:35:48 +00001054 VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
fitzhardinge39de4b42003-10-31 07:12:21 +00001055 SET_CLREQ_RETVAL( tid, count );
1056 break; }
1057
fitzhardinge98abfc72003-12-16 02:05:15 +00001058 case VG_USERREQ__GET_MALLOCFUNCS: {
1059 struct vg_mallocfunc_info *info = (struct vg_mallocfunc_info *)arg[1];
1060
sewardjb5f6f512005-03-10 23:59:00 +00001061 info->tl_malloc = (Addr)TL_(malloc);
1062 info->tl_calloc = (Addr)TL_(calloc);
1063 info->tl_realloc = (Addr)TL_(realloc);
1064 info->tl_memalign = (Addr)TL_(memalign);
1065 info->tl___builtin_new = (Addr)TL_(__builtin_new);
1066 info->tl___builtin_vec_new = (Addr)TL_(__builtin_vec_new);
1067 info->tl_free = (Addr)TL_(free);
1068 info->tl___builtin_delete = (Addr)TL_(__builtin_delete);
1069 info->tl___builtin_vec_delete = (Addr)TL_(__builtin_vec_delete);
fitzhardinge98abfc72003-12-16 02:05:15 +00001070
sewardjb5f6f512005-03-10 23:59:00 +00001071 info->arena_payload_szB = (Addr)VG_(arena_payload_szB);
fitzhardinge98abfc72003-12-16 02:05:15 +00001072
sewardjb5f6f512005-03-10 23:59:00 +00001073 info->clo_sloppy_malloc = VG_(clo_sloppy_malloc);
1074 info->clo_trace_malloc = VG_(clo_trace_malloc);
fitzhardinge98abfc72003-12-16 02:05:15 +00001075
1076 SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
1077
1078 break;
1079 }
1080
njn25e49d8e72002-09-23 09:36:25 +00001081 /* Requests from the client program */
1082
1083 case VG_USERREQ__DISCARD_TRANSLATIONS:
1084 if (VG_(clo_verbosity) > 2)
1085 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
1086 " addr %p, len %d\n",
1087 (void*)arg[1], arg[2] );
1088
sewardjfa8ec112005-01-19 11:55:34 +00001089 VG_(discard_translations)( arg[1], arg[2] );
njn25e49d8e72002-09-23 09:36:25 +00001090
njnd3040452003-05-19 15:04:06 +00001091 SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
njn25e49d8e72002-09-23 09:36:25 +00001092 break;
1093
njn47363ab2003-04-21 13:24:40 +00001094 case VG_USERREQ__COUNT_ERRORS:
nethercotef2b11482004-08-02 12:36:01 +00001095 SET_CLREQ_RETVAL( tid, VG_(get_n_errs_found)() );
njn47363ab2003-04-21 13:24:40 +00001096 break;
1097
sewardjb5f6f512005-03-10 23:59:00 +00001098 /* Obsolete requests: print a warning in case there's an old
1099 libpthread.so still hanging around. */
1100 case VG_USERREQ__APPLY_IN_NEW_THREAD:
1101 case VG_USERREQ__QUIT:
1102 case VG_USERREQ__WAIT_JOINER:
1103 case VG_USERREQ__PTHREAD_JOIN:
1104 case VG_USERREQ__SET_CANCELSTATE:
1105 case VG_USERREQ__SET_CANCELTYPE:
1106 case VG_USERREQ__TESTCANCEL:
1107 case VG_USERREQ__SET_CANCELPEND:
1108 case VG_USERREQ__SET_OR_GET_DETACH:
1109 case VG_USERREQ__PTHREAD_GET_THREADID:
1110 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
1111 case VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK:
1112 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
1113 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
1114 case VG_USERREQ__PTHREAD_COND_WAIT:
1115 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
1116 case VG_USERREQ__PTHREAD_COND_SIGNAL:
1117 case VG_USERREQ__PTHREAD_COND_BROADCAST:
1118 case VG_USERREQ__PTHREAD_KEY_CREATE:
1119 case VG_USERREQ__PTHREAD_KEY_DELETE:
1120 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
1121 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
1122 case VG_USERREQ__PTHREAD_SIGMASK:
1123 case VG_USERREQ__SIGWAIT:
1124 case VG_USERREQ__PTHREAD_KILL:
1125 case VG_USERREQ__PTHREAD_YIELD:
1126 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
1127 case VG_USERREQ__CLEANUP_PUSH:
1128 case VG_USERREQ__CLEANUP_POP:
1129 case VG_USERREQ__GET_KEY_D_AND_S:
1130 case VG_USERREQ__NUKE_OTHER_THREADS:
1131 case VG_USERREQ__GET_N_SIGS_RETURNED:
1132 case VG_USERREQ__SET_FHSTACK_USED:
1133 case VG_USERREQ__GET_FHSTACK_USED:
1134 case VG_USERREQ__SET_FHSTACK_ENTRY:
1135 case VG_USERREQ__GET_FHSTACK_ENTRY:
1136 case VG_USERREQ__GET_SIGRT_MIN:
1137 case VG_USERREQ__GET_SIGRT_MAX:
1138 case VG_USERREQ__ALLOC_RTSIG:
1139 VG_(message)(Vg_UserMsg, "It looks like you've got an old libpthread.so* ");
1140 VG_(message)(Vg_UserMsg, "installed in \"%s\".", VG_(libdir));
1141 VG_(message)(Vg_UserMsg, "Please delete it and try again.");
1142 VG_(exit)(99);
1143 break;
1144
sewardje663cb92002-04-12 10:26:32 +00001145 default:
sewardjb5f6f512005-03-10 23:59:00 +00001146 if (VGA_(client_request)(tid, arg)) {
1147 /* architecture handled the client request */
1148 } else if (VG_(needs).client_requests) {
nethercoted1b64b22004-11-04 18:22:28 +00001149 UWord ret;
sewardj34042512002-10-22 04:14:35 +00001150
njn25e49d8e72002-09-23 09:36:25 +00001151 if (VG_(clo_verbosity) > 2)
fitzhardinge98abfc72003-12-16 02:05:15 +00001152 VG_(printf)("client request: code %x, addr %p, len %d\n",
njn25e49d8e72002-09-23 09:36:25 +00001153 arg[0], (void*)arg[1], arg[2] );
1154
njn26f02512004-11-22 18:33:15 +00001155 if (TL_(handle_client_request) ( tid, arg, &ret ))
sewardjb5f6f512005-03-10 23:59:00 +00001156 SET_CLREQ_RETVAL(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00001157 } else {
sewardj34042512002-10-22 04:14:35 +00001158 static Bool whined = False;
1159
sewardjb5f6f512005-03-10 23:59:00 +00001160 if (!whined && VG_(clo_verbosity) > 2) {
nethercote7cc9c232004-01-21 15:08:04 +00001161 // Allow for requests in core, but defined by tools, which
njnd7994182003-10-02 13:44:04 +00001162 // have 0 and 0 in their two high bytes.
1163 Char c1 = (arg[0] >> 24) & 0xff;
1164 Char c2 = (arg[0] >> 16) & 0xff;
1165 if (c1 == 0) c1 = '_';
1166 if (c2 == 0) c2 = '_';
sewardj34042512002-10-22 04:14:35 +00001167 VG_(message)(Vg_UserMsg, "Warning:\n"
njnd7994182003-10-02 13:44:04 +00001168 " unhandled client request: 0x%x (%c%c+0x%x). Perhaps\n"
1169 " VG_(needs).client_requests should be set?\n",
1170 arg[0], c1, c2, arg[0] & 0xffff);
sewardj34042512002-10-22 04:14:35 +00001171 whined = True;
1172 }
njn25e49d8e72002-09-23 09:36:25 +00001173 }
sewardje663cb92002-04-12 10:26:32 +00001174 break;
1175 }
1176}
1177
1178
sewardj6072c362002-04-19 14:40:57 +00001179/* ---------------------------------------------------------------------
1180 Sanity checking.
1181 ------------------------------------------------------------------ */
1182
sewardjb5f6f512005-03-10 23:59:00 +00001183/* Internal consistency checks on the sched structures. */
sewardj6072c362002-04-19 14:40:57 +00001184static
sewardjb5f6f512005-03-10 23:59:00 +00001185void scheduler_sanity ( ThreadId tid )
sewardj6072c362002-04-19 14:40:57 +00001186{
sewardjb5f6f512005-03-10 23:59:00 +00001187 Bool bad = False;
jsgf855d93d2003-10-13 22:26:55 +00001188
sewardjb5f6f512005-03-10 23:59:00 +00001189 if (!VG_(is_running_thread)(tid)) {
1190 VG_(message)(Vg_DebugMsg,
1191 "Thread %d is supposed to be running, but doesn't own run_sema (owned by %d)\n",
1192 tid, running_tid);
1193 bad = True;
jsgf855d93d2003-10-13 22:26:55 +00001194 }
sewardj5f07b662002-04-23 16:52:51 +00001195
sewardjb5f6f512005-03-10 23:59:00 +00001196 if (VG_(gettid)() != VG_(threads)[tid].os_state.lwpid) {
1197 VG_(message)(Vg_DebugMsg,
njnd06ed472005-03-13 05:12:31 +00001198 "Thread %d supposed to be in LWP %d, but we're actually %d\n",
1199 tid, VG_(threads)[tid].os_state.lwpid, VG_(gettid)());
sewardjb5f6f512005-03-10 23:59:00 +00001200 bad = True;
sewardj5f07b662002-04-23 16:52:51 +00001201 }
sewardj6072c362002-04-19 14:40:57 +00001202}
1203
1204
sewardje663cb92002-04-12 10:26:32 +00001205/*--------------------------------------------------------------------*/
1206/*--- end vg_scheduler.c ---*/
1207/*--------------------------------------------------------------------*/