blob: e6b8eeaf414e5abe6f9ffcfeeb99f9727c20eee7 [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/*--------------------------------------------------------------------*/
3/*--- A user-space pthreads implementation. vg_scheduler.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2000-2002 Julian Seward
11 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
31#include "vg_include.h"
njn25e49d8e72002-09-23 09:36:25 +000032#include "valgrind.h" /* for VG_USERREQ__RUNNING_ON_VALGRIND and
33 VG_USERREQ__DISCARD_TRANSLATIONS */
sewardje663cb92002-04-12 10:26:32 +000034
sewardjb60c1ad2002-05-29 20:23:26 +000035/* BORKAGE/ISSUES as of 29 May 02
sewardje663cb92002-04-12 10:26:32 +000036
sewardj77e466c2002-04-14 02:29:29 +000037- Currently, when a signal is run, just the ThreadStatus.status fields
38 are saved in the signal frame, along with the CPU state. Question:
39 should I also save and restore:
40 ThreadStatus.joiner
41 ThreadStatus.waited_on_mid
42 ThreadStatus.awaken_at
43 ThreadStatus.retval
44 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000045
sewardj77e466c2002-04-14 02:29:29 +000046- Signals interrupting read/write and nanosleep: SA_RESTART settings.
47 Read/write correctly return with EINTR when SA_RESTART isn't
48 specified and they are interrupted by a signal. nanosleep just
49 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000050
sewardj705d3cb2002-05-23 13:13:12 +000051- So, what's the deal with signals and mutexes? If a thread is
sewardj6072c362002-04-19 14:40:57 +000052 blocked on a mutex, or for a condition variable for that matter, can
53 signals still be delivered to it? This has serious consequences --
54 deadlocks, etc.
55
sewardj705d3cb2002-05-23 13:13:12 +000056- Signals still not really right. Each thread should have its
57 own pending-set, but there is just one process-wide pending set.
58
sewardjb60c1ad2002-05-29 20:23:26 +000059 TODO for valgrind-1.0:
60
sewardj055fbb82002-05-30 00:40:55 +000061- Update assertion checking in scheduler_sanity().
62
sewardjb60c1ad2002-05-29 20:23:26 +000063 TODO sometime:
64
sewardj645030e2002-06-06 01:27:39 +000065- poll() in the vg_libpthread.c -- should it handle the nanosleep
66 being interrupted by a signal? Ditto accept?
67
sewardjb60c1ad2002-05-29 20:23:26 +000068- Mutex scrubbing - clearup_after_thread_exit: look for threads
69 blocked on mutexes held by the exiting thread, and release them
70 appropriately. (??)
71
72- pthread_atfork
73
sewardje462e202002-04-13 04:09:07 +000074*/
sewardje663cb92002-04-12 10:26:32 +000075
76
77/* ---------------------------------------------------------------------
78 Types and globals for the scheduler.
79 ------------------------------------------------------------------ */
80
81/* type ThreadId is defined in vg_include.h. */
82
83/* struct ThreadState is defined in vg_include.h. */
84
sewardj018f7622002-05-15 21:13:39 +000085/* Globals. A statically allocated array of threads. NOTE: [0] is
86 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000087 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000088ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000089
sewardj2cb00342002-06-28 01:46:26 +000090/* The process' fork-handler stack. */
91static Int vg_fhstack_used = 0;
92static ForkHandlerEntry vg_fhstack[VG_N_FORKHANDLERSTACK];
93
94
sewardj1e8cdc92002-04-18 11:37:52 +000095/* The tid of the thread currently in VG_(baseBlock). */
96static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
97
sewardje663cb92002-04-12 10:26:32 +000098
99/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
100jmp_buf VG_(scheduler_jmpbuf);
sewardj872051c2002-07-13 12:12:56 +0000101/* This says whether scheduler_jmpbuf is actually valid. Needed so
102 that our signal handler doesn't longjmp when the buffer isn't
103 actually valid. */
104Bool VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000105/* ... and if so, here's the signal which caused it to do so. */
106Int VG_(longjmpd_on_signal);
107
108
109/* Machinery to keep track of which threads are waiting on which
110 fds. */
111typedef
112 struct {
113 /* The thread which made the request. */
114 ThreadId tid;
115
116 /* The next two fields describe the request. */
117 /* File descriptor waited for. -1 means this slot is not in use */
118 Int fd;
119 /* The syscall number the fd is used in. */
120 Int syscall_no;
121
122 /* False => still waiting for select to tell us the fd is ready
123 to go. True => the fd is ready, but the results have not yet
124 been delivered back to the calling thread. Once the latter
125 happens, this entire record is marked as no longer in use, by
126 making the fd field be -1. */
127 Bool ready;
njn25e49d8e72002-09-23 09:36:25 +0000128
129 /* The result from SK_(pre_blocking_syscall)(); is passed to
130 * SK_(post_blocking_syscall)(). */
131 void* pre_result;
sewardje663cb92002-04-12 10:26:32 +0000132 }
133 VgWaitedOnFd;
134
135static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
136
137
sewardj5f07b662002-04-23 16:52:51 +0000138/* Keeping track of keys. */
139typedef
140 struct {
141 /* Has this key been allocated ? */
142 Bool inuse;
143 /* If .inuse==True, records the address of the associated
144 destructor, or NULL if none. */
145 void (*destructor)(void*);
146 }
147 ThreadKeyState;
148
149/* And our array of thread keys. */
150static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
151
152typedef UInt ThreadKey;
153
154
njn25e49d8e72002-09-23 09:36:25 +0000155UInt VG_(written_shadow_reg);
156
sewardje663cb92002-04-12 10:26:32 +0000157/* Forwards */
sewardj124ca2a2002-06-20 10:19:38 +0000158static void do_client_request ( ThreadId tid );
sewardj6072c362002-04-19 14:40:57 +0000159static void scheduler_sanity ( void );
sewardj124ca2a2002-06-20 10:19:38 +0000160static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
sewardjd140e442002-05-29 01:21:19 +0000161
sewardje663cb92002-04-12 10:26:32 +0000162/* ---------------------------------------------------------------------
163 Helper functions for the scheduler.
164 ------------------------------------------------------------------ */
165
sewardjb48e5002002-05-13 00:16:03 +0000166__inline__
167Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000168{
169 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000170 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000171 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000172 if (VG_(threads)[tid].status == VgTs_Empty) return False;
173 return True;
174}
175
176
177__inline__
178Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
179{
180 /* tid is unsigned, hence no < 0 test. */
181 if (tid == 0) return False;
182 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000183 return True;
184}
185
186
sewardj1e8cdc92002-04-18 11:37:52 +0000187/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000188 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
189 if none do. A small complication is dealing with any currently
190 VG_(baseBlock)-resident thread.
sewardj1e8cdc92002-04-18 11:37:52 +0000191*/
njn25e49d8e72002-09-23 09:36:25 +0000192ThreadId VG_(any_matching_thread_stack)
193 ( Bool (*p) ( Addr stack_min, Addr stack_max ))
sewardj1e8cdc92002-04-18 11:37:52 +0000194{
195 ThreadId tid, tid_to_skip;
196
197 tid_to_skip = VG_INVALID_THREADID;
198
199 /* First check to see if there's a currently-loaded thread in
200 VG_(baseBlock). */
201 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
202 tid = vg_tid_currently_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000203 if ( p ( VG_(baseBlock)[VGOFF_(m_esp)],
204 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000205 return tid;
206 else
207 tid_to_skip = tid;
208 }
209
sewardj6072c362002-04-19 14:40:57 +0000210 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000211 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardj1e8cdc92002-04-18 11:37:52 +0000212 if (tid == tid_to_skip) continue;
njn25e49d8e72002-09-23 09:36:25 +0000213 if ( p ( VG_(threads)[tid].m_esp,
214 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000215 return tid;
216 }
217 return VG_INVALID_THREADID;
218}
219
220
sewardj15a43e12002-04-17 19:35:12 +0000221/* Print the scheduler status. */
222void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000223{
224 Int i;
225 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000226 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000227 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000228 VG_(printf)("\nThread %d: status = ", i);
sewardj018f7622002-05-15 21:13:39 +0000229 switch (VG_(threads)[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000230 case VgTs_Runnable: VG_(printf)("Runnable"); break;
231 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
sewardj20917d82002-05-28 01:36:45 +0000232 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee(%d)",
233 VG_(threads)[i].joiner_jee_tid);
234 break;
235 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner"); break;
sewardj6072c362002-04-19 14:40:57 +0000236 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
237 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000238 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000239 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000240 default: VG_(printf)("???"); break;
241 }
sewardj3b5d8862002-04-20 13:53:23 +0000242 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000243 VG_(threads)[i].associated_mx,
244 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000245 VG_(pp_ExeContext)(
njn25e49d8e72002-09-23 09:36:25 +0000246 VG_(get_ExeContext2)( VG_(threads)[i].m_eip, VG_(threads)[i].m_ebp,
247 VG_(threads)[i].m_esp,
248 VG_(threads)[i].stack_highest_word)
249 );
sewardje663cb92002-04-12 10:26:32 +0000250 }
251 VG_(printf)("\n");
252}
253
254static
njn25e49d8e72002-09-23 09:36:25 +0000255void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no, void* pre_res )
sewardje663cb92002-04-12 10:26:32 +0000256{
257 Int i;
258
259 vg_assert(fd != -1); /* avoid total chaos */
260
261 for (i = 0; i < VG_N_WAITING_FDS; i++)
262 if (vg_waiting_fds[i].fd == -1)
263 break;
264
265 if (i == VG_N_WAITING_FDS)
266 VG_(panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
267 /*
268 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
269 tid, fd, i);
270 */
271 vg_waiting_fds[i].fd = fd;
272 vg_waiting_fds[i].tid = tid;
273 vg_waiting_fds[i].ready = False;
274 vg_waiting_fds[i].syscall_no = syscall_no;
njn25e49d8e72002-09-23 09:36:25 +0000275 vg_waiting_fds[i].pre_result = pre_res;
sewardje663cb92002-04-12 10:26:32 +0000276}
277
278
279
280static
281void print_sched_event ( ThreadId tid, Char* what )
282{
sewardj45b4b372002-04-16 22:50:32 +0000283 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000284}
285
286
287static
288void print_pthread_event ( ThreadId tid, Char* what )
289{
290 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000291}
292
293
294static
295Char* name_of_sched_event ( UInt event )
296{
297 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000298 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
299 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
300 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
301 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
302 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
303 default: return "??UNKNOWN??";
304 }
305}
306
307
308/* Create a translation of the client basic block beginning at
309 orig_addr, and add it to the translation cache & translation table.
310 This probably doesn't really belong here, but, hey ...
311*/
sewardj1e8cdc92002-04-18 11:37:52 +0000312static
313void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000314{
315 Addr trans_addr;
316 TTEntry tte;
317 Int orig_size, trans_size;
318 /* Ensure there is space to hold a translation. */
319 VG_(maybe_do_lru_pass)();
sewardj018f7622002-05-15 21:13:39 +0000320 VG_(translate)( &VG_(threads)[tid],
sewardj1e8cdc92002-04-18 11:37:52 +0000321 orig_addr, &orig_size, &trans_addr, &trans_size );
sewardje663cb92002-04-12 10:26:32 +0000322 /* Copy data at trans_addr into the translation cache.
323 Returned pointer is to the code, not to the 4-byte
324 header. */
325 /* Since the .orig_size and .trans_size fields are
326 UShort, be paranoid. */
327 vg_assert(orig_size > 0 && orig_size < 65536);
328 vg_assert(trans_size > 0 && trans_size < 65536);
329 tte.orig_size = orig_size;
330 tte.orig_addr = orig_addr;
331 tte.trans_size = trans_size;
332 tte.trans_addr = VG_(copy_to_transcache)
333 ( trans_addr, trans_size );
334 tte.mru_epoch = VG_(current_epoch);
335 /* Free the intermediary -- was allocated by VG_(emit_code). */
njn25e49d8e72002-09-23 09:36:25 +0000336 VG_(arena_free)( VG_AR_JITTER, (void*)trans_addr );
sewardje663cb92002-04-12 10:26:32 +0000337 /* Add to trans tab and set back pointer. */
338 VG_(add_to_trans_tab) ( &tte );
339 /* Update stats. */
340 VG_(this_epoch_in_count) ++;
341 VG_(this_epoch_in_osize) += orig_size;
342 VG_(this_epoch_in_tsize) += trans_size;
343 VG_(overall_in_count) ++;
344 VG_(overall_in_osize) += orig_size;
345 VG_(overall_in_tsize) += trans_size;
sewardje663cb92002-04-12 10:26:32 +0000346}
347
348
349/* Allocate a completely empty ThreadState record. */
350static
351ThreadId vg_alloc_ThreadState ( void )
352{
353 Int i;
sewardj6072c362002-04-19 14:40:57 +0000354 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000355 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000356 return i;
357 }
358 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
359 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
360 VG_(panic)("VG_N_THREADS is too low");
361 /*NOTREACHED*/
362}
363
njn25e49d8e72002-09-23 09:36:25 +0000364ThreadState* VG_(get_ThreadState)( ThreadId tid )
365{
366 vg_assert(tid >= 0 && tid < VG_N_THREADS);
367 return & VG_(threads)[tid];
368}
sewardje663cb92002-04-12 10:26:32 +0000369
sewardj1e8cdc92002-04-18 11:37:52 +0000370ThreadState* VG_(get_current_thread_state) ( void )
371{
sewardj018f7622002-05-15 21:13:39 +0000372 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
373 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000374}
375
376
377ThreadId VG_(get_current_tid) ( void )
378{
sewardj018f7622002-05-15 21:13:39 +0000379 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
sewardj1e8cdc92002-04-18 11:37:52 +0000380 return vg_tid_currently_in_baseBlock;
381}
382
njn25e49d8e72002-09-23 09:36:25 +0000383ThreadId VG_(get_current_tid_1_if_root) ( void )
384{
385 if (0 == vg_tid_currently_in_baseBlock)
386 return 1; /* root thread */
387
388 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
389 return vg_tid_currently_in_baseBlock;
390}
391
sewardj1e8cdc92002-04-18 11:37:52 +0000392
sewardje663cb92002-04-12 10:26:32 +0000393/* Copy the saved state of a thread into VG_(baseBlock), ready for it
394 to be run. */
395__inline__
396void VG_(load_thread_state) ( ThreadId tid )
397{
398 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000399 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
400
sewardj92a59562002-09-30 00:53:10 +0000401 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
402 VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs;
403 VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss;
404 VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds;
405 VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es;
406 VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs;
407 VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs;
408
sewardj018f7622002-05-15 21:13:39 +0000409 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
410 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
411 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
412 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
413 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
414 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
415 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
416 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
417 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags;
418 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000419
420 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000421 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000422
njn25e49d8e72002-09-23 09:36:25 +0000423 if (VG_(needs).shadow_regs) {
424 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
425 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
426 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
427 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
428 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
429 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
430 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
431 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
432 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
433 } else {
434 /* Fields shouldn't be used -- check their values haven't changed. */
435 /* Nb: they are written to by some macros like SET_EDX, but they
436 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
437 vg_assert(
438 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
439 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
440 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
441 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
442 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
443 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
444 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
445 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
446 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
447 }
sewardj1e8cdc92002-04-18 11:37:52 +0000448
449 vg_tid_currently_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000450}
451
452
453/* Copy the state of a thread from VG_(baseBlock), presumably after it
454 has been descheduled. For sanity-check purposes, fill the vacated
455 VG_(baseBlock) with garbage so as to make the system more likely to
456 fail quickly if we erroneously continue to poke around inside
457 VG_(baseBlock) without first doing a load_thread_state().
458*/
459__inline__
460void VG_(save_thread_state) ( ThreadId tid )
461{
462 Int i;
463 const UInt junk = 0xDEADBEEF;
464
sewardj1e8cdc92002-04-18 11:37:52 +0000465 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
466
sewardj92a59562002-09-30 00:53:10 +0000467
468 /* We don't copy out the LDT entry, because it can never be changed
469 by the normal actions of the thread, only by the modify_ldt
470 syscall, in which case we will correctly be updating
471 VG_(threads)[tid].ldt. */
472 vg_assert((void*)VG_(threads)[tid].ldt
473 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
474
475 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
476 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
477 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
478 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
479 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
480 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
481
sewardj018f7622002-05-15 21:13:39 +0000482 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
483 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
484 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
485 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
486 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
487 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
488 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
489 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
490 VG_(threads)[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
491 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000492
493 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000494 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000495
njn25e49d8e72002-09-23 09:36:25 +0000496 if (VG_(needs).shadow_regs) {
497 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
498 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
499 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
500 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
501 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
502 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
503 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
504 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
505 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
506 } else {
507 /* Fill with recognisable junk */
508 VG_(threads)[tid].sh_eax =
509 VG_(threads)[tid].sh_ebx =
510 VG_(threads)[tid].sh_ecx =
511 VG_(threads)[tid].sh_edx =
512 VG_(threads)[tid].sh_esi =
513 VG_(threads)[tid].sh_edi =
514 VG_(threads)[tid].sh_ebp =
515 VG_(threads)[tid].sh_esp =
516 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
517 }
sewardje663cb92002-04-12 10:26:32 +0000518
519 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000520 VG_(baseBlock)[VGOFF_(ldt)] = junk;
521 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
522 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
523 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
524 VG_(baseBlock)[VGOFF_(m_es)] = junk;
525 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
526 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
527
sewardje663cb92002-04-12 10:26:32 +0000528 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
529 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
530 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
531 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
532 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
533 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
534 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
535 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
536 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
537 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
538
539 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
540 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000541
542 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000543}
544
545
546/* Run the thread tid for a while, and return a VG_TRC_* value to the
547 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000548static
sewardje663cb92002-04-12 10:26:32 +0000549UInt run_thread_for_a_while ( ThreadId tid )
550{
sewardj7ccc5c22002-04-24 21:39:11 +0000551 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000552 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000553 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000554 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000555 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000556
sewardj671ff542002-05-07 09:25:30 +0000557 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000558 VG_(load_thread_state) ( tid );
559 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
560 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000561 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000562 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000563 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000564 /* We get here if the client didn't take a fault. */
565 } else {
566 /* We get here if the client took a fault, which caused our
567 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000568 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000569 vg_assert(trc == 0);
570 trc = VG_TRC_UNRESUMABLE_SIGNAL;
571 }
sewardj872051c2002-07-13 12:12:56 +0000572
573 vg_assert(!VG_(scheduler_jmpbuf_valid));
574
sewardje663cb92002-04-12 10:26:32 +0000575 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000576 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000577 return trc;
578}
579
580
581/* Increment the LRU epoch counter. */
582static
583void increment_epoch ( void )
584{
585 VG_(current_epoch)++;
586 if (VG_(clo_verbosity) > 2) {
587 UInt tt_used, tc_used;
588 VG_(get_tt_tc_used) ( &tt_used, &tc_used );
589 VG_(message)(Vg_UserMsg,
590 "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
591 VG_(bbs_done),
592 VG_(this_epoch_in_count),
593 VG_(this_epoch_in_osize),
594 VG_(this_epoch_in_tsize),
595 VG_(this_epoch_out_count),
596 VG_(this_epoch_out_osize),
597 VG_(this_epoch_out_tsize),
598 tt_used, tc_used
599 );
600 }
601 VG_(this_epoch_in_count) = 0;
602 VG_(this_epoch_in_osize) = 0;
603 VG_(this_epoch_in_tsize) = 0;
604 VG_(this_epoch_out_count) = 0;
605 VG_(this_epoch_out_osize) = 0;
606 VG_(this_epoch_out_tsize) = 0;
607}
608
609
sewardj20917d82002-05-28 01:36:45 +0000610static
611void mostly_clear_thread_record ( ThreadId tid )
612{
613 Int j;
614 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000615 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000616 VG_(threads)[tid].tid = tid;
617 VG_(threads)[tid].status = VgTs_Empty;
618 VG_(threads)[tid].associated_mx = NULL;
619 VG_(threads)[tid].associated_cv = NULL;
620 VG_(threads)[tid].awaken_at = 0;
621 VG_(threads)[tid].joinee_retval = NULL;
622 VG_(threads)[tid].joiner_thread_return = NULL;
623 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000624 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000625 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
626 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
627 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000628 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000629 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000630 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
631 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
632 for (j = 0; j < VG_N_THREAD_KEYS; j++)
633 VG_(threads)[tid].specifics[j] = NULL;
634}
635
636
sewardje663cb92002-04-12 10:26:32 +0000637/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000638 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000639 caller takes care to park the client's state is parked in
640 VG_(baseBlock).
641*/
642void VG_(scheduler_init) ( void )
643{
644 Int i;
645 Addr startup_esp;
646 ThreadId tid_main;
647
648 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000649
650 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
daywalkera2562202002-07-15 19:39:51 +0000651 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)
njn25e49d8e72002-09-23 09:36:25 +0000652 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_3)
653 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_4)) {
sewardja1679dd2002-05-10 22:31:40 +0000654 /* Jolly good! */
655 } else {
njn25e49d8e72002-09-23 09:36:25 +0000656 VG_(printf)(
657 "%%esp at startup = %p is not near %p, %p, %p or %p; aborting\n",
658 (void*)startup_esp,
659 (void*)VG_STARTUP_STACK_BASE_1,
660 (void*)VG_STARTUP_STACK_BASE_2,
661 (void*)VG_STARTUP_STACK_BASE_3,
662 (void*)VG_STARTUP_STACK_BASE_4
663 );
sewardje663cb92002-04-12 10:26:32 +0000664 VG_(panic)("unexpected %esp at startup");
665 }
666
sewardj6072c362002-04-19 14:40:57 +0000667 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000668 mostly_clear_thread_record(i);
669 VG_(threads)[i].stack_size = 0;
670 VG_(threads)[i].stack_base = (Addr)NULL;
671 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000672 }
673
674 for (i = 0; i < VG_N_WAITING_FDS; i++)
675 vg_waiting_fds[i].fd = -1; /* not in use */
676
sewardj5f07b662002-04-23 16:52:51 +0000677 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
678 vg_thread_keys[i].inuse = False;
679 vg_thread_keys[i].destructor = NULL;
680 }
681
sewardj2cb00342002-06-28 01:46:26 +0000682 vg_fhstack_used = 0;
683
sewardje663cb92002-04-12 10:26:32 +0000684 /* Assert this is thread zero, which has certain magic
685 properties. */
686 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000687 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000688 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000689
690 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000691 vg_tid_currently_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000692 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000693
sewardj018f7622002-05-15 21:13:39 +0000694 VG_(threads)[tid_main].stack_highest_word
695 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000696
sewardj1e8cdc92002-04-18 11:37:52 +0000697 /* So now ... */
698 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000699
700 /* Not running client code right now. */
701 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000702}
703
704
705/* What if fd isn't a valid fd? */
706static
707void set_fd_nonblocking ( Int fd )
708{
709 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
710 vg_assert(!VG_(is_kerror)(res));
711 res |= VKI_O_NONBLOCK;
712 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
713 vg_assert(!VG_(is_kerror)(res));
714}
715
716static
717void set_fd_blocking ( Int fd )
718{
719 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
720 vg_assert(!VG_(is_kerror)(res));
721 res &= ~VKI_O_NONBLOCK;
722 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
723 vg_assert(!VG_(is_kerror)(res));
724}
725
726static
727Bool fd_is_blockful ( Int fd )
728{
729 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
730 vg_assert(!VG_(is_kerror)(res));
731 return (res & VKI_O_NONBLOCK) ? False : True;
732}
733
sewardj3947e622002-05-23 16:52:11 +0000734static
735Bool fd_is_valid ( Int fd )
736{
737 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
738 return VG_(is_kerror)(res) ? False : True;
739}
740
sewardje663cb92002-04-12 10:26:32 +0000741
742
sewardj6072c362002-04-19 14:40:57 +0000743/* vthread tid is returning from a signal handler; modify its
744 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000745
746/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
747 for read or write, has been interrupted by a signal. Find and
748 clear the relevant vg_waiting_fd[] entry. Most of the code in this
749 procedure is total paranoia, if you look closely. */
750static
751void cleanup_waiting_fd_table ( ThreadId tid )
752{
753 Int i, waiters;
754
sewardjb48e5002002-05-13 00:16:03 +0000755 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000756 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
757 vg_assert(VG_(threads)[tid].m_eax == __NR_read
758 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000759
760 /* Excessively paranoidly ... find the fd this op was waiting
761 for, and mark it as not being waited on. */
762 waiters = 0;
763 for (i = 0; i < VG_N_WAITING_FDS; i++) {
764 if (vg_waiting_fds[i].tid == tid) {
765 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000766 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000767 }
768 }
769 vg_assert(waiters == 1);
770 for (i = 0; i < VG_N_WAITING_FDS; i++)
771 if (vg_waiting_fds[i].tid == tid)
772 break;
773 vg_assert(i < VG_N_WAITING_FDS);
774 vg_assert(vg_waiting_fds[i].fd != -1);
775 vg_waiting_fds[i].fd = -1; /* not in use */
776}
777
778
sewardj6072c362002-04-19 14:40:57 +0000779static
780void handle_signal_return ( ThreadId tid )
781{
782 Char msg_buf[100];
783 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000784 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000785
sewardjb48e5002002-05-13 00:16:03 +0000786 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000787
sewardj9a2224b2002-06-19 10:17:40 +0000788 /* Increment signal-returned counter. Used only to implement
789 pause(). */
790 VG_(threads)[tid].n_signals_returned++;
791
sewardj6072c362002-04-19 14:40:57 +0000792 restart_blocked_syscalls = VG_(signal_returns)(tid);
793
794 if (restart_blocked_syscalls)
795 /* Easy; we don't have to do anything. */
796 return;
797
sewardj018f7622002-05-15 21:13:39 +0000798 if (VG_(threads)[tid].status == VgTs_WaitFD
799 && (VG_(threads)[tid].m_eax == __NR_read
800 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000801 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000802 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000803 VG_(threads)[tid].m_eax = -VKI_EINTR;
804 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000805
sewardj6072c362002-04-19 14:40:57 +0000806 if (VG_(clo_trace_sched)) {
807 VG_(sprintf)(msg_buf,
808 "read() / write() interrupted by signal; return EINTR" );
809 print_sched_event(tid, msg_buf);
810 }
811 return;
812 }
813
sewardj645030e2002-06-06 01:27:39 +0000814 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000815 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000816 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000817 write the unused time to nanosleep's second param, but that's
818 too much effort ... we just say that 1 nanosecond was not
819 used, and return EINTR. */
820 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
821 if (rem != NULL) {
822 rem->tv_sec = 0;
823 rem->tv_nsec = 1;
824 }
825 SET_EAX(tid, -VKI_EINTR);
826 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000827 return;
828 }
829
sewardj018f7622002-05-15 21:13:39 +0000830 if (VG_(threads)[tid].status == VgTs_WaitFD) {
sewardj1ffa8da2002-04-26 22:47:57 +0000831 VG_(panic)("handle_signal_return: unknown interrupted syscall");
832 }
833
sewardj6072c362002-04-19 14:40:57 +0000834 /* All other cases? Just return. */
835}
836
837
sewardje663cb92002-04-12 10:26:32 +0000838static
839void sched_do_syscall ( ThreadId tid )
840{
njn25e49d8e72002-09-23 09:36:25 +0000841 UInt saved_eax;
842 UInt res, syscall_no;
843 UInt fd;
844 void* pre_res;
845 Bool orig_fd_blockness;
846 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000847
sewardjb48e5002002-05-13 00:16:03 +0000848 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000849 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000850
sewardj018f7622002-05-15 21:13:39 +0000851 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000852
853 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000854 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000855 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000856 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000857 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000858 t_awaken
859 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000860 + (UInt)1000ULL * (UInt)(req->tv_sec)
861 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000862 VG_(threads)[tid].status = VgTs_Sleeping;
863 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000864 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000865 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000866 t_now, t_awaken-t_now);
867 print_sched_event(tid, msg_buf);
868 }
869 /* Force the scheduler to run something else for a while. */
870 return;
871 }
872
sewardjaec22c02002-04-29 01:58:08 +0000873 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000874 /* We think it's non-blocking. Just do it in the normal way. */
875 VG_(perform_assumed_nonblocking_syscall)(tid);
876 /* The thread is still runnable. */
877 return;
878 }
879
sewardje663cb92002-04-12 10:26:32 +0000880 /* Set the fd to nonblocking, and do the syscall, which will return
881 immediately, in order to lodge a request with the Linux kernel.
882 We later poll for I/O completion using select(). */
883
sewardj018f7622002-05-15 21:13:39 +0000884 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000885
886 /* Deal with error case immediately. */
887 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000888 if (VG_(needs).core_errors)
889 VG_(message)(Vg_UserMsg,
890 "Warning: invalid file descriptor %d in syscall %s",
891 fd, syscall_no == __NR_read ? "read()" : "write()" );
892 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000893 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000894 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000895 /* We're still runnable. */
896 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
897 return;
898 }
899
900 /* From here onwards we know that fd is valid. */
901
sewardje663cb92002-04-12 10:26:32 +0000902 orig_fd_blockness = fd_is_blockful(fd);
903 set_fd_nonblocking(fd);
904 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000905 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000906
907 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000908 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000909 KERNEL_DO_SYSCALL(tid,res);
910
911 /* Restore original blockfulness of the fd. */
912 if (orig_fd_blockness)
913 set_fd_blocking(fd);
914 else
915 set_fd_nonblocking(fd);
916
sewardjaec22c02002-04-29 01:58:08 +0000917 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
918 /* Finish off in the normal way. Don't restore %EAX, since that
919 now (correctly) holds the result of the call. We get here if either:
920 1. The call didn't block, or
921 2. The fd was already in nonblocking mode before we started to
922 mess with it. In this case, we're not expecting to handle
923 the I/O completion -- the client is. So don't file a
924 completion-wait entry.
925 */
njn25e49d8e72002-09-23 09:36:25 +0000926 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000927 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000928 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000929
930 } else {
931
sewardjaec22c02002-04-29 01:58:08 +0000932 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
933
sewardje663cb92002-04-12 10:26:32 +0000934 /* It would have blocked. First, restore %EAX to what it was
935 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000936 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000937 /* Put this fd in a table of fds on which we are waiting for
938 completion. The arguments for select() later are constructed
939 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000940 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
941 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000942 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000943 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000944 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000945 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
946 print_sched_event(tid, msg_buf);
947 }
948
949 }
950}
951
952
953/* Find out which of the fds in vg_waiting_fds are now ready to go, by
954 making enquiries with select(), and mark them as ready. We have to
955 wait for the requesting threads to fall into the the WaitFD state
956 before we can actually finally deliver the results, so this
957 procedure doesn't do that; complete_blocked_syscalls() does it.
958
959 It might seem odd that a thread which has done a blocking syscall
960 is not in WaitFD state; the way this can happen is if it initially
961 becomes WaitFD, but then a signal is delivered to it, so it becomes
962 Runnable for a while. In this case we have to wait for the
963 sighandler to return, whereupon the WaitFD state is resumed, and
964 only at that point can the I/O result be delivered to it. However,
965 this point may be long after the fd is actually ready.
966
967 So, poll_for_ready_fds() merely detects fds which are ready.
968 complete_blocked_syscalls() does the second half of the trick,
969 possibly much later: it delivers the results from ready fds to
970 threads in WaitFD state.
971*/
sewardj9a199dc2002-04-14 13:01:38 +0000972static
sewardje663cb92002-04-12 10:26:32 +0000973void poll_for_ready_fds ( void )
974{
975 vki_ksigset_t saved_procmask;
976 vki_fd_set readfds;
977 vki_fd_set writefds;
978 vki_fd_set exceptfds;
979 struct vki_timeval timeout;
980 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
981 ThreadId tid;
982 Bool rd_ok, wr_ok, ex_ok;
983 Char msg_buf[100];
984
sewardje462e202002-04-13 04:09:07 +0000985 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000986 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000987
sewardje663cb92002-04-12 10:26:32 +0000988 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000989 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000990 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000991 break;
sewardj6072c362002-04-19 14:40:57 +0000992
sewardj5f07b662002-04-23 16:52:51 +0000993 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000994 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000995 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000996 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000997 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000998 continue;
sewardj018f7622002-05-15 21:13:39 +0000999 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +00001000 /* Resume this thread. Set to zero the remaining-time
1001 (second) arg of nanosleep, since it's used up all its
1002 time. */
sewardj018f7622002-05-15 21:13:39 +00001003 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
1004 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +00001005 if (rem != NULL) {
1006 rem->tv_sec = 0;
1007 rem->tv_nsec = 0;
1008 }
1009 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +00001010 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +00001011 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +00001012 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +00001013 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +00001014 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +00001015 t_now);
1016 print_sched_event(tid, msg_buf);
1017 }
sewardje663cb92002-04-12 10:26:32 +00001018 }
1019 }
1020 }
sewardje663cb92002-04-12 10:26:32 +00001021
sewardje462e202002-04-13 04:09:07 +00001022 /* And look for threads waiting on file descriptors which are now
1023 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +00001024 timeout.tv_sec = 0;
1025 timeout.tv_usec = 0;
1026
1027 VKI_FD_ZERO(&readfds);
1028 VKI_FD_ZERO(&writefds);
1029 VKI_FD_ZERO(&exceptfds);
1030 fd_max = -1;
1031 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1032 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1033 continue;
1034 if (vg_waiting_fds[i].ready /* already ready? */)
1035 continue;
1036 fd = vg_waiting_fds[i].fd;
1037 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001038 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001039 if (fd > fd_max)
1040 fd_max = fd;
1041 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001042 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001043 syscall_no = vg_waiting_fds[i].syscall_no;
1044 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001045 case __NR_read:
1046 /* In order to catch timeout events on fds which are
1047 readable and which have been ioctl(TCSETA)'d with a
1048 VTIMEout, we appear to need to ask if the fd is
1049 writable, for some reason. Ask me not why. Since this
1050 is strange and potentially troublesome we only do it if
1051 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001052 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001053 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001054 VKI_FD_SET(fd, &readfds); break;
1055 case __NR_write:
1056 VKI_FD_SET(fd, &writefds); break;
1057 default:
1058 VG_(panic)("poll_for_ready_fds: unexpected syscall");
1059 /*NOTREACHED*/
1060 break;
1061 }
1062 }
1063
sewardje462e202002-04-13 04:09:07 +00001064 /* Short cut: if no fds are waiting, give up now. */
1065 if (fd_max == -1)
1066 return;
1067
sewardje663cb92002-04-12 10:26:32 +00001068 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1069 getting interrupted. */
1070 VG_(block_all_host_signals)( &saved_procmask );
1071
1072 n_ready = VG_(select)
1073 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1074 if (VG_(is_kerror)(n_ready)) {
1075 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
1076 VG_(panic)("poll_for_ready_fds: select failed?!");
1077 /*NOTREACHED*/
1078 }
1079
1080 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001081 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001082
1083 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1084
1085 if (n_ready == 0)
1086 return;
1087
1088 /* Inspect all the fds we know about, and handle any completions that
1089 have happened. */
1090 /*
1091 VG_(printf)("\n\n");
1092 for (fd = 0; fd < 100; fd++)
1093 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1094 VG_(printf)("X"); } else { VG_(printf)("."); };
1095 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1096 */
1097
1098 for (fd = 0; fd <= fd_max; fd++) {
1099 rd_ok = VKI_FD_ISSET(fd, &readfds);
1100 wr_ok = VKI_FD_ISSET(fd, &writefds);
1101 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1102
1103 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1104 if (n_ok == 0)
1105 continue;
1106 if (n_ok > 1) {
1107 VG_(printf)("offending fd = %d\n", fd);
1108 VG_(panic)("poll_for_ready_fds: multiple events on fd");
1109 }
sewardjbc7d8782002-06-30 12:44:54 +00001110
sewardje663cb92002-04-12 10:26:32 +00001111 /* An I/O event completed for fd. Find the thread which
1112 requested this. */
1113 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1114 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1115 continue;
1116 if (vg_waiting_fds[i].fd == fd)
1117 break;
1118 }
1119
1120 /* And a bit more paranoia ... */
1121 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1122
1123 /* Mark the fd as ready. */
1124 vg_assert(! vg_waiting_fds[i].ready);
1125 vg_waiting_fds[i].ready = True;
1126 }
1127}
1128
1129
1130/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001131static
sewardje663cb92002-04-12 10:26:32 +00001132void complete_blocked_syscalls ( void )
1133{
1134 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001135 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001136 ThreadId tid;
1137 Char msg_buf[100];
1138
1139 /* Inspect all the outstanding fds we know about. */
1140
1141 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1142 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1143 continue;
1144 if (! vg_waiting_fds[i].ready)
1145 continue;
1146
1147 fd = vg_waiting_fds[i].fd;
1148 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001149 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001150
1151 /* The thread actually has to be waiting for the I/O event it
1152 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001153 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001154 continue;
1155
1156 /* Ok, actually do it! We can safely use %EAX as the syscall
1157 number, because the speculative call made by
1158 sched_do_syscall() doesn't change %EAX in the case where the
1159 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001160 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001161 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001162
njn25e49d8e72002-09-23 09:36:25 +00001163 pre_res = vg_waiting_fds[i].pre_result;
1164
sewardjbc7d8782002-06-30 12:44:54 +00001165 /* In a rare case pertaining to writing into a pipe, write()
1166 will block when asked to write > 4096 bytes even though the
1167 kernel claims, when asked via select(), that blocking will
1168 not occur for a write on that fd. This can cause deadlocks.
1169 An easy answer is to limit the size of the write to 4096
1170 anyway and hope that the client program's logic can handle
1171 the short write. That shoulds dubious to me, so we don't do
1172 it by default. */
1173 if (syscall_no == __NR_write
1174 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1175 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1176 /* VG_(printf)("truncate write from %d to 4096\n",
1177 VG_(threads)[tid].m_edx ); */
1178 VG_(threads)[tid].m_edx = 4096;
1179 }
1180
sewardje663cb92002-04-12 10:26:32 +00001181 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001182 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001183
1184 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001185 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001186 /* Mark slot as no longer in use. */
1187 vg_waiting_fds[i].fd = -1;
1188 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001189 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001190 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1191 print_sched_event(tid, msg_buf);
1192 }
1193 }
1194}
1195
1196
1197static
sewardj5f07b662002-04-23 16:52:51 +00001198void check_for_pthread_cond_timedwait ( void )
1199{
sewardj51c0aaf2002-04-25 01:32:10 +00001200 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001201 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001202 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001203 continue;
sewardj018f7622002-05-15 21:13:39 +00001204 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001205 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001206 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001207 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001208 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001209 }
sewardj5f07b662002-04-23 16:52:51 +00001210 }
1211}
1212
1213
1214static
sewardje663cb92002-04-12 10:26:32 +00001215void nanosleep_for_a_while ( void )
1216{
1217 Int res;
1218 struct vki_timespec req;
1219 struct vki_timespec rem;
1220 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001221 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001222 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001223 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001224}
1225
1226
1227/* ---------------------------------------------------------------------
1228 The scheduler proper.
1229 ------------------------------------------------------------------ */
1230
1231/* Run user-space threads until either
1232 * Deadlock occurs
1233 * One thread asks to shutdown Valgrind
1234 * The specified number of basic blocks has gone by.
1235*/
1236VgSchedReturnCode VG_(scheduler) ( void )
1237{
1238 ThreadId tid, tid_next;
1239 UInt trc;
1240 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001241 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001242 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001243 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001244
1245 /* For the LRU structures, records when the epoch began. */
1246 ULong lru_epoch_started_at = 0;
1247
1248 /* Start with the root thread. tid in general indicates the
1249 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001250 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001251
1252 /* This is the top level scheduler loop. It falls into three
1253 phases. */
1254 while (True) {
1255
sewardj6072c362002-04-19 14:40:57 +00001256 /* ======================= Phase 0 of 3 =======================
1257 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001258 stage1:
sewardj6072c362002-04-19 14:40:57 +00001259 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001260 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001261
sewardje663cb92002-04-12 10:26:32 +00001262 /* ======================= Phase 1 of 3 =======================
1263 Handle I/O completions and signals. This may change the
1264 status of various threads. Then select a new thread to run,
1265 or declare deadlock, or sleep if there are no runnable
1266 threads but some are blocked on I/O. */
1267
1268 /* Age the LRU structures if an epoch has been completed. */
1269 if (VG_(bbs_done) - lru_epoch_started_at >= VG_BBS_PER_EPOCH) {
1270 lru_epoch_started_at = VG_(bbs_done);
1271 increment_epoch();
1272 }
1273
1274 /* Was a debug-stop requested? */
1275 if (VG_(bbs_to_go) == 0)
1276 goto debug_stop;
1277
1278 /* Do the following loop until a runnable thread is found, or
1279 deadlock is detected. */
1280 while (True) {
1281
1282 /* For stats purposes only. */
1283 VG_(num_scheduling_events_MAJOR) ++;
1284
1285 /* See if any I/O operations which we were waiting for have
1286 completed, and, if so, make runnable the relevant waiting
1287 threads. */
1288 poll_for_ready_fds();
1289 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001290 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001291
1292 /* See if there are any signals which need to be delivered. If
1293 so, choose thread(s) to deliver them to, and build signal
1294 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001295
1296 /* Be careful about delivering signals to a thread waiting
1297 for a mutex. In particular, when the handler is running,
1298 that thread is temporarily apparently-not-waiting for the
1299 mutex, so if it is unlocked by another thread whilst the
1300 handler is running, this thread is not informed. When the
1301 handler returns, the thread resumes waiting on the mutex,
1302 even if, as a result, it has missed the unlocking of it.
1303 Potential deadlock. This sounds all very strange, but the
1304 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001305 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001306 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001307 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001308
1309 /* Try and find a thread (tid) to run. */
1310 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001311 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001312 while (True) {
1313 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001314 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001315 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1316 || VG_(threads)[tid_next].status == VgTs_Sleeping
1317 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1318 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1319 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001320 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001321 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001322 break; /* We can run this one. */
1323 if (tid_next == tid)
1324 break; /* been all the way round */
1325 }
1326 tid = tid_next;
1327
sewardj018f7622002-05-15 21:13:39 +00001328 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001329 /* Found a suitable candidate. Fall out of this loop, so
1330 we can advance to stage 2 of the scheduler: actually
1331 running the thread. */
1332 break;
1333 }
1334
1335 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001336 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001337 /* No runnable threads and no prospect of any appearing
1338 even if we wait for an arbitrary length of time. In
1339 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001340 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001341 return VgSrc_Deadlock;
1342 }
1343
1344 /* At least one thread is in a fd-wait state. Delay for a
1345 while, and go round again, in the hope that eventually a
1346 thread becomes runnable. */
1347 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001348 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001349 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001350 }
1351
1352
1353 /* ======================= Phase 2 of 3 =======================
1354 Wahey! We've finally decided that thread tid is runnable, so
1355 we now do that. Run it for as much of a quanta as possible.
1356 Trivial requests are handled and the thread continues. The
1357 aim is not to do too many of Phase 1 since it is expensive. */
1358
1359 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001360 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001361
njn25e49d8e72002-09-23 09:36:25 +00001362 VG_TRACK( thread_run, tid );
1363
sewardje663cb92002-04-12 10:26:32 +00001364 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1365 that it decrements the counter before testing it for zero, so
1366 that if VG_(dispatch_ctr) is set to N you get at most N-1
1367 iterations. Also this means that VG_(dispatch_ctr) must
1368 exceed zero before entering the innerloop. Also also, the
1369 decrement is done before the bb is actually run, so you
1370 always get at least one decrement even if nothing happens.
1371 */
1372 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1373 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1374 else
1375 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1376
1377 /* ... and remember what we asked for. */
1378 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1379
sewardj1e8cdc92002-04-18 11:37:52 +00001380 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001381 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001382
sewardje663cb92002-04-12 10:26:32 +00001383 /* Actually run thread tid. */
1384 while (True) {
1385
sewardj7e87e382002-05-03 19:09:05 +00001386 VG_(last_run_tid) = tid;
1387
sewardje663cb92002-04-12 10:26:32 +00001388 /* For stats purposes only. */
1389 VG_(num_scheduling_events_MINOR) ++;
1390
1391 if (0)
1392 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1393 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001394# if 0
1395 if (VG_(bbs_done) > 31700000 + 0) {
1396 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001397 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001398 NULL,NULL,NULL);
1399 }
sewardj018f7622002-05-15 21:13:39 +00001400 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001401# endif
sewardje663cb92002-04-12 10:26:32 +00001402
1403 trc = run_thread_for_a_while ( tid );
1404
sewardjb3eef6b2002-05-01 00:05:27 +00001405# if 0
sewardj018f7622002-05-15 21:13:39 +00001406 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001407 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001408 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001409 }
1410# endif
1411
sewardje663cb92002-04-12 10:26:32 +00001412 /* Deal quickly with trivial scheduling events, and resume the
1413 thread. */
1414
1415 if (trc == VG_TRC_INNER_FASTMISS) {
1416 vg_assert(VG_(dispatch_ctr) > 0);
1417
1418 /* Trivial event. Miss in the fast-cache. Do a full
1419 lookup for it. */
1420 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001421 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001422 if (trans_addr == (Addr)0) {
1423 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001424 create_translation_for(
1425 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001426 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001427 if (trans_addr == (Addr)0)
1428 VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
1429 }
1430 continue; /* with this thread */
1431 }
1432
1433 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001434 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1435 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001436
1437 /* Are we really absolutely totally quitting? */
1438 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1439 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1440 VG_(message)(Vg_DebugMsg,
1441 "__libc_freeres() done; really quitting!");
1442 }
1443 return VgSrc_ExitSyscall;
1444 }
1445
sewardj124ca2a2002-06-20 10:19:38 +00001446 do_client_request(tid);
1447 /* Following the request, we try and continue with the
1448 same thread if still runnable. If not, go back to
1449 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001450 if (VG_(threads)[tid].status == VgTs_Runnable
1451 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001452 continue; /* with this thread */
1453 else
1454 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001455 }
1456
sewardj51c0aaf2002-04-25 01:32:10 +00001457 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1458 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001459 to become non-runnable. One special case: spot the
1460 client doing calls to exit() and take this as the cue
1461 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001462# if 0
1463 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001464 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001465 VG_(printf)("\nBEFORE\n");
1466 for (i = 10; i >= -10; i--)
1467 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1468 }
1469# endif
1470
sewardj1fe7b002002-07-16 01:43:15 +00001471 /* Deal with calling __libc_freeres() at exit. When the
1472 client does __NR_exit, it's exiting for good. So we
1473 then run VG_(__libc_freeres_wrapper). That quits by
1474 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1475 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001476 currently running.
1477
1478 If not valgrinding (cachegrinding, etc) don't do this.
1479 __libc_freeres does some invalid frees which crash
1480 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001481
1482 /* If __NR_exit, remember the supplied argument. */
1483 if (VG_(threads)[tid].m_eax == __NR_exit)
1484 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1485
sewardjade9d0d2002-07-26 10:52:48 +00001486 if (VG_(threads)[tid].m_eax == __NR_exit
njn25e49d8e72002-09-23 09:36:25 +00001487 && ! VG_(needs).run_libc_freeres) {
sewardjade9d0d2002-07-26 10:52:48 +00001488 if (VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1489 VG_(message)(Vg_DebugMsg,
1490 "Caught __NR_exit; quitting");
1491 }
1492 return VgSrc_ExitSyscall;
1493 }
1494
sewardj1fe7b002002-07-16 01:43:15 +00001495 if (VG_(threads)[tid].m_eax == __NR_exit) {
njn25e49d8e72002-09-23 09:36:25 +00001496 vg_assert(VG_(needs).run_libc_freeres);
sewardj1fe7b002002-07-16 01:43:15 +00001497 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1498 VG_(message)(Vg_DebugMsg,
1499 "Caught __NR_exit; running __libc_freeres()");
1500 }
1501 VG_(nuke_all_threads_except) ( tid );
1502 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1503 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1504 goto stage1; /* party on, dudes (but not for much longer :) */
1505 }
sewardj7e87e382002-05-03 19:09:05 +00001506
sewardj83798bf2002-05-24 00:11:16 +00001507 /* Trap syscalls to __NR_sched_yield and just have this
1508 thread yield instead. Not essential, just an
1509 optimisation. */
1510 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1511 SET_EAX(tid, 0); /* syscall returns with success */
1512 goto stage1; /* find a new thread to run */
1513 }
1514
sewardj51c0aaf2002-04-25 01:32:10 +00001515 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001516
1517# if 0
1518 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001519 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001520 VG_(printf)("AFTER\n");
1521 for (i = 10; i >= -10; i--)
1522 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1523 }
1524# endif
1525
sewardj77f0fc12002-07-12 01:23:03 +00001526 if (VG_(threads)[tid].status == VgTs_Runnable) {
1527 /* Better do a signal check, since if in a tight loop
1528 with a slow syscall it may be a very long time
1529 before we get back to the main signal check in Stage 1. */
1530 sigs_delivered = VG_(deliver_signals)();
1531 if (sigs_delivered)
1532 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001533 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001534 } else {
1535 goto stage1;
1536 }
sewardj51c0aaf2002-04-25 01:32:10 +00001537 }
1538
sewardjd7fd4d22002-04-24 01:57:27 +00001539 /* It's an event we can't quickly deal with. Give up running
1540 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001541 break;
1542 }
1543
1544 /* ======================= Phase 3 of 3 =======================
1545 Handle non-trivial thread requests, mostly pthread stuff. */
1546
1547 /* Ok, we've fallen out of the dispatcher for a
1548 non-completely-trivial reason. First, update basic-block
1549 counters. */
1550
1551 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1552 vg_assert(done_this_time >= 0);
1553 VG_(bbs_to_go) -= (ULong)done_this_time;
1554 VG_(bbs_done) += (ULong)done_this_time;
1555
1556 if (0 && trc != VG_TRC_INNER_FASTMISS)
1557 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1558 tid, done_this_time, (Int)trc );
1559
1560 if (0 && trc != VG_TRC_INNER_FASTMISS)
1561 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1562 tid, VG_(bbs_done),
1563 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001564
sewardje663cb92002-04-12 10:26:32 +00001565 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001566 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001567
1568 switch (trc) {
1569
sewardje663cb92002-04-12 10:26:32 +00001570 case VG_TRC_INNER_COUNTERZERO:
1571 /* Timeslice is out. Let a new thread be scheduled,
1572 simply by doing nothing, causing us to arrive back at
1573 Phase 1. */
1574 if (VG_(bbs_to_go) == 0) {
1575 goto debug_stop;
1576 }
1577 vg_assert(VG_(dispatch_ctr) == 0);
1578 break;
1579
1580 case VG_TRC_UNRESUMABLE_SIGNAL:
1581 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1582 away. Again, do nothing, so we wind up back at Phase
1583 1, whereupon the signal will be "delivered". */
1584 break;
1585
sewardje663cb92002-04-12 10:26:32 +00001586 default:
1587 VG_(printf)("\ntrc = %d\n", trc);
1588 VG_(panic)("VG_(scheduler), phase 3: "
1589 "unexpected thread return code");
1590 /* NOTREACHED */
1591 break;
1592
1593 } /* switch (trc) */
1594
1595 /* That completes Phase 3 of 3. Return now to the top of the
1596 main scheduler loop, to Phase 1 of 3. */
1597
1598 } /* top-level scheduler loop */
1599
1600
1601 /* NOTREACHED */
1602 VG_(panic)("scheduler: post-main-loop ?!");
1603 /* NOTREACHED */
1604
1605 debug_stop:
1606 /* If we exited because of a debug stop, print the translation
1607 of the last block executed -- by translating it again, and
1608 throwing away the result. */
1609 VG_(printf)(
1610 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001611 VG_(translate)( &VG_(threads)[tid],
1612 VG_(threads)[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001613 VG_(printf)("\n");
1614 VG_(printf)(
1615 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1616
1617 return VgSrc_BbsDone;
1618}
1619
1620
1621/* ---------------------------------------------------------------------
1622 The pthread implementation.
1623 ------------------------------------------------------------------ */
1624
1625#include <pthread.h>
1626#include <errno.h>
1627
sewardjbf290b92002-05-01 02:28:01 +00001628#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001629 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001630
1631/* /usr/include/bits/pthreadtypes.h:
1632 typedef unsigned long int pthread_t;
1633*/
1634
sewardje663cb92002-04-12 10:26:32 +00001635
sewardj604ec3c2002-04-18 22:38:41 +00001636/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001637 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001638 -------------------------------------------------------- */
1639
sewardj20917d82002-05-28 01:36:45 +00001640/* We've decided to action a cancellation on tid. Make it jump to
1641 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1642 as the arg. */
1643static
1644void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1645{
1646 Char msg_buf[100];
1647 vg_assert(VG_(is_valid_tid)(tid));
1648 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1649 handler -- which is really thread_exit_wrapper() in
1650 vg_libpthread.c. */
1651 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1652 VG_(threads)[tid].m_esp -= 4;
1653 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1654 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1655 VG_(threads)[tid].status = VgTs_Runnable;
1656 /* Make sure we aren't cancelled again whilst handling this
1657 cancellation. */
1658 VG_(threads)[tid].cancel_st = False;
1659 if (VG_(clo_trace_sched)) {
1660 VG_(sprintf)(msg_buf,
1661 "jump to cancellation handler (hdlr = %p)",
1662 VG_(threads)[tid].cancel_pend);
1663 print_sched_event(tid, msg_buf);
1664 }
1665}
1666
1667
1668
sewardjb48e5002002-05-13 00:16:03 +00001669/* Release resources and generally clean up once a thread has finally
1670 disappeared. */
1671static
1672void cleanup_after_thread_exited ( ThreadId tid )
1673{
sewardj89f20fd2002-06-30 10:57:30 +00001674 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001675 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001676 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1677 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001678 /* Its stack is now off-limits */
1679 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1680 VG_(threads)[tid].stack_size );
1681
sewardjb48e5002002-05-13 00:16:03 +00001682 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001683 thread, and get rid of signal handlers specifically arranged for
1684 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001685 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001686 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001687
1688 /* Clean up the waiting_fd table */
1689 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1690 if (vg_waiting_fds[i].tid == tid) {
1691 vg_waiting_fds[i].fd = -1; /* not in use */
1692 }
1693 }
sewardj92a59562002-09-30 00:53:10 +00001694
1695 /* Deallocate its LDT, if it ever had one. */
1696 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1697 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001698}
1699
1700
sewardj20917d82002-05-28 01:36:45 +00001701/* Look for matching pairs of threads waiting for joiners and threads
1702 waiting for joinees. For each such pair copy the return value of
1703 the joinee into the joiner, let the joiner resume and discard the
1704 joinee. */
1705static
1706void maybe_rendezvous_joiners_and_joinees ( void )
1707{
1708 Char msg_buf[100];
1709 void** thread_return;
1710 ThreadId jnr, jee;
1711
1712 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1713 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1714 continue;
1715 jee = VG_(threads)[jnr].joiner_jee_tid;
1716 if (jee == VG_INVALID_THREADID)
1717 continue;
1718 vg_assert(VG_(is_valid_tid)(jee));
1719 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1720 continue;
1721 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1722 joined by ... well, any thread. So let's do it! */
1723
1724 /* Copy return value to where joiner wants it. */
1725 thread_return = VG_(threads)[jnr].joiner_thread_return;
1726 if (thread_return != NULL) {
1727 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001728 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1729 "pthread_join: thread_return",
1730 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001731
sewardj20917d82002-05-28 01:36:45 +00001732 *thread_return = VG_(threads)[jee].joinee_retval;
1733 /* Not really right, since it makes the thread's return value
1734 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001735 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001736 }
1737
1738 /* Joinee is discarded */
1739 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1740 cleanup_after_thread_exited ( jee );
1741 if (VG_(clo_trace_sched)) {
1742 VG_(sprintf)(msg_buf,
1743 "rendezvous with joinee %d. %d resumes, %d exits.",
1744 jee, jnr, jee );
1745 print_sched_event(jnr, msg_buf);
1746 }
1747
1748 /* joiner returns with success */
1749 VG_(threads)[jnr].status = VgTs_Runnable;
1750 SET_EDX(jnr, 0);
1751 }
1752}
1753
1754
sewardjccef2e62002-05-29 19:26:32 +00001755/* Nuke all threads other than tid. POSIX specifies that this should
1756 happen in __NR_exec, and after a __NR_fork() when I am the child,
1757 as POSIX requires. */
1758void VG_(nuke_all_threads_except) ( ThreadId me )
1759{
1760 ThreadId tid;
1761 for (tid = 1; tid < VG_N_THREADS; tid++) {
1762 if (tid == me
1763 || VG_(threads)[tid].status == VgTs_Empty)
1764 continue;
sewardjef037c72002-05-30 00:40:03 +00001765 if (0)
1766 VG_(printf)(
1767 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001768 VG_(threads)[tid].status = VgTs_Empty;
1769 cleanup_after_thread_exited( tid );
1770 }
1771}
1772
1773
sewardj20917d82002-05-28 01:36:45 +00001774/* -----------------------------------------------------------
1775 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1776 -------------------------------------------------------- */
1777
sewardje663cb92002-04-12 10:26:32 +00001778static
sewardj8ad94e12002-05-29 00:10:20 +00001779void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1780{
1781 Int sp;
1782 Char msg_buf[100];
1783 vg_assert(VG_(is_valid_tid)(tid));
1784 sp = VG_(threads)[tid].custack_used;
1785 if (VG_(clo_trace_sched)) {
1786 VG_(sprintf)(msg_buf,
1787 "cleanup_push (fn %p, arg %p) -> slot %d",
1788 cu->fn, cu->arg, sp);
1789 print_sched_event(tid, msg_buf);
1790 }
1791 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1792 if (sp == VG_N_CLEANUPSTACK)
1793 VG_(panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
1794 " Increase and recompile.");
1795 VG_(threads)[tid].custack[sp] = *cu;
1796 sp++;
1797 VG_(threads)[tid].custack_used = sp;
1798 SET_EDX(tid, 0);
1799}
1800
1801
1802static
1803void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1804{
1805 Int sp;
1806 Char msg_buf[100];
1807 vg_assert(VG_(is_valid_tid)(tid));
1808 sp = VG_(threads)[tid].custack_used;
1809 if (VG_(clo_trace_sched)) {
1810 VG_(sprintf)(msg_buf,
sewardj4dced352002-06-04 22:54:20 +00001811 "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001812 print_sched_event(tid, msg_buf);
1813 }
1814 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1815 if (sp == 0) {
1816 SET_EDX(tid, -1);
1817 return;
1818 }
1819 sp--;
1820 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001821 // JJJ: no corresponding pre_mem_write check??
1822 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001823 VG_(threads)[tid].custack_used = sp;
1824 SET_EDX(tid, 0);
1825}
1826
1827
1828static
sewardjff42d1d2002-05-22 13:17:31 +00001829void do_pthread_yield ( ThreadId tid )
1830{
1831 Char msg_buf[100];
1832 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001833 if (VG_(clo_trace_sched)) {
1834 VG_(sprintf)(msg_buf, "yield");
1835 print_sched_event(tid, msg_buf);
1836 }
1837 SET_EDX(tid, 0);
1838}
1839
1840
1841static
sewardj20917d82002-05-28 01:36:45 +00001842void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001843{
sewardj7989d0c2002-05-28 11:00:01 +00001844 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001845 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001846 if (VG_(clo_trace_sched)) {
1847 VG_(sprintf)(msg_buf, "testcancel");
1848 print_sched_event(tid, msg_buf);
1849 }
sewardj20917d82002-05-28 01:36:45 +00001850 if (/* is there a cancellation pending on this thread? */
1851 VG_(threads)[tid].cancel_pend != NULL
1852 && /* is this thread accepting cancellations? */
1853 VG_(threads)[tid].cancel_st) {
1854 /* Ok, let's do the cancellation. */
1855 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001856 } else {
sewardj20917d82002-05-28 01:36:45 +00001857 /* No, we keep going. */
1858 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001859 }
sewardje663cb92002-04-12 10:26:32 +00001860}
1861
1862
1863static
sewardj20917d82002-05-28 01:36:45 +00001864void do__set_cancelstate ( ThreadId tid, Int state )
1865{
1866 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001867 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001868 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001869 if (VG_(clo_trace_sched)) {
1870 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1871 state==PTHREAD_CANCEL_ENABLE
1872 ? "ENABLE"
1873 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1874 print_sched_event(tid, msg_buf);
1875 }
sewardj20917d82002-05-28 01:36:45 +00001876 old_st = VG_(threads)[tid].cancel_st;
1877 if (state == PTHREAD_CANCEL_ENABLE) {
1878 VG_(threads)[tid].cancel_st = True;
1879 } else
1880 if (state == PTHREAD_CANCEL_DISABLE) {
1881 VG_(threads)[tid].cancel_st = False;
1882 } else {
1883 VG_(panic)("do__set_cancelstate");
1884 }
1885 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1886 : PTHREAD_CANCEL_DISABLE);
1887}
1888
1889
1890static
1891void do__set_canceltype ( ThreadId tid, Int type )
1892{
1893 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001894 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001895 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001896 if (VG_(clo_trace_sched)) {
1897 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1898 type==PTHREAD_CANCEL_ASYNCHRONOUS
1899 ? "ASYNCHRONOUS"
1900 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1901 print_sched_event(tid, msg_buf);
1902 }
sewardj20917d82002-05-28 01:36:45 +00001903 old_ty = VG_(threads)[tid].cancel_ty;
1904 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1905 VG_(threads)[tid].cancel_ty = False;
1906 } else
1907 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001908 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001909 } else {
1910 VG_(panic)("do__set_canceltype");
1911 }
1912 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1913 : PTHREAD_CANCEL_ASYNCHRONOUS);
1914}
1915
1916
sewardj7989d0c2002-05-28 11:00:01 +00001917/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001918static
sewardj7989d0c2002-05-28 11:00:01 +00001919void do__set_or_get_detach ( ThreadId tid,
1920 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001921{
sewardj7989d0c2002-05-28 11:00:01 +00001922 ThreadId i;
1923 Char msg_buf[100];
1924 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1925 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001926 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001927 if (VG_(clo_trace_sched)) {
1928 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1929 what==0 ? "not-detached" : (
1930 what==1 ? "detached" : (
1931 what==2 ? "fetch old value" : "???")),
1932 det );
1933 print_sched_event(tid, msg_buf);
1934 }
1935
1936 if (!VG_(is_valid_tid)(det)) {
1937 SET_EDX(tid, -1);
1938 return;
1939 }
1940
sewardj20917d82002-05-28 01:36:45 +00001941 switch (what) {
1942 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001943 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001944 return;
sewardj7989d0c2002-05-28 11:00:01 +00001945 case 1: /* set detached. If someone is in a join-wait for det,
1946 do not detach. */
1947 for (i = 1; i < VG_N_THREADS; i++) {
1948 if (VG_(threads)[i].status == VgTs_WaitJoinee
1949 && VG_(threads)[i].joiner_jee_tid == det) {
1950 SET_EDX(tid, 0);
1951 if (VG_(clo_trace_sched)) {
1952 VG_(sprintf)(msg_buf,
1953 "tid %d not detached because %d in join-wait for it %d",
1954 det, i);
1955 print_sched_event(tid, msg_buf);
1956 }
1957 return;
1958 }
1959 }
1960 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001961 SET_EDX(tid, 0);
1962 return;
1963 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001964 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001965 SET_EDX(tid, 0);
1966 return;
1967 default:
1968 VG_(panic)("do__set_or_get_detach");
1969 }
1970}
1971
1972
1973static
1974void do__set_cancelpend ( ThreadId tid,
1975 ThreadId cee,
1976 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001977{
1978 Char msg_buf[100];
1979
sewardj20917d82002-05-28 01:36:45 +00001980 vg_assert(VG_(is_valid_tid)(tid));
1981 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1982
sewardj7989d0c2002-05-28 11:00:01 +00001983 if (!VG_(is_valid_tid)(cee)) {
1984 if (VG_(clo_trace_sched)) {
1985 VG_(sprintf)(msg_buf,
1986 "set_cancelpend for invalid tid %d", cee);
1987 print_sched_event(tid, msg_buf);
1988 }
njn25e49d8e72002-09-23 09:36:25 +00001989 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00001990 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00001991 SET_EDX(tid, -VKI_ESRCH);
1992 return;
1993 }
sewardj20917d82002-05-28 01:36:45 +00001994
1995 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
1996
1997 if (VG_(clo_trace_sched)) {
1998 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001999 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00002000 cancelpend_hdlr, tid);
2001 print_sched_event(cee, msg_buf);
2002 }
2003
2004 /* Thread doing the cancelling returns with success. */
2005 SET_EDX(tid, 0);
2006
2007 /* Perhaps we can nuke the cancellee right now? */
2008 do__testcancel(cee);
2009}
2010
2011
2012static
2013void do_pthread_join ( ThreadId tid,
2014 ThreadId jee, void** thread_return )
2015{
2016 Char msg_buf[100];
2017 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00002018 /* jee, the joinee, is the thread specified as an arg in thread
2019 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00002020 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00002021 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002022
2023 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002024 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002025 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002026 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002027 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002028 return;
2029 }
2030
sewardj20917d82002-05-28 01:36:45 +00002031 /* Flush any completed pairs, so as to make sure what we're looking
2032 at is up-to-date. */
2033 maybe_rendezvous_joiners_and_joinees();
2034
2035 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002036 if (jee < 0
2037 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002038 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002039 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002040 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002041 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002042 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002043 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002044 return;
2045 }
2046
sewardj20917d82002-05-28 01:36:45 +00002047 /* Is anyone else already in a join-wait for jee? */
2048 for (i = 1; i < VG_N_THREADS; i++) {
2049 if (i == tid) continue;
2050 if (VG_(threads)[i].status == VgTs_WaitJoinee
2051 && VG_(threads)[i].joiner_jee_tid == jee) {
2052 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002053 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002054 "pthread_join: another thread already "
2055 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002056 SET_EDX(tid, EINVAL);
2057 VG_(threads)[tid].status = VgTs_Runnable;
2058 return;
2059 }
sewardje663cb92002-04-12 10:26:32 +00002060 }
2061
sewardj20917d82002-05-28 01:36:45 +00002062 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002063 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002064 VG_(threads)[tid].joiner_thread_return = thread_return;
2065 VG_(threads)[tid].joiner_jee_tid = jee;
2066
2067 /* Look for matching joiners and joinees and do the right thing. */
2068 maybe_rendezvous_joiners_and_joinees();
2069
2070 /* Return value is irrelevant since this this thread becomes
2071 non-runnable. maybe_resume_joiner() will cause it to return the
2072 right value when it resumes. */
2073
sewardj8937c812002-04-12 20:12:20 +00002074 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002075 VG_(sprintf)(msg_buf,
2076 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002077 print_sched_event(tid, msg_buf);
2078 }
sewardje663cb92002-04-12 10:26:32 +00002079}
2080
2081
sewardj20917d82002-05-28 01:36:45 +00002082/* ( void* ): calling thread waits for joiner and returns the void* to
2083 it. This is one of two ways in which a thread can finally exit --
2084 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002085static
sewardj20917d82002-05-28 01:36:45 +00002086void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002087{
sewardj20917d82002-05-28 01:36:45 +00002088 Char msg_buf[100];
2089 vg_assert(VG_(is_valid_tid)(tid));
2090 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2091 if (VG_(clo_trace_sched)) {
2092 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002093 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002094 print_sched_event(tid, msg_buf);
2095 }
2096 VG_(threads)[tid].status = VgTs_WaitJoiner;
2097 VG_(threads)[tid].joinee_retval = retval;
2098 maybe_rendezvous_joiners_and_joinees();
2099}
2100
2101
2102/* ( no-args ): calling thread disappears from the system forever.
2103 Reclaim resources. */
2104static
2105void do__quit ( ThreadId tid )
2106{
2107 Char msg_buf[100];
2108 vg_assert(VG_(is_valid_tid)(tid));
2109 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2110 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2111 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002112 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002113 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002114 print_sched_event(tid, msg_buf);
2115 }
2116 /* Return value is irrelevant; this thread will not get
2117 rescheduled. */
2118}
2119
2120
2121/* Should never be entered. If it is, will be on the simulated
2122 CPU. */
2123static
2124void do__apply_in_new_thread_bogusRA ( void )
2125{
2126 VG_(panic)("do__apply_in_new_thread_bogusRA");
2127}
2128
2129/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2130 MUST NOT return -- ever. Eventually it will do either __QUIT or
2131 __WAIT_JOINER. Return the child tid to the parent. */
2132static
2133void do__apply_in_new_thread ( ThreadId parent_tid,
2134 void* (*fn)(void *),
2135 void* arg )
2136{
sewardje663cb92002-04-12 10:26:32 +00002137 Addr new_stack;
2138 UInt new_stk_szb;
2139 ThreadId tid;
2140 Char msg_buf[100];
2141
2142 /* Paranoia ... */
2143 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2144
sewardj018f7622002-05-15 21:13:39 +00002145 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002146
sewardj1e8cdc92002-04-18 11:37:52 +00002147 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002148
2149 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002150 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002151 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002152
2153 /* Copy the parent's CPU state into the child's, in a roundabout
2154 way (via baseBlock). */
2155 VG_(load_thread_state)(parent_tid);
2156 VG_(save_thread_state)(tid);
2157
2158 /* Consider allocating the child a stack, if the one it already has
2159 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002160 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002161
sewardj018f7622002-05-15 21:13:39 +00002162 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002163 /* Again, for good measure :) We definitely don't want to be
2164 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002165 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002166 /* for now, we don't handle the case of anything other than
2167 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002168 vg_assert(VG_(threads)[tid].stack_size == 0);
2169 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002170 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2171 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002172 VG_(threads)[tid].stack_base = new_stack;
2173 VG_(threads)[tid].stack_size = new_stk_szb;
2174 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002175 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002176 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002177 }
sewardj1e8cdc92002-04-18 11:37:52 +00002178
njn25e49d8e72002-09-23 09:36:25 +00002179 /* Having got memory to hold the thread's stack:
2180 - set %esp as base + size
2181 - mark everything below %esp inaccessible
2182 - mark redzone at stack end inaccessible
2183 */
2184 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2185 + VG_(threads)[tid].stack_size
2186 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002187
njn25e49d8e72002-09-23 09:36:25 +00002188 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2189 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2190 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2191 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002192
njn25e49d8e72002-09-23 09:36:25 +00002193 /* push two args */
2194 VG_(threads)[tid].m_esp -= 8;
2195 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2196 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2197 "new thread: stack",
2198 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2199
2200 /* push arg and (bogus) return address */
2201 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002202 * (UInt*)(VG_(threads)[tid].m_esp)
2203 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002204
njn25e49d8e72002-09-23 09:36:25 +00002205 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002206
2207 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002208 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002209
sewardj8937c812002-04-12 20:12:20 +00002210 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002211 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002212 print_sched_event(tid, msg_buf);
2213 }
2214
sewardj20917d82002-05-28 01:36:45 +00002215 /* Create new thread with default attrs:
2216 deferred cancellation, not detached
2217 */
2218 mostly_clear_thread_record(tid);
2219 VG_(threads)[tid].status = VgTs_Runnable;
sewardj5f07b662002-04-23 16:52:51 +00002220
sewardj018f7622002-05-15 21:13:39 +00002221 /* We inherit our parent's signal mask. */
2222 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002223 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002224
sewardj92a59562002-09-30 00:53:10 +00002225 /* We inherit our parent's LDT. */
2226 if (VG_(threads)[parent_tid].ldt == NULL) {
2227 /* We hope this is the common case. */
2228 VG_(threads)[tid].ldt = NULL;
2229 } else {
2230 /* No luck .. we have to take a copy of the parent's. */
2231 VG_(threads)[tid].ldt
2232 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2233 }
2234
sewardj20917d82002-05-28 01:36:45 +00002235 /* return child's tid to parent */
2236 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002237}
2238
2239
sewardj604ec3c2002-04-18 22:38:41 +00002240/* -----------------------------------------------------------
2241 MUTEXes
2242 -------------------------------------------------------- */
2243
sewardj604ec3c2002-04-18 22:38:41 +00002244/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002245 typedef struct
2246 {
2247 int __m_reserved; -- Reserved for future use
2248 int __m_count; -- Depth of recursive locking
2249 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2250 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2251 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2252 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002253
sewardj6072c362002-04-19 14:40:57 +00002254 #define PTHREAD_MUTEX_INITIALIZER \
2255 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2256 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2257 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2258 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2259 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2260 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2261 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002262
sewardj6072c362002-04-19 14:40:57 +00002263 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002264
sewardj6072c362002-04-19 14:40:57 +00002265 __m_kind never changes and indicates whether or not it is recursive.
2266
2267 __m_count indicates the lock count; if 0, the mutex is not owned by
2268 anybody.
2269
2270 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2271 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2272 statically initialised mutexes correctly appear
2273 to belong to nobody.
2274
2275 In summary, a not-in-use mutex is distinguised by having __m_owner
2276 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2277 conditions holds, the other should too.
2278
2279 There is no linked list of threads waiting for this mutex. Instead
2280 a thread in WaitMX state points at the mutex with its waited_on_mx
2281 field. This makes _unlock() inefficient, but simple to implement the
2282 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002283
sewardj604ec3c2002-04-18 22:38:41 +00002284 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002285 deals with that for us.
2286*/
sewardje663cb92002-04-12 10:26:32 +00002287
sewardj3b5d8862002-04-20 13:53:23 +00002288/* Helper fns ... */
2289static
2290void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2291 Char* caller )
2292{
2293 Int i;
2294 Char msg_buf[100];
2295
2296 /* Find some arbitrary thread waiting on this mutex, and make it
2297 runnable. If none are waiting, mark the mutex as not held. */
2298 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002299 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002300 continue;
sewardj018f7622002-05-15 21:13:39 +00002301 if (VG_(threads)[i].status == VgTs_WaitMX
2302 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002303 break;
2304 }
2305
2306 vg_assert(i <= VG_N_THREADS);
2307 if (i == VG_N_THREADS) {
2308 /* Nobody else is waiting on it. */
2309 mutex->__m_count = 0;
2310 mutex->__m_owner = VG_INVALID_THREADID;
2311 } else {
2312 /* Notionally transfer the hold to thread i, whose
2313 pthread_mutex_lock() call now returns with 0 (success). */
2314 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002315 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002316 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002317 VG_(threads)[i].status = VgTs_Runnable;
2318 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002319 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002320
2321 if (VG_(clo_trace_pthread_level) >= 1) {
2322 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2323 caller, mutex );
2324 print_pthread_event(i, msg_buf);
2325 }
2326 }
2327}
2328
sewardje663cb92002-04-12 10:26:32 +00002329
2330static
sewardj30671ff2002-04-21 00:13:57 +00002331void do_pthread_mutex_lock( ThreadId tid,
2332 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002333 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002334{
sewardj30671ff2002-04-21 00:13:57 +00002335 Char msg_buf[100];
2336 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002337 = is_trylock ? "pthread_mutex_trylock"
2338 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002339
sewardj604ec3c2002-04-18 22:38:41 +00002340 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002341 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002342 print_pthread_event(tid, msg_buf);
2343 }
2344
2345 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002346 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002347 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002348
2349 /* POSIX doesn't mandate this, but for sanity ... */
2350 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002351 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002352 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002353 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002354 return;
2355 }
2356
sewardj604ec3c2002-04-18 22:38:41 +00002357 /* More paranoia ... */
2358 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002359# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002360 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002361 case PTHREAD_MUTEX_ADAPTIVE_NP:
2362# endif
sewardja1679dd2002-05-10 22:31:40 +00002363# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002364 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002365# endif
sewardj604ec3c2002-04-18 22:38:41 +00002366 case PTHREAD_MUTEX_RECURSIVE_NP:
2367 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002368 if (mutex->__m_count >= 0) break;
2369 /* else fall thru */
2370 default:
njn25e49d8e72002-09-23 09:36:25 +00002371 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002372 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002373 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002374 return;
sewardje663cb92002-04-12 10:26:32 +00002375 }
2376
sewardj604ec3c2002-04-18 22:38:41 +00002377 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002378
sewardjb48e5002002-05-13 00:16:03 +00002379 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002380
2381 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002382 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002383 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002384 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002385 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002386 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002387 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002388 if (0)
2389 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2390 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002391 return;
2392 } else {
sewardj30671ff2002-04-21 00:13:57 +00002393 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002394 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002395 else
sewardjc3bd5f52002-05-01 03:24:23 +00002396 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002397 return;
2398 }
2399 } else {
sewardj6072c362002-04-19 14:40:57 +00002400 /* Someone else has it; we have to wait. Mark ourselves
2401 thusly. */
sewardj05553872002-04-20 20:53:17 +00002402 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002403 if (is_trylock) {
2404 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002405 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002406 } else {
sewardj018f7622002-05-15 21:13:39 +00002407 VG_(threads)[tid].status = VgTs_WaitMX;
2408 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002409 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002410 if (VG_(clo_trace_pthread_level) >= 1) {
2411 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2412 caller, mutex );
2413 print_pthread_event(tid, msg_buf);
2414 }
2415 }
sewardje663cb92002-04-12 10:26:32 +00002416 return;
2417 }
sewardjf8f819e2002-04-17 23:21:37 +00002418
sewardje663cb92002-04-12 10:26:32 +00002419 } else {
sewardj6072c362002-04-19 14:40:57 +00002420 /* Nobody owns it. Sanity check ... */
2421 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002422 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002423 mutex->__m_count = 1;
2424 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002425
2426 VG_TRACK( post_mutex_lock, tid, mutex);
2427
sewardje663cb92002-04-12 10:26:32 +00002428 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002429 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002430 }
sewardjf8f819e2002-04-17 23:21:37 +00002431
sewardje663cb92002-04-12 10:26:32 +00002432}
2433
2434
2435static
2436void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002437 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002438{
sewardj3b5d8862002-04-20 13:53:23 +00002439 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002440
sewardj45b4b372002-04-16 22:50:32 +00002441 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002442 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002443 print_pthread_event(tid, msg_buf);
2444 }
2445
sewardj604ec3c2002-04-18 22:38:41 +00002446 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002447 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002448 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002449
2450 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002451 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002452 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002453 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002454 return;
2455 }
2456
2457 /* More paranoia ... */
2458 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002459# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002460 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002461 case PTHREAD_MUTEX_ADAPTIVE_NP:
2462# endif
sewardja1679dd2002-05-10 22:31:40 +00002463# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002464 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002465# endif
sewardj604ec3c2002-04-18 22:38:41 +00002466 case PTHREAD_MUTEX_RECURSIVE_NP:
2467 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002468 if (mutex->__m_count >= 0) break;
2469 /* else fall thru */
2470 default:
njn25e49d8e72002-09-23 09:36:25 +00002471 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002472 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002473 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002474 return;
2475 }
sewardje663cb92002-04-12 10:26:32 +00002476
2477 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002478 if (mutex->__m_count == 0) {
2479 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002480 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002481 "pthread_mutex_unlock: mutex is not locked");
2482 SET_EDX(tid, EPERM);
2483 return;
2484 }
2485
2486 if ((ThreadId)mutex->__m_owner != tid) {
2487 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002488 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002489 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002490 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002491 return;
2492 }
2493
sewardjf8f819e2002-04-17 23:21:37 +00002494 /* If it's a multiply-locked recursive mutex, just decrement the
2495 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002496 if (mutex->__m_count > 1) {
2497 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2498 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002499 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002500 return;
2501 }
2502
sewardj604ec3c2002-04-18 22:38:41 +00002503 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002504 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002505 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002506 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002507
njn25e49d8e72002-09-23 09:36:25 +00002508 VG_TRACK( post_mutex_unlock, tid, mutex);
2509
sewardj3b5d8862002-04-20 13:53:23 +00002510 /* Release at max one thread waiting on this mutex. */
2511 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002512
sewardj3b5d8862002-04-20 13:53:23 +00002513 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002514 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002515}
2516
2517
sewardj6072c362002-04-19 14:40:57 +00002518/* -----------------------------------------------------------
2519 CONDITION VARIABLES
2520 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002521
sewardj6072c362002-04-19 14:40:57 +00002522/* The relevant native types are as follows:
2523 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002524
sewardj6072c362002-04-19 14:40:57 +00002525 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2526 typedef struct
2527 {
2528 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2529 _pthread_descr __c_waiting; -- Threads waiting on this condition
2530 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002531
sewardj6072c362002-04-19 14:40:57 +00002532 -- Attribute for conditionally variables.
2533 typedef struct
2534 {
2535 int __dummy;
2536 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002537
sewardj6072c362002-04-19 14:40:57 +00002538 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002539
sewardj3b5d8862002-04-20 13:53:23 +00002540 We don't use any fields of pthread_cond_t for anything at all.
2541 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002542
2543 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002544 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002545
sewardj77e466c2002-04-14 02:29:29 +00002546
sewardj5f07b662002-04-23 16:52:51 +00002547static
2548void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2549{
2550 Char msg_buf[100];
2551 pthread_mutex_t* mx;
2552 pthread_cond_t* cv;
2553
sewardjb48e5002002-05-13 00:16:03 +00002554 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002555 && VG_(threads)[tid].status == VgTs_WaitCV
2556 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2557 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002558 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002559 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002560 vg_assert(cv != NULL);
2561
2562 if (mx->__m_owner == VG_INVALID_THREADID) {
2563 /* Currently unheld; hand it out to thread tid. */
2564 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002565 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002566 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002567 VG_(threads)[tid].associated_cv = NULL;
2568 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002569 mx->__m_owner = (_pthread_descr)tid;
2570 mx->__m_count = 1;
2571
2572 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002573 VG_(sprintf)(msg_buf,
2574 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2575 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002576 print_pthread_event(tid, msg_buf);
2577 }
2578 } else {
2579 /* Currently held. Make thread tid be blocked on it. */
2580 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002581 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002582 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002583 VG_(threads)[tid].associated_cv = NULL;
2584 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002585 if (VG_(clo_trace_pthread_level) >= 1) {
2586 VG_(sprintf)(msg_buf,
2587 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2588 cv, mx );
2589 print_pthread_event(tid, msg_buf);
2590 }
2591
2592 }
2593}
2594
2595
sewardj3b5d8862002-04-20 13:53:23 +00002596static
2597void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2598 Int n_to_release,
2599 Char* caller )
2600{
2601 Int i;
2602 Char msg_buf[100];
2603 pthread_mutex_t* mx;
2604
2605 while (True) {
2606 if (n_to_release == 0)
2607 return;
2608
2609 /* Find a thread waiting on this CV. */
2610 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002611 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002612 continue;
sewardj018f7622002-05-15 21:13:39 +00002613 if (VG_(threads)[i].status == VgTs_WaitCV
2614 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002615 break;
2616 }
2617 vg_assert(i <= VG_N_THREADS);
2618
2619 if (i == VG_N_THREADS) {
2620 /* Nobody else is waiting on it. */
2621 return;
2622 }
2623
sewardj018f7622002-05-15 21:13:39 +00002624 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002625 vg_assert(mx != NULL);
2626
2627 if (mx->__m_owner == VG_INVALID_THREADID) {
2628 /* Currently unheld; hand it out to thread i. */
2629 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002630 VG_(threads)[i].status = VgTs_Runnable;
2631 VG_(threads)[i].associated_cv = NULL;
2632 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002633 mx->__m_owner = (_pthread_descr)i;
2634 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002635 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002636
2637 if (VG_(clo_trace_pthread_level) >= 1) {
2638 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2639 caller, cond, mx );
2640 print_pthread_event(i, msg_buf);
2641 }
2642
2643 } else {
2644 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002645 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002646 VG_(threads)[i].status = VgTs_WaitMX;
2647 VG_(threads)[i].associated_cv = NULL;
2648 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002649 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002650
2651 if (VG_(clo_trace_pthread_level) >= 1) {
2652 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2653 caller, cond, mx );
2654 print_pthread_event(i, msg_buf);
2655 }
2656
2657 }
2658
2659 n_to_release--;
2660 }
2661}
2662
2663
2664static
2665void do_pthread_cond_wait ( ThreadId tid,
2666 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002667 pthread_mutex_t *mutex,
2668 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002669{
2670 Char msg_buf[100];
2671
sewardj5f07b662002-04-23 16:52:51 +00002672 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2673 ms_end is the ending millisecond. */
2674
sewardj3b5d8862002-04-20 13:53:23 +00002675 /* pre: mutex should be a valid mutex and owned by tid. */
2676 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002677 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2678 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002679 print_pthread_event(tid, msg_buf);
2680 }
2681
2682 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002683 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002684 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002685
2686 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002687 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002688 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002689 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002690 return;
2691 }
2692
2693 /* More paranoia ... */
2694 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002695# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002696 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002697 case PTHREAD_MUTEX_ADAPTIVE_NP:
2698# endif
sewardja1679dd2002-05-10 22:31:40 +00002699# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002700 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002701# endif
sewardj3b5d8862002-04-20 13:53:23 +00002702 case PTHREAD_MUTEX_RECURSIVE_NP:
2703 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002704 if (mutex->__m_count >= 0) break;
2705 /* else fall thru */
2706 default:
njn25e49d8e72002-09-23 09:36:25 +00002707 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002708 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002709 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002710 return;
2711 }
2712
2713 /* Barf if we don't currently hold the mutex. */
2714 if (mutex->__m_count == 0 /* nobody holds it */
2715 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002716 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002717 "pthread_cond_wait/timedwait: mutex is unlocked "
2718 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002719 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002720 return;
2721 }
2722
2723 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002724 VG_(threads)[tid].status = VgTs_WaitCV;
2725 VG_(threads)[tid].associated_cv = cond;
2726 VG_(threads)[tid].associated_mx = mutex;
2727 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002728
2729 if (VG_(clo_trace_pthread_level) >= 1) {
2730 VG_(sprintf)(msg_buf,
2731 "pthread_cond_wait cv %p, mx %p: BLOCK",
2732 cond, mutex );
2733 print_pthread_event(tid, msg_buf);
2734 }
2735
2736 /* Release the mutex. */
2737 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2738}
2739
2740
2741static
2742void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2743 Bool broadcast,
2744 pthread_cond_t *cond )
2745{
2746 Char msg_buf[100];
2747 Char* caller
2748 = broadcast ? "pthread_cond_broadcast"
2749 : "pthread_cond_signal ";
2750
2751 if (VG_(clo_trace_pthread_level) >= 2) {
2752 VG_(sprintf)(msg_buf, "%s cv %p ...",
2753 caller, cond );
2754 print_pthread_event(tid, msg_buf);
2755 }
2756
2757 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002758 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002759 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002760
2761 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002762 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002763 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002764 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002765 return;
2766 }
2767
2768 release_N_threads_waiting_on_cond (
2769 cond,
2770 broadcast ? VG_N_THREADS : 1,
2771 caller
2772 );
2773
sewardjc3bd5f52002-05-01 03:24:23 +00002774 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002775}
2776
sewardj77e466c2002-04-14 02:29:29 +00002777
sewardj5f07b662002-04-23 16:52:51 +00002778/* -----------------------------------------------------------
2779 THREAD SPECIFIC DATA
2780 -------------------------------------------------------- */
2781
2782static __inline__
2783Bool is_valid_key ( ThreadKey k )
2784{
2785 /* k unsigned; hence no < 0 check */
2786 if (k >= VG_N_THREAD_KEYS) return False;
2787 if (!vg_thread_keys[k].inuse) return False;
2788 return True;
2789}
2790
2791static
2792void do_pthread_key_create ( ThreadId tid,
2793 pthread_key_t* key,
2794 void (*destructor)(void*) )
2795{
2796 Int i;
2797 Char msg_buf[100];
2798
2799 if (VG_(clo_trace_pthread_level) >= 1) {
2800 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2801 key, destructor );
2802 print_pthread_event(tid, msg_buf);
2803 }
2804
2805 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002806 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002807 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002808
2809 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2810 if (!vg_thread_keys[i].inuse)
2811 break;
2812
2813 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002814 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002815 return;
2816 */
2817 VG_(panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2818 " increase and recompile");
2819 }
2820
sewardj870497a2002-05-29 01:06:47 +00002821 vg_thread_keys[i].inuse = True;
2822 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002823
sewardj5a3798b2002-06-04 23:24:22 +00002824 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002825 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2826 "pthread_key_create: key",
2827 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002828 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002829 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002830
2831 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002832}
2833
2834
2835static
2836void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2837{
2838 Char msg_buf[100];
2839 if (VG_(clo_trace_pthread_level) >= 1) {
2840 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2841 key );
2842 print_pthread_event(tid, msg_buf);
2843 }
2844
sewardjb48e5002002-05-13 00:16:03 +00002845 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002846 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002847
2848 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002849 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002850 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002851 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002852 return;
2853 }
2854
2855 vg_thread_keys[key].inuse = False;
2856
2857 /* Optional. We're not required to do this, although it shouldn't
2858 make any difference to programs which use the key/specifics
2859 functions correctly. */
sewardj3b13f0e2002-04-25 20:17:29 +00002860# if 1
sewardj5f07b662002-04-23 16:52:51 +00002861 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00002862 if (VG_(threads)[tid].status != VgTs_Empty)
2863 VG_(threads)[tid].specifics[key] = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002864 }
sewardj3b13f0e2002-04-25 20:17:29 +00002865# endif
sewardj5f07b662002-04-23 16:52:51 +00002866}
2867
2868
2869static
2870void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
2871{
2872 Char msg_buf[100];
2873 if (VG_(clo_trace_pthread_level) >= 1) {
2874 VG_(sprintf)(msg_buf, "pthread_getspecific key %d",
2875 key );
2876 print_pthread_event(tid, msg_buf);
2877 }
2878
sewardjb48e5002002-05-13 00:16:03 +00002879 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002880 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002881
2882 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002883 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002884 "pthread_getspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002885 SET_EDX(tid, (UInt)NULL);
sewardj5f07b662002-04-23 16:52:51 +00002886 return;
2887 }
2888
sewardj018f7622002-05-15 21:13:39 +00002889 SET_EDX(tid, (UInt)VG_(threads)[tid].specifics[key]);
sewardj5f07b662002-04-23 16:52:51 +00002890}
2891
2892
2893static
2894void do_pthread_setspecific ( ThreadId tid,
2895 pthread_key_t key,
2896 void *pointer )
2897{
2898 Char msg_buf[100];
2899 if (VG_(clo_trace_pthread_level) >= 1) {
2900 VG_(sprintf)(msg_buf, "pthread_setspecific key %d, ptr %p",
2901 key, pointer );
2902 print_pthread_event(tid, msg_buf);
2903 }
2904
sewardjb48e5002002-05-13 00:16:03 +00002905 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002906 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002907
2908 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002909 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002910 "pthread_setspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002911 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002912 return;
2913 }
2914
sewardj018f7622002-05-15 21:13:39 +00002915 VG_(threads)[tid].specifics[key] = pointer;
sewardjc3bd5f52002-05-01 03:24:23 +00002916 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002917}
2918
2919
sewardj870497a2002-05-29 01:06:47 +00002920/* Helper for calling destructors at thread exit. If key is valid,
2921 copy the thread's specific value into cu->arg and put the *key*'s
2922 destructor fn address in cu->fn. Then return 0 to the caller.
2923 Otherwise return non-zero to the caller. */
2924static
2925void do__get_key_destr_and_spec ( ThreadId tid,
2926 pthread_key_t key,
2927 CleanupEntry* cu )
2928{
2929 Char msg_buf[100];
2930 if (VG_(clo_trace_pthread_level) >= 1) {
2931 VG_(sprintf)(msg_buf,
2932 "get_key_destr_and_arg (key = %d)", key );
2933 print_pthread_event(tid, msg_buf);
2934 }
2935 vg_assert(VG_(is_valid_tid)(tid));
2936 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00002937
2938 // JJJ: no pre_mem_write check??
2939
sewardj870497a2002-05-29 01:06:47 +00002940 if (!vg_thread_keys[key].inuse) {
2941 SET_EDX(tid, -1);
2942 return;
2943 }
2944 cu->fn = vg_thread_keys[key].destructor;
2945 cu->arg = VG_(threads)[tid].specifics[key];
njn25e49d8e72002-09-23 09:36:25 +00002946 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00002947 SET_EDX(tid, 0);
2948}
2949
2950
sewardjb48e5002002-05-13 00:16:03 +00002951/* ---------------------------------------------------
2952 SIGNALS
2953 ------------------------------------------------ */
2954
2955/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002956 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2957 for OK and 1 for some kind of addressing error, which the
2958 vg_libpthread.c routine turns into return values 0 and EFAULT
2959 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002960static
2961void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002962 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002963 vki_ksigset_t* newmask,
2964 vki_ksigset_t* oldmask )
2965{
2966 Char msg_buf[100];
2967 if (VG_(clo_trace_pthread_level) >= 1) {
2968 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00002969 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
2970 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002971 print_pthread_event(tid, msg_buf);
2972 }
2973
2974 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002975 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002976
njn25e49d8e72002-09-23 09:36:25 +00002977 if (newmask)
2978 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
2979 "pthread_sigmask: newmask",
2980 (Addr)newmask, sizeof(vki_ksigset_t));
2981 if (oldmask)
2982 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2983 "pthread_sigmask: oldmask",
2984 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00002985
sewardj018f7622002-05-15 21:13:39 +00002986 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002987
njn25e49d8e72002-09-23 09:36:25 +00002988 if (oldmask)
2989 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00002990
sewardj018f7622002-05-15 21:13:39 +00002991 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00002992 SET_EDX(tid, 0);
2993}
2994
2995
2996static
2997void do_sigwait ( ThreadId tid,
2998 vki_ksigset_t* set,
2999 Int* sig )
3000{
sewardj018f7622002-05-15 21:13:39 +00003001 vki_ksigset_t irrelevant_sigmask;
3002 Char msg_buf[100];
3003
sewardjb48e5002002-05-13 00:16:03 +00003004 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3005 VG_(sprintf)(msg_buf,
3006 "suspend due to sigwait(): set %p, sig %p",
3007 set, sig );
3008 print_pthread_event(tid, msg_buf);
3009 }
3010
3011 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003012 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003013
sewardj018f7622002-05-15 21:13:39 +00003014 /* Change SCSS */
3015 VG_(threads)[tid].sigs_waited_for = *set;
3016 VG_(threads)[tid].status = VgTs_WaitSIG;
3017
3018 VG_(block_all_host_signals)( &irrelevant_sigmask );
3019 VG_(handle_SCSS_change)( False /* lazy update */ );
3020}
3021
3022
3023static
3024void do_pthread_kill ( ThreadId tid, /* me */
3025 ThreadId thread, /* thread to signal */
3026 Int sig )
3027{
3028 Char msg_buf[100];
3029
3030 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3031 VG_(sprintf)(msg_buf,
3032 "pthread_kill thread %d, signo %d",
3033 thread, sig );
3034 print_pthread_event(tid, msg_buf);
3035 }
3036
3037 vg_assert(VG_(is_valid_tid)(tid)
3038 && VG_(threads)[tid].status == VgTs_Runnable);
3039
sewardj4dced352002-06-04 22:54:20 +00003040 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003041 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003042 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003043 SET_EDX(tid, -VKI_ESRCH);
3044 return;
3045 }
3046
3047 if (sig < 1 || sig > VKI_KNSIG) {
3048 SET_EDX(tid, -VKI_EINVAL);
3049 return;
3050 }
3051
3052 VG_(send_signal_to_thread)( thread, sig );
3053 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003054}
3055
3056
sewardj2cb00342002-06-28 01:46:26 +00003057/* -----------------------------------------------------------
3058 FORK HANDLERS.
3059 -------------------------------------------------------- */
3060
3061static
3062void do__set_fhstack_used ( ThreadId tid, Int n )
3063{
3064 Char msg_buf[100];
3065 if (VG_(clo_trace_sched)) {
3066 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3067 print_pthread_event(tid, msg_buf);
3068 }
3069
3070 vg_assert(VG_(is_valid_tid)(tid)
3071 && VG_(threads)[tid].status == VgTs_Runnable);
3072
3073 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3074 vg_fhstack_used = n;
3075 SET_EDX(tid, 0);
3076 } else {
3077 SET_EDX(tid, -1);
3078 }
3079}
3080
3081
3082static
3083void do__get_fhstack_used ( ThreadId tid )
3084{
3085 Int n;
3086 Char msg_buf[100];
3087 if (VG_(clo_trace_sched)) {
3088 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3089 print_pthread_event(tid, msg_buf);
3090 }
3091
3092 vg_assert(VG_(is_valid_tid)(tid)
3093 && VG_(threads)[tid].status == VgTs_Runnable);
3094
3095 n = vg_fhstack_used;
3096 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3097 SET_EDX(tid, n);
3098}
3099
3100static
3101void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3102{
3103 Char msg_buf[100];
3104 if (VG_(clo_trace_sched)) {
3105 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3106 print_pthread_event(tid, msg_buf);
3107 }
3108
3109 vg_assert(VG_(is_valid_tid)(tid)
3110 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003111 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3112 "pthread_atfork: prepare/parent/child",
3113 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003114
njn25e49d8e72002-09-23 09:36:25 +00003115 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003116 SET_EDX(tid, -1);
3117 return;
3118 }
3119
3120 vg_fhstack[n] = *fh;
3121 SET_EDX(tid, 0);
3122}
3123
3124
3125static
3126void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3127 ForkHandlerEntry* fh )
3128{
3129 Char msg_buf[100];
3130 if (VG_(clo_trace_sched)) {
3131 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3132 print_pthread_event(tid, msg_buf);
3133 }
3134
3135 vg_assert(VG_(is_valid_tid)(tid)
3136 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003137 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3138 "fork: prepare/parent/child",
3139 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003140
njn25e49d8e72002-09-23 09:36:25 +00003141 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003142 SET_EDX(tid, -1);
3143 return;
3144 }
3145
3146 *fh = vg_fhstack[n];
3147 SET_EDX(tid, 0);
3148
njn25e49d8e72002-09-23 09:36:25 +00003149 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003150}
3151
3152
sewardje663cb92002-04-12 10:26:32 +00003153/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003154 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003155 ------------------------------------------------------------------ */
3156
sewardj124ca2a2002-06-20 10:19:38 +00003157/* Do a client request for the thread tid. After the request, tid may
3158 or may not still be runnable; if not, the scheduler will have to
3159 choose a new thread to run.
3160*/
sewardje663cb92002-04-12 10:26:32 +00003161static
sewardj124ca2a2002-06-20 10:19:38 +00003162void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003163{
njn25e49d8e72002-09-23 09:36:25 +00003164# define RETURN_WITH(vvv) \
3165 { tst->m_edx = (vvv); \
3166 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003167 }
3168
3169 ThreadState* tst = &VG_(threads)[tid];
3170 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3171 UInt req_no = arg[0];
3172
3173 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003174 switch (req_no) {
3175
sewardj124ca2a2002-06-20 10:19:38 +00003176 case VG_USERREQ__MALLOC:
3177 RETURN_WITH(
3178 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3179 );
3180 break;
3181
3182 case VG_USERREQ__BUILTIN_NEW:
3183 RETURN_WITH(
3184 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3185 );
3186 break;
3187
3188 case VG_USERREQ__BUILTIN_VEC_NEW:
3189 RETURN_WITH(
3190 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3191 );
3192 break;
3193
3194 case VG_USERREQ__FREE:
3195 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3196 RETURN_WITH(0); /* irrelevant */
3197 break;
3198
3199 case VG_USERREQ__BUILTIN_DELETE:
3200 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3201 RETURN_WITH(0); /* irrelevant */
3202 break;
3203
3204 case VG_USERREQ__BUILTIN_VEC_DELETE:
3205 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3206 RETURN_WITH(0); /* irrelevant */
3207 break;
3208
3209 case VG_USERREQ__CALLOC:
3210 RETURN_WITH(
3211 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3212 );
3213 break;
3214
3215 case VG_USERREQ__REALLOC:
3216 RETURN_WITH(
3217 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3218 );
3219 break;
3220
3221 case VG_USERREQ__MEMALIGN:
3222 RETURN_WITH(
3223 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3224 );
3225 break;
3226
3227 case VG_USERREQ__PTHREAD_GET_THREADID:
3228 RETURN_WITH(tid);
3229 break;
3230
3231 case VG_USERREQ__RUNNING_ON_VALGRIND:
3232 RETURN_WITH(1);
3233 break;
3234
3235 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3236 RETURN_WITH(VG_(clo_trace_pthread_level));
3237 break;
3238
3239 case VG_USERREQ__READ_MILLISECOND_TIMER:
3240 RETURN_WITH(VG_(read_millisecond_timer)());
3241 break;
3242
3243 /* Some of these may make thread tid non-runnable, but the
3244 scheduler checks for that on return from this function. */
3245 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3246 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3247 break;
3248
3249 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3250 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3251 break;
3252
3253 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3254 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3255 break;
3256
3257 case VG_USERREQ__PTHREAD_GETSPECIFIC:
3258 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
3259 break;
3260
3261 case VG_USERREQ__SET_CANCELTYPE:
3262 do__set_canceltype ( tid, arg[1] );
3263 break;
3264
3265 case VG_USERREQ__CLEANUP_PUSH:
3266 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3267 break;
3268
3269 case VG_USERREQ__CLEANUP_POP:
3270 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3271 break;
3272
3273 case VG_USERREQ__TESTCANCEL:
3274 do__testcancel ( tid );
3275 break;
3276
3277 case VG_USERREQ__GET_N_SIGS_RETURNED:
3278 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3279 break;
3280
sewardje663cb92002-04-12 10:26:32 +00003281 case VG_USERREQ__PTHREAD_JOIN:
3282 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3283 break;
3284
sewardj3b5d8862002-04-20 13:53:23 +00003285 case VG_USERREQ__PTHREAD_COND_WAIT:
3286 do_pthread_cond_wait( tid,
3287 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003288 (pthread_mutex_t *)(arg[2]),
3289 0xFFFFFFFF /* no timeout */ );
3290 break;
3291
3292 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3293 do_pthread_cond_wait( tid,
3294 (pthread_cond_t *)(arg[1]),
3295 (pthread_mutex_t *)(arg[2]),
3296 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003297 break;
3298
3299 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3300 do_pthread_cond_signal_or_broadcast(
3301 tid,
3302 False, /* signal, not broadcast */
3303 (pthread_cond_t *)(arg[1]) );
3304 break;
3305
3306 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3307 do_pthread_cond_signal_or_broadcast(
3308 tid,
3309 True, /* broadcast, not signal */
3310 (pthread_cond_t *)(arg[1]) );
3311 break;
3312
sewardj5f07b662002-04-23 16:52:51 +00003313 case VG_USERREQ__PTHREAD_KEY_CREATE:
3314 do_pthread_key_create ( tid,
3315 (pthread_key_t*)(arg[1]),
3316 (void(*)(void*))(arg[2]) );
3317 break;
3318
3319 case VG_USERREQ__PTHREAD_KEY_DELETE:
3320 do_pthread_key_delete ( tid,
3321 (pthread_key_t)(arg[1]) );
3322 break;
3323
sewardj5f07b662002-04-23 16:52:51 +00003324 case VG_USERREQ__PTHREAD_SETSPECIFIC:
3325 do_pthread_setspecific ( tid,
3326 (pthread_key_t)(arg[1]),
3327 (void*)(arg[2]) );
3328 break;
3329
sewardjb48e5002002-05-13 00:16:03 +00003330 case VG_USERREQ__PTHREAD_SIGMASK:
3331 do_pthread_sigmask ( tid,
3332 arg[1],
3333 (vki_ksigset_t*)(arg[2]),
3334 (vki_ksigset_t*)(arg[3]) );
3335 break;
3336
3337 case VG_USERREQ__SIGWAIT:
3338 do_sigwait ( tid,
3339 (vki_ksigset_t*)(arg[1]),
3340 (Int*)(arg[2]) );
3341 break;
3342
sewardj018f7622002-05-15 21:13:39 +00003343 case VG_USERREQ__PTHREAD_KILL:
3344 do_pthread_kill ( tid, arg[1], arg[2] );
3345 break;
3346
sewardjff42d1d2002-05-22 13:17:31 +00003347 case VG_USERREQ__PTHREAD_YIELD:
3348 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003349 /* On return from do_client_request(), the scheduler will
3350 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003351 break;
sewardj018f7622002-05-15 21:13:39 +00003352
sewardj7989d0c2002-05-28 11:00:01 +00003353 case VG_USERREQ__SET_CANCELSTATE:
3354 do__set_cancelstate ( tid, arg[1] );
3355 break;
3356
sewardj7989d0c2002-05-28 11:00:01 +00003357 case VG_USERREQ__SET_OR_GET_DETACH:
3358 do__set_or_get_detach ( tid, arg[1], arg[2] );
3359 break;
3360
3361 case VG_USERREQ__SET_CANCELPEND:
3362 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3363 break;
3364
3365 case VG_USERREQ__WAIT_JOINER:
3366 do__wait_joiner ( tid, (void*)arg[1] );
3367 break;
3368
3369 case VG_USERREQ__QUIT:
3370 do__quit ( tid );
3371 break;
3372
3373 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3374 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3375 (void*)arg[2] );
3376 break;
3377
sewardj870497a2002-05-29 01:06:47 +00003378 case VG_USERREQ__GET_KEY_D_AND_S:
3379 do__get_key_destr_and_spec ( tid,
3380 (pthread_key_t)arg[1],
3381 (CleanupEntry*)arg[2] );
3382 break;
3383
sewardjef037c72002-05-30 00:40:03 +00003384 case VG_USERREQ__NUKE_OTHER_THREADS:
3385 VG_(nuke_all_threads_except) ( tid );
3386 SET_EDX(tid, 0);
3387 break;
3388
sewardj4dced352002-06-04 22:54:20 +00003389 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003390 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003391 SET_EDX(tid, 0);
3392 break;
3393
sewardj2cb00342002-06-28 01:46:26 +00003394 case VG_USERREQ__SET_FHSTACK_USED:
3395 do__set_fhstack_used( tid, (Int)(arg[1]) );
3396 break;
3397
3398 case VG_USERREQ__GET_FHSTACK_USED:
3399 do__get_fhstack_used( tid );
3400 break;
3401
3402 case VG_USERREQ__SET_FHSTACK_ENTRY:
3403 do__set_fhstack_entry( tid, (Int)(arg[1]),
3404 (ForkHandlerEntry*)(arg[2]) );
3405 break;
3406
3407 case VG_USERREQ__GET_FHSTACK_ENTRY:
3408 do__get_fhstack_entry( tid, (Int)(arg[1]),
3409 (ForkHandlerEntry*)(arg[2]) );
3410 break;
3411
sewardj77e466c2002-04-14 02:29:29 +00003412 case VG_USERREQ__SIGNAL_RETURNS:
3413 handle_signal_return(tid);
3414 break;
sewardj54cacf02002-04-12 23:24:59 +00003415
njn25e49d8e72002-09-23 09:36:25 +00003416 /* Requests from the client program */
3417
3418 case VG_USERREQ__DISCARD_TRANSLATIONS:
3419 if (VG_(clo_verbosity) > 2)
3420 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3421 " addr %p, len %d\n",
3422 (void*)arg[1], arg[2] );
3423
3424 VG_(invalidate_translations)( arg[1], arg[2] );
3425
3426 SET_EDX( tid, 0 ); /* return value is meaningless */
3427 break;
3428
sewardje663cb92002-04-12 10:26:32 +00003429 default:
njn25e49d8e72002-09-23 09:36:25 +00003430 if (VG_(needs).client_requests) {
3431 if (VG_(clo_verbosity) > 2)
3432 VG_(printf)("client request: code %d, addr %p, len %d\n",
3433 arg[0], (void*)arg[1], arg[2] );
3434
3435 SET_EDX(tid,
3436 SK_(handle_client_request) ( &VG_(threads)[tid], arg )
3437 );
3438 } else {
3439 VG_(printf)("\nError:\n"
3440 " unhandled client request: 0x%x. Perhaps\n"
3441 " VG_(needs).client_requests should be set?\n",
3442 arg[0]);
3443 VG_(panic)("do_client_request: unknown request");
3444 /*NOTREACHED*/
3445 }
sewardje663cb92002-04-12 10:26:32 +00003446 break;
3447 }
sewardj124ca2a2002-06-20 10:19:38 +00003448
3449# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003450}
3451
3452
sewardj6072c362002-04-19 14:40:57 +00003453/* ---------------------------------------------------------------------
3454 Sanity checking.
3455 ------------------------------------------------------------------ */
3456
3457/* Internal consistency checks on the sched/pthread structures. */
3458static
3459void scheduler_sanity ( void )
3460{
sewardj3b5d8862002-04-20 13:53:23 +00003461 pthread_mutex_t* mx;
3462 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003463 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003464
sewardj6072c362002-04-19 14:40:57 +00003465 /* VG_(printf)("scheduler_sanity\n"); */
3466 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003467 mx = VG_(threads)[i].associated_mx;
3468 cv = VG_(threads)[i].associated_cv;
3469 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003470 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3471 it's actually held by someone, since otherwise this thread
3472 is deadlocked, (4) the mutex's owner is not us, since
3473 otherwise this thread is also deadlocked. The logic in
3474 do_pthread_mutex_lock rejects attempts by a thread to lock
3475 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003476
sewardjbf290b92002-05-01 02:28:01 +00003477 (2) has been seen to fail sometimes. I don't know why.
3478 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003479 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003480 /* 1 */ vg_assert(mx != NULL);
3481 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003482 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003483 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003484 } else
sewardj018f7622002-05-15 21:13:39 +00003485 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003486 vg_assert(cv != NULL);
3487 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003488 } else {
sewardj05553872002-04-20 20:53:17 +00003489 /* Unfortunately these don't hold true when a sighandler is
3490 running. To be fixed. */
3491 /* vg_assert(cv == NULL); */
3492 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003493 }
sewardjbf290b92002-05-01 02:28:01 +00003494
sewardj018f7622002-05-15 21:13:39 +00003495 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003496 Int
sewardj018f7622002-05-15 21:13:39 +00003497 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3498 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003499 if (i > 1 /* not the root thread */
3500 && stack_used
3501 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3502 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003503 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003504 "thread %d: stack used %d, available %d",
3505 i, stack_used, VG_PTHREAD_STACK_MIN );
3506 VG_(message)(Vg_UserMsg,
3507 "Terminating Valgrind. If thread(s) "
3508 "really need more stack, increase");
3509 VG_(message)(Vg_UserMsg,
3510 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3511 VG_(exit)(1);
3512 }
sewardjb48e5002002-05-13 00:16:03 +00003513
sewardj018f7622002-05-15 21:13:39 +00003514 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003515 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003516 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003517 } else {
3518 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003519 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003520 }
3521
sewardjbf290b92002-05-01 02:28:01 +00003522 }
sewardj6072c362002-04-19 14:40:57 +00003523 }
sewardj5f07b662002-04-23 16:52:51 +00003524
3525 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3526 if (!vg_thread_keys[i].inuse)
3527 vg_assert(vg_thread_keys[i].destructor == NULL);
3528 }
sewardj6072c362002-04-19 14:40:57 +00003529}
3530
3531
sewardje663cb92002-04-12 10:26:32 +00003532/*--------------------------------------------------------------------*/
3533/*--- end vg_scheduler.c ---*/
3534/*--------------------------------------------------------------------*/