blob: d50fe93e0deeb22f083acbff6d997125a9be2379 [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
28 The GNU General Public License is contained in the file LICENSE.
29*/
30
31#include "vg_include.h"
32#include "vg_constants.h"
sewardje663cb92002-04-12 10:26:32 +000033#include "valgrind.h" /* for VG_USERREQ__MAKE_NOACCESS and
34 VG_USERREQ__DO_LEAK_CHECK */
35
sewardj77e466c2002-04-14 02:29:29 +000036/* BORKAGE/ISSUES as of 14 Apr 02
sewardje663cb92002-04-12 10:26:32 +000037
sewardj77e466c2002-04-14 02:29:29 +000038Note! This pthreads implementation is so poor as to not be
39suitable for use by anyone at all!
sewardje663cb92002-04-12 10:26:32 +000040
sewardj77e466c2002-04-14 02:29:29 +000041- Currently, when a signal is run, just the ThreadStatus.status fields
42 are saved in the signal frame, along with the CPU state. Question:
43 should I also save and restore:
44 ThreadStatus.joiner
45 ThreadStatus.waited_on_mid
46 ThreadStatus.awaken_at
47 ThreadStatus.retval
48 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000049
sewardj77e466c2002-04-14 02:29:29 +000050- Signals interrupting read/write and nanosleep: SA_RESTART settings.
51 Read/write correctly return with EINTR when SA_RESTART isn't
52 specified and they are interrupted by a signal. nanosleep just
53 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000054
sewardj75fe1892002-04-14 02:46:33 +000055- Read/write syscall starts: don't crap out when the initial
56 nonblocking read/write returns an error.
sewardj8937c812002-04-12 20:12:20 +000057
sewardj9a199dc2002-04-14 13:01:38 +000058- Get rid of restrictions re use of sigaltstack; they are no longer
59 needed.
60
sewardj6072c362002-04-19 14:40:57 +000061- Fix signals properly, so that each thread has its own blocking mask.
62 Currently this isn't done, and (worse?) signals are delivered to
63 Thread 1 (the root thread) regardless.
64
65 So, what's the deal with signals and mutexes? If a thread is
66 blocked on a mutex, or for a condition variable for that matter, can
67 signals still be delivered to it? This has serious consequences --
68 deadlocks, etc.
69
sewardje462e202002-04-13 04:09:07 +000070*/
sewardje663cb92002-04-12 10:26:32 +000071
72
73/* ---------------------------------------------------------------------
74 Types and globals for the scheduler.
75 ------------------------------------------------------------------ */
76
77/* type ThreadId is defined in vg_include.h. */
78
79/* struct ThreadState is defined in vg_include.h. */
80
sewardj6072c362002-04-19 14:40:57 +000081/* Private globals. A statically allocated array of threads. NOTE:
82 [0] is never used, to simplify the simulation of initialisers for
83 LinuxThreads. */
sewardje663cb92002-04-12 10:26:32 +000084static ThreadState vg_threads[VG_N_THREADS];
85
sewardj1e8cdc92002-04-18 11:37:52 +000086/* The tid of the thread currently in VG_(baseBlock). */
87static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
88
sewardje663cb92002-04-12 10:26:32 +000089
90/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
91jmp_buf VG_(scheduler_jmpbuf);
92/* ... and if so, here's the signal which caused it to do so. */
93Int VG_(longjmpd_on_signal);
94
95
96/* Machinery to keep track of which threads are waiting on which
97 fds. */
98typedef
99 struct {
100 /* The thread which made the request. */
101 ThreadId tid;
102
103 /* The next two fields describe the request. */
104 /* File descriptor waited for. -1 means this slot is not in use */
105 Int fd;
106 /* The syscall number the fd is used in. */
107 Int syscall_no;
108
109 /* False => still waiting for select to tell us the fd is ready
110 to go. True => the fd is ready, but the results have not yet
111 been delivered back to the calling thread. Once the latter
112 happens, this entire record is marked as no longer in use, by
113 making the fd field be -1. */
114 Bool ready;
115 }
116 VgWaitedOnFd;
117
118static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
119
120
sewardj5f07b662002-04-23 16:52:51 +0000121/* Keeping track of keys. */
122typedef
123 struct {
124 /* Has this key been allocated ? */
125 Bool inuse;
126 /* If .inuse==True, records the address of the associated
127 destructor, or NULL if none. */
128 void (*destructor)(void*);
129 }
130 ThreadKeyState;
131
132/* And our array of thread keys. */
133static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
134
135typedef UInt ThreadKey;
136
137
sewardje663cb92002-04-12 10:26:32 +0000138/* Forwards */
sewardj5f07b662002-04-23 16:52:51 +0000139static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
140
sewardje663cb92002-04-12 10:26:32 +0000141static void do_nontrivial_clientreq ( ThreadId tid );
142
sewardj6072c362002-04-19 14:40:57 +0000143static void scheduler_sanity ( void );
144
sewardjd7fd4d22002-04-24 01:57:27 +0000145static void do_pthread_mutex_unlock ( ThreadId,
sewardj8ccc2be2002-05-10 20:26:37 +0000146 void* /* pthread_mutex_t* */ );
sewardjd7fd4d22002-04-24 01:57:27 +0000147static void do_pthread_mutex_lock ( ThreadId, Bool,
sewardj8ccc2be2002-05-10 20:26:37 +0000148 void* /* pthread_mutex_t* */ );
sewardjd7fd4d22002-04-24 01:57:27 +0000149
sewardj51c0aaf2002-04-25 01:32:10 +0000150static void do_pthread_getspecific ( ThreadId,
151 UInt /* pthread_key_t */ );
152
sewardje663cb92002-04-12 10:26:32 +0000153
154/* ---------------------------------------------------------------------
155 Helper functions for the scheduler.
156 ------------------------------------------------------------------ */
157
sewardjb48e5002002-05-13 00:16:03 +0000158__inline__
159Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000160{
161 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000162 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000163 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000164 return True;
165}
166
167
sewardj1e8cdc92002-04-18 11:37:52 +0000168/* For constructing error messages only: try and identify a thread
169 whose stack this address currently falls within, or return
170 VG_INVALID_THREADID if it doesn't. A small complication is dealing
171 with any currently VG_(baseBlock)-resident thread.
172*/
173ThreadId VG_(identify_stack_addr)( Addr a )
174{
175 ThreadId tid, tid_to_skip;
176
177 tid_to_skip = VG_INVALID_THREADID;
178
179 /* First check to see if there's a currently-loaded thread in
180 VG_(baseBlock). */
181 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
182 tid = vg_tid_currently_in_baseBlock;
183 if (VG_(baseBlock)[VGOFF_(m_esp)] <= a
184 && a <= vg_threads[tid].stack_highest_word)
185 return tid;
186 else
187 tid_to_skip = tid;
188 }
189
sewardj6072c362002-04-19 14:40:57 +0000190 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj1e8cdc92002-04-18 11:37:52 +0000191 if (vg_threads[tid].status == VgTs_Empty) continue;
192 if (tid == tid_to_skip) continue;
193 if (vg_threads[tid].m_esp <= a
194 && a <= vg_threads[tid].stack_highest_word)
195 return tid;
196 }
197 return VG_INVALID_THREADID;
198}
199
200
sewardj15a43e12002-04-17 19:35:12 +0000201/* Print the scheduler status. */
202void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000203{
204 Int i;
205 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000206 for (i = 1; i < VG_N_THREADS; i++) {
sewardje663cb92002-04-12 10:26:32 +0000207 if (vg_threads[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000208 VG_(printf)("\nThread %d: status = ", i);
sewardje663cb92002-04-12 10:26:32 +0000209 switch (vg_threads[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000210 case VgTs_Runnable: VG_(printf)("Runnable"); break;
211 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
212 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner(%d)",
sewardje663cb92002-04-12 10:26:32 +0000213 vg_threads[i].joiner); break;
sewardj6072c362002-04-19 14:40:57 +0000214 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee"); break;
215 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
216 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000217 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000218 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000219 default: VG_(printf)("???"); break;
220 }
sewardj3b5d8862002-04-20 13:53:23 +0000221 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
222 vg_threads[i].associated_mx,
223 vg_threads[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000224 VG_(pp_ExeContext)(
225 VG_(get_ExeContext)( False, vg_threads[i].m_eip,
226 vg_threads[i].m_ebp ));
sewardje663cb92002-04-12 10:26:32 +0000227 }
228 VG_(printf)("\n");
229}
230
231static
232void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no )
233{
234 Int i;
235
236 vg_assert(fd != -1); /* avoid total chaos */
237
238 for (i = 0; i < VG_N_WAITING_FDS; i++)
239 if (vg_waiting_fds[i].fd == -1)
240 break;
241
242 if (i == VG_N_WAITING_FDS)
243 VG_(panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
244 /*
245 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
246 tid, fd, i);
247 */
248 vg_waiting_fds[i].fd = fd;
249 vg_waiting_fds[i].tid = tid;
250 vg_waiting_fds[i].ready = False;
251 vg_waiting_fds[i].syscall_no = syscall_no;
252}
253
254
255
256static
257void print_sched_event ( ThreadId tid, Char* what )
258{
sewardj45b4b372002-04-16 22:50:32 +0000259 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000260}
261
262
263static
264void print_pthread_event ( ThreadId tid, Char* what )
265{
266 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000267}
268
269
270static
271Char* name_of_sched_event ( UInt event )
272{
273 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000274 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
275 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
276 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
277 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
278 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
279 default: return "??UNKNOWN??";
280 }
281}
282
283
284/* Create a translation of the client basic block beginning at
285 orig_addr, and add it to the translation cache & translation table.
286 This probably doesn't really belong here, but, hey ...
287*/
sewardj1e8cdc92002-04-18 11:37:52 +0000288static
289void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000290{
291 Addr trans_addr;
292 TTEntry tte;
293 Int orig_size, trans_size;
294 /* Ensure there is space to hold a translation. */
295 VG_(maybe_do_lru_pass)();
sewardj1e8cdc92002-04-18 11:37:52 +0000296 VG_(translate)( &vg_threads[tid],
297 orig_addr, &orig_size, &trans_addr, &trans_size );
sewardje663cb92002-04-12 10:26:32 +0000298 /* Copy data at trans_addr into the translation cache.
299 Returned pointer is to the code, not to the 4-byte
300 header. */
301 /* Since the .orig_size and .trans_size fields are
302 UShort, be paranoid. */
303 vg_assert(orig_size > 0 && orig_size < 65536);
304 vg_assert(trans_size > 0 && trans_size < 65536);
305 tte.orig_size = orig_size;
306 tte.orig_addr = orig_addr;
307 tte.trans_size = trans_size;
308 tte.trans_addr = VG_(copy_to_transcache)
309 ( trans_addr, trans_size );
310 tte.mru_epoch = VG_(current_epoch);
311 /* Free the intermediary -- was allocated by VG_(emit_code). */
312 VG_(jitfree)( (void*)trans_addr );
313 /* Add to trans tab and set back pointer. */
314 VG_(add_to_trans_tab) ( &tte );
315 /* Update stats. */
316 VG_(this_epoch_in_count) ++;
317 VG_(this_epoch_in_osize) += orig_size;
318 VG_(this_epoch_in_tsize) += trans_size;
319 VG_(overall_in_count) ++;
320 VG_(overall_in_osize) += orig_size;
321 VG_(overall_in_tsize) += trans_size;
322 /* Record translated area for SMC detection. */
323 VG_(smc_mark_original) ( orig_addr, orig_size );
324}
325
326
327/* Allocate a completely empty ThreadState record. */
328static
329ThreadId vg_alloc_ThreadState ( void )
330{
331 Int i;
sewardj6072c362002-04-19 14:40:57 +0000332 for (i = 1; i < VG_N_THREADS; i++) {
sewardje663cb92002-04-12 10:26:32 +0000333 if (vg_threads[i].status == VgTs_Empty)
334 return i;
335 }
336 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
337 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
338 VG_(panic)("VG_N_THREADS is too low");
339 /*NOTREACHED*/
340}
341
342
sewardjb48e5002002-05-13 00:16:03 +0000343ThreadState* VG_(get_thread_state_UNCHECKED) ( ThreadId tid )
344{
345 vg_assert(VG_(is_valid_tid)(tid));
346 return & vg_threads[tid];
347}
348
349
sewardje663cb92002-04-12 10:26:32 +0000350ThreadState* VG_(get_thread_state) ( ThreadId tid )
351{
sewardjb48e5002002-05-13 00:16:03 +0000352 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +0000353 vg_assert(vg_threads[tid].status != VgTs_Empty);
354 return & vg_threads[tid];
355}
356
357
sewardj1e8cdc92002-04-18 11:37:52 +0000358ThreadState* VG_(get_current_thread_state) ( void )
359{
360 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
sewardj6072c362002-04-19 14:40:57 +0000361 return VG_(get_thread_state) ( vg_tid_currently_in_baseBlock );
sewardj1e8cdc92002-04-18 11:37:52 +0000362}
363
364
365ThreadId VG_(get_current_tid) ( void )
366{
367 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
368 return vg_tid_currently_in_baseBlock;
369}
370
371
sewardje663cb92002-04-12 10:26:32 +0000372/* Copy the saved state of a thread into VG_(baseBlock), ready for it
373 to be run. */
374__inline__
375void VG_(load_thread_state) ( ThreadId tid )
376{
377 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000378 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
379
sewardje663cb92002-04-12 10:26:32 +0000380 VG_(baseBlock)[VGOFF_(m_eax)] = vg_threads[tid].m_eax;
381 VG_(baseBlock)[VGOFF_(m_ebx)] = vg_threads[tid].m_ebx;
382 VG_(baseBlock)[VGOFF_(m_ecx)] = vg_threads[tid].m_ecx;
383 VG_(baseBlock)[VGOFF_(m_edx)] = vg_threads[tid].m_edx;
384 VG_(baseBlock)[VGOFF_(m_esi)] = vg_threads[tid].m_esi;
385 VG_(baseBlock)[VGOFF_(m_edi)] = vg_threads[tid].m_edi;
386 VG_(baseBlock)[VGOFF_(m_ebp)] = vg_threads[tid].m_ebp;
387 VG_(baseBlock)[VGOFF_(m_esp)] = vg_threads[tid].m_esp;
388 VG_(baseBlock)[VGOFF_(m_eflags)] = vg_threads[tid].m_eflags;
389 VG_(baseBlock)[VGOFF_(m_eip)] = vg_threads[tid].m_eip;
390
391 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
392 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = vg_threads[tid].m_fpu[i];
393
394 VG_(baseBlock)[VGOFF_(sh_eax)] = vg_threads[tid].sh_eax;
395 VG_(baseBlock)[VGOFF_(sh_ebx)] = vg_threads[tid].sh_ebx;
396 VG_(baseBlock)[VGOFF_(sh_ecx)] = vg_threads[tid].sh_ecx;
397 VG_(baseBlock)[VGOFF_(sh_edx)] = vg_threads[tid].sh_edx;
398 VG_(baseBlock)[VGOFF_(sh_esi)] = vg_threads[tid].sh_esi;
399 VG_(baseBlock)[VGOFF_(sh_edi)] = vg_threads[tid].sh_edi;
400 VG_(baseBlock)[VGOFF_(sh_ebp)] = vg_threads[tid].sh_ebp;
401 VG_(baseBlock)[VGOFF_(sh_esp)] = vg_threads[tid].sh_esp;
402 VG_(baseBlock)[VGOFF_(sh_eflags)] = vg_threads[tid].sh_eflags;
sewardj1e8cdc92002-04-18 11:37:52 +0000403
404 vg_tid_currently_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000405}
406
407
408/* Copy the state of a thread from VG_(baseBlock), presumably after it
409 has been descheduled. For sanity-check purposes, fill the vacated
410 VG_(baseBlock) with garbage so as to make the system more likely to
411 fail quickly if we erroneously continue to poke around inside
412 VG_(baseBlock) without first doing a load_thread_state().
413*/
414__inline__
415void VG_(save_thread_state) ( ThreadId tid )
416{
417 Int i;
418 const UInt junk = 0xDEADBEEF;
419
sewardj1e8cdc92002-04-18 11:37:52 +0000420 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
421
sewardje663cb92002-04-12 10:26:32 +0000422 vg_threads[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
423 vg_threads[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
424 vg_threads[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
425 vg_threads[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
426 vg_threads[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
427 vg_threads[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
428 vg_threads[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
429 vg_threads[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
430 vg_threads[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
431 vg_threads[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
432
433 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
434 vg_threads[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
435
436 vg_threads[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
437 vg_threads[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
438 vg_threads[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
439 vg_threads[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
440 vg_threads[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
441 vg_threads[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
442 vg_threads[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
443 vg_threads[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
444 vg_threads[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
445
446 /* Fill it up with junk. */
447 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
448 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
449 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
450 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
451 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
452 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
453 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
454 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
455 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
456 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
457
458 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
459 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000460
461 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000462}
463
464
465/* Run the thread tid for a while, and return a VG_TRC_* value to the
466 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000467static
sewardje663cb92002-04-12 10:26:32 +0000468UInt run_thread_for_a_while ( ThreadId tid )
469{
sewardj7ccc5c22002-04-24 21:39:11 +0000470 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000471 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000472 vg_assert(vg_threads[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000473 vg_assert(VG_(bbs_to_go) > 0);
474
sewardj671ff542002-05-07 09:25:30 +0000475 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000476 VG_(load_thread_state) ( tid );
477 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
478 /* try this ... */
479 trc = VG_(run_innerloop)();
480 /* We get here if the client didn't take a fault. */
481 } else {
482 /* We get here if the client took a fault, which caused our
483 signal handler to longjmp. */
484 vg_assert(trc == 0);
485 trc = VG_TRC_UNRESUMABLE_SIGNAL;
486 }
487 VG_(save_thread_state) ( tid );
sewardj671ff542002-05-07 09:25:30 +0000488 VGP_POPCC;
sewardje663cb92002-04-12 10:26:32 +0000489 return trc;
490}
491
492
493/* Increment the LRU epoch counter. */
494static
495void increment_epoch ( void )
496{
497 VG_(current_epoch)++;
498 if (VG_(clo_verbosity) > 2) {
499 UInt tt_used, tc_used;
500 VG_(get_tt_tc_used) ( &tt_used, &tc_used );
501 VG_(message)(Vg_UserMsg,
502 "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
503 VG_(bbs_done),
504 VG_(this_epoch_in_count),
505 VG_(this_epoch_in_osize),
506 VG_(this_epoch_in_tsize),
507 VG_(this_epoch_out_count),
508 VG_(this_epoch_out_osize),
509 VG_(this_epoch_out_tsize),
510 tt_used, tc_used
511 );
512 }
513 VG_(this_epoch_in_count) = 0;
514 VG_(this_epoch_in_osize) = 0;
515 VG_(this_epoch_in_tsize) = 0;
516 VG_(this_epoch_out_count) = 0;
517 VG_(this_epoch_out_osize) = 0;
518 VG_(this_epoch_out_tsize) = 0;
519}
520
521
522/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000523 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000524 caller takes care to park the client's state is parked in
525 VG_(baseBlock).
526*/
527void VG_(scheduler_init) ( void )
528{
529 Int i;
530 Addr startup_esp;
531 ThreadId tid_main;
532
533 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000534
535 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
536 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)) {
537 /* Jolly good! */
538 } else {
539 VG_(printf)("%%esp at startup = %p is not near %p or %p; aborting\n",
540 (void*)startup_esp,
541 (void*)VG_STARTUP_STACK_BASE_1,
542 (void*)VG_STARTUP_STACK_BASE_2 );
sewardje663cb92002-04-12 10:26:32 +0000543 VG_(panic)("unexpected %esp at startup");
544 }
545
sewardj6072c362002-04-19 14:40:57 +0000546 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
547 vg_threads[i].status = VgTs_Empty;
sewardje663cb92002-04-12 10:26:32 +0000548 vg_threads[i].stack_size = 0;
549 vg_threads[i].stack_base = (Addr)NULL;
sewardj1e8cdc92002-04-18 11:37:52 +0000550 vg_threads[i].tid = i;
sewardjb48e5002002-05-13 00:16:03 +0000551 VG_(ksigemptyset)(&vg_threads[i].sig_mask);
552 VG_(ksigemptyset)(&vg_threads[i].sigs_waited_for);
sewardje663cb92002-04-12 10:26:32 +0000553 }
554
555 for (i = 0; i < VG_N_WAITING_FDS; i++)
556 vg_waiting_fds[i].fd = -1; /* not in use */
557
sewardj5f07b662002-04-23 16:52:51 +0000558 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
559 vg_thread_keys[i].inuse = False;
560 vg_thread_keys[i].destructor = NULL;
561 }
562
sewardje663cb92002-04-12 10:26:32 +0000563 /* Assert this is thread zero, which has certain magic
564 properties. */
565 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000566 vg_assert(tid_main == 1);
sewardje663cb92002-04-12 10:26:32 +0000567
sewardj3b5d8862002-04-20 13:53:23 +0000568 vg_threads[tid_main].status = VgTs_Runnable;
569 vg_threads[tid_main].joiner = VG_INVALID_THREADID;
570 vg_threads[tid_main].associated_mx = NULL;
571 vg_threads[tid_main].associated_cv = NULL;
572 vg_threads[tid_main].retval = NULL; /* not important */
sewardj5f07b662002-04-23 16:52:51 +0000573 for (i = 0; i < VG_N_THREAD_KEYS; i++)
574 vg_threads[tid_main].specifics[i] = NULL;
sewardje663cb92002-04-12 10:26:32 +0000575
576 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000577 vg_tid_currently_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000578 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000579
sewardjbf290b92002-05-01 02:28:01 +0000580 vg_threads[tid_main].stack_highest_word
581 = vg_threads[tid_main].m_esp /* -4 ??? */;
582
sewardj1e8cdc92002-04-18 11:37:52 +0000583 /* So now ... */
584 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardje663cb92002-04-12 10:26:32 +0000585}
586
587
588/* What if fd isn't a valid fd? */
589static
590void set_fd_nonblocking ( Int fd )
591{
592 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
593 vg_assert(!VG_(is_kerror)(res));
594 res |= VKI_O_NONBLOCK;
595 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
596 vg_assert(!VG_(is_kerror)(res));
597}
598
599static
600void set_fd_blocking ( Int fd )
601{
602 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
603 vg_assert(!VG_(is_kerror)(res));
604 res &= ~VKI_O_NONBLOCK;
605 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
606 vg_assert(!VG_(is_kerror)(res));
607}
608
609static
610Bool fd_is_blockful ( Int fd )
611{
612 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
613 vg_assert(!VG_(is_kerror)(res));
614 return (res & VKI_O_NONBLOCK) ? False : True;
615}
616
617
618
sewardjd7fd4d22002-04-24 01:57:27 +0000619/* Possibly do a for tid. Return values are:
sewardje663cb92002-04-12 10:26:32 +0000620
sewardjd7fd4d22002-04-24 01:57:27 +0000621 True = request done. Thread may or may not be still runnable;
622 caller must check. If it is still runnable, the result will be in
623 the thread's %EDX as expected.
624
625 False = request not done. A more capable but slower mechanism will
626 deal with it.
sewardje663cb92002-04-12 10:26:32 +0000627*/
sewardjd7fd4d22002-04-24 01:57:27 +0000628static
sewardje663cb92002-04-12 10:26:32 +0000629Bool maybe_do_trivial_clientreq ( ThreadId tid )
630{
631# define SIMPLE_RETURN(vvv) \
sewardj8c824512002-04-14 04:16:48 +0000632 { tst->m_edx = (vvv); \
sewardjc3bd5f52002-05-01 03:24:23 +0000633 tst->sh_edx = VGM_WORD_VALID; \
sewardje663cb92002-04-12 10:26:32 +0000634 return True; \
635 }
636
sewardj8c824512002-04-14 04:16:48 +0000637 ThreadState* tst = &vg_threads[tid];
638 UInt* arg = (UInt*)(tst->m_eax);
639 UInt req_no = arg[0];
640
sewardj8ccc2be2002-05-10 20:26:37 +0000641 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +0000642 switch (req_no) {
643 case VG_USERREQ__MALLOC:
644 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000645 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
sewardje663cb92002-04-12 10:26:32 +0000646 );
647 case VG_USERREQ__BUILTIN_NEW:
648 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000649 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
sewardje663cb92002-04-12 10:26:32 +0000650 );
651 case VG_USERREQ__BUILTIN_VEC_NEW:
652 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000653 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
sewardje663cb92002-04-12 10:26:32 +0000654 );
655 case VG_USERREQ__FREE:
sewardj8c824512002-04-14 04:16:48 +0000656 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
sewardje663cb92002-04-12 10:26:32 +0000657 SIMPLE_RETURN(0); /* irrelevant */
658 case VG_USERREQ__BUILTIN_DELETE:
sewardj8c824512002-04-14 04:16:48 +0000659 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
sewardje663cb92002-04-12 10:26:32 +0000660 SIMPLE_RETURN(0); /* irrelevant */
661 case VG_USERREQ__BUILTIN_VEC_DELETE:
sewardj8c824512002-04-14 04:16:48 +0000662 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
sewardje663cb92002-04-12 10:26:32 +0000663 SIMPLE_RETURN(0); /* irrelevant */
664 case VG_USERREQ__CALLOC:
665 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000666 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000667 );
668 case VG_USERREQ__REALLOC:
669 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000670 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000671 );
672 case VG_USERREQ__MEMALIGN:
673 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000674 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000675 );
sewardj9650c992002-04-16 03:44:31 +0000676
sewardj5f07b662002-04-23 16:52:51 +0000677 /* These are heavily used -- or at least we want them to be
678 cheap. */
sewardj9650c992002-04-16 03:44:31 +0000679 case VG_USERREQ__PTHREAD_GET_THREADID:
680 SIMPLE_RETURN(tid);
681 case VG_USERREQ__RUNNING_ON_VALGRIND:
682 SIMPLE_RETURN(1);
sewardj45b4b372002-04-16 22:50:32 +0000683 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
684 SIMPLE_RETURN(VG_(clo_trace_pthread_level));
sewardj5f07b662002-04-23 16:52:51 +0000685 case VG_USERREQ__READ_MILLISECOND_TIMER:
686 SIMPLE_RETURN(VG_(read_millisecond_timer)());
sewardj9650c992002-04-16 03:44:31 +0000687
sewardjd7fd4d22002-04-24 01:57:27 +0000688 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
689 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
690 return True;
691
692 /* This may make thread tid non-runnable, but the scheduler
693 checks for that on return from this function. */
694 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
695 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
696 return True;
697
sewardj14e03422002-04-24 19:51:31 +0000698 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
699 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
700 return True;
701
sewardj51c0aaf2002-04-25 01:32:10 +0000702 case VG_USERREQ__PTHREAD_GETSPECIFIC:
703 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
704 return True;
705
sewardje663cb92002-04-12 10:26:32 +0000706 default:
707 /* Too hard; wimp out. */
708 return False;
709 }
710# undef SIMPLE_RETURN
711}
712
713
sewardj6072c362002-04-19 14:40:57 +0000714/* vthread tid is returning from a signal handler; modify its
715 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000716
717/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
718 for read or write, has been interrupted by a signal. Find and
719 clear the relevant vg_waiting_fd[] entry. Most of the code in this
720 procedure is total paranoia, if you look closely. */
721static
722void cleanup_waiting_fd_table ( ThreadId tid )
723{
724 Int i, waiters;
725
sewardjb48e5002002-05-13 00:16:03 +0000726 vg_assert(VG_(is_valid_tid)(tid));
sewardj1ffa8da2002-04-26 22:47:57 +0000727 vg_assert(vg_threads[tid].status == VgTs_WaitFD);
728 vg_assert(vg_threads[tid].m_eax == __NR_read
729 || vg_threads[tid].m_eax == __NR_write);
730
731 /* Excessively paranoidly ... find the fd this op was waiting
732 for, and mark it as not being waited on. */
733 waiters = 0;
734 for (i = 0; i < VG_N_WAITING_FDS; i++) {
735 if (vg_waiting_fds[i].tid == tid) {
736 waiters++;
737 vg_assert(vg_waiting_fds[i].syscall_no == vg_threads[tid].m_eax);
738 }
739 }
740 vg_assert(waiters == 1);
741 for (i = 0; i < VG_N_WAITING_FDS; i++)
742 if (vg_waiting_fds[i].tid == tid)
743 break;
744 vg_assert(i < VG_N_WAITING_FDS);
745 vg_assert(vg_waiting_fds[i].fd != -1);
746 vg_waiting_fds[i].fd = -1; /* not in use */
747}
748
749
sewardj6072c362002-04-19 14:40:57 +0000750static
751void handle_signal_return ( ThreadId tid )
752{
753 Char msg_buf[100];
754 Bool restart_blocked_syscalls;
755
sewardjb48e5002002-05-13 00:16:03 +0000756 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000757
758 restart_blocked_syscalls = VG_(signal_returns)(tid);
759
760 if (restart_blocked_syscalls)
761 /* Easy; we don't have to do anything. */
762 return;
763
sewardj1ffa8da2002-04-26 22:47:57 +0000764 if (vg_threads[tid].status == VgTs_WaitFD
765 && (vg_threads[tid].m_eax == __NR_read
766 || vg_threads[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000767 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000768 cleanup_waiting_fd_table(tid);
sewardj6072c362002-04-19 14:40:57 +0000769 vg_threads[tid].m_eax = -VKI_EINTR;
770 vg_threads[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000771
sewardj6072c362002-04-19 14:40:57 +0000772 if (VG_(clo_trace_sched)) {
773 VG_(sprintf)(msg_buf,
774 "read() / write() interrupted by signal; return EINTR" );
775 print_sched_event(tid, msg_buf);
776 }
777 return;
778 }
779
sewardj1ffa8da2002-04-26 22:47:57 +0000780 if (vg_threads[tid].status == VgTs_WaitFD
781 && vg_threads[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000782 /* We interrupted a nanosleep(). The right thing to do is to
783 write the unused time to nanosleep's second param and return
784 EINTR, but I'm too lazy for that. */
785 return;
786 }
787
sewardj1ffa8da2002-04-26 22:47:57 +0000788 if (vg_threads[tid].status == VgTs_WaitFD) {
789 VG_(panic)("handle_signal_return: unknown interrupted syscall");
790 }
791
sewardj6072c362002-04-19 14:40:57 +0000792 /* All other cases? Just return. */
793}
794
795
sewardje663cb92002-04-12 10:26:32 +0000796static
797void sched_do_syscall ( ThreadId tid )
798{
799 UInt saved_eax;
800 UInt res, syscall_no;
801 UInt fd;
sewardje663cb92002-04-12 10:26:32 +0000802 Bool orig_fd_blockness;
803 Char msg_buf[100];
804
sewardjb48e5002002-05-13 00:16:03 +0000805 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +0000806 vg_assert(vg_threads[tid].status == VgTs_Runnable);
807
808 syscall_no = vg_threads[tid].m_eax; /* syscall number */
809
810 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000811 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000812 struct vki_timespec* req;
813 req = (struct vki_timespec*)vg_threads[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000814 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000815 t_awaken
816 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000817 + (UInt)1000ULL * (UInt)(req->tv_sec)
818 + (UInt)(req->tv_nsec) / 1000000;
sewardje663cb92002-04-12 10:26:32 +0000819 vg_threads[tid].status = VgTs_Sleeping;
820 vg_threads[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000821 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000822 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000823 t_now, t_awaken-t_now);
824 print_sched_event(tid, msg_buf);
825 }
826 /* Force the scheduler to run something else for a while. */
827 return;
828 }
829
sewardjaec22c02002-04-29 01:58:08 +0000830 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000831 /* We think it's non-blocking. Just do it in the normal way. */
832 VG_(perform_assumed_nonblocking_syscall)(tid);
833 /* The thread is still runnable. */
834 return;
835 }
836
sewardje663cb92002-04-12 10:26:32 +0000837 /* Set the fd to nonblocking, and do the syscall, which will return
838 immediately, in order to lodge a request with the Linux kernel.
839 We later poll for I/O completion using select(). */
840
sewardjaec22c02002-04-29 01:58:08 +0000841 fd = vg_threads[tid].m_ebx /* arg1 */;
sewardje663cb92002-04-12 10:26:32 +0000842 orig_fd_blockness = fd_is_blockful(fd);
843 set_fd_nonblocking(fd);
844 vg_assert(!fd_is_blockful(fd));
845 VG_(check_known_blocking_syscall)(tid, syscall_no, NULL /* PRE */);
846
847 /* This trashes the thread's %eax; we have to preserve it. */
848 saved_eax = vg_threads[tid].m_eax;
849 KERNEL_DO_SYSCALL(tid,res);
850
851 /* Restore original blockfulness of the fd. */
852 if (orig_fd_blockness)
853 set_fd_blocking(fd);
854 else
855 set_fd_nonblocking(fd);
856
sewardjaec22c02002-04-29 01:58:08 +0000857 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
858 /* Finish off in the normal way. Don't restore %EAX, since that
859 now (correctly) holds the result of the call. We get here if either:
860 1. The call didn't block, or
861 2. The fd was already in nonblocking mode before we started to
862 mess with it. In this case, we're not expecting to handle
863 the I/O completion -- the client is. So don't file a
864 completion-wait entry.
865 */
sewardje663cb92002-04-12 10:26:32 +0000866 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
867 /* We're still runnable. */
868 vg_assert(vg_threads[tid].status == VgTs_Runnable);
869
870 } else {
871
sewardjaec22c02002-04-29 01:58:08 +0000872 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
873
sewardje663cb92002-04-12 10:26:32 +0000874 /* It would have blocked. First, restore %EAX to what it was
875 before our speculative call. */
876 vg_threads[tid].m_eax = saved_eax;
877 /* Put this fd in a table of fds on which we are waiting for
878 completion. The arguments for select() later are constructed
879 from this table. */
880 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */);
881 /* Deschedule thread until an I/O completion happens. */
882 vg_threads[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000883 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000884 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
885 print_sched_event(tid, msg_buf);
886 }
887
888 }
889}
890
891
892/* Find out which of the fds in vg_waiting_fds are now ready to go, by
893 making enquiries with select(), and mark them as ready. We have to
894 wait for the requesting threads to fall into the the WaitFD state
895 before we can actually finally deliver the results, so this
896 procedure doesn't do that; complete_blocked_syscalls() does it.
897
898 It might seem odd that a thread which has done a blocking syscall
899 is not in WaitFD state; the way this can happen is if it initially
900 becomes WaitFD, but then a signal is delivered to it, so it becomes
901 Runnable for a while. In this case we have to wait for the
902 sighandler to return, whereupon the WaitFD state is resumed, and
903 only at that point can the I/O result be delivered to it. However,
904 this point may be long after the fd is actually ready.
905
906 So, poll_for_ready_fds() merely detects fds which are ready.
907 complete_blocked_syscalls() does the second half of the trick,
908 possibly much later: it delivers the results from ready fds to
909 threads in WaitFD state.
910*/
sewardj9a199dc2002-04-14 13:01:38 +0000911static
sewardje663cb92002-04-12 10:26:32 +0000912void poll_for_ready_fds ( void )
913{
914 vki_ksigset_t saved_procmask;
915 vki_fd_set readfds;
916 vki_fd_set writefds;
917 vki_fd_set exceptfds;
918 struct vki_timeval timeout;
919 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
920 ThreadId tid;
921 Bool rd_ok, wr_ok, ex_ok;
922 Char msg_buf[100];
923
sewardje462e202002-04-13 04:09:07 +0000924 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000925 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000926
sewardje663cb92002-04-12 10:26:32 +0000927 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000928 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj853f55d2002-04-26 00:27:53 +0000929 if (vg_threads[tid].status == VgTs_Sleeping)
930 break;
sewardj6072c362002-04-19 14:40:57 +0000931
sewardj5f07b662002-04-23 16:52:51 +0000932 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000933 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000934 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000935 for (tid = 1; tid < VG_N_THREADS; tid++) {
936 if (vg_threads[tid].status != VgTs_Sleeping)
937 continue;
938 if (t_now >= vg_threads[tid].awaken_at) {
939 /* Resume this thread. Set to zero the remaining-time
940 (second) arg of nanosleep, since it's used up all its
941 time. */
942 vg_assert(vg_threads[tid].m_eax == __NR_nanosleep);
943 rem = (struct vki_timespec *)vg_threads[tid].m_ecx; /* arg2 */
944 if (rem != NULL) {
945 rem->tv_sec = 0;
946 rem->tv_nsec = 0;
947 }
948 /* Make the syscall return 0 (success). */
949 vg_threads[tid].m_eax = 0;
950 /* Reschedule this thread. */
951 vg_threads[tid].status = VgTs_Runnable;
952 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000953 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +0000954 t_now);
955 print_sched_event(tid, msg_buf);
956 }
sewardje663cb92002-04-12 10:26:32 +0000957 }
958 }
959 }
sewardje663cb92002-04-12 10:26:32 +0000960
sewardje462e202002-04-13 04:09:07 +0000961 /* And look for threads waiting on file descriptors which are now
962 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +0000963 timeout.tv_sec = 0;
964 timeout.tv_usec = 0;
965
966 VKI_FD_ZERO(&readfds);
967 VKI_FD_ZERO(&writefds);
968 VKI_FD_ZERO(&exceptfds);
969 fd_max = -1;
970 for (i = 0; i < VG_N_WAITING_FDS; i++) {
971 if (vg_waiting_fds[i].fd == -1 /* not in use */)
972 continue;
973 if (vg_waiting_fds[i].ready /* already ready? */)
974 continue;
975 fd = vg_waiting_fds[i].fd;
976 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +0000977 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +0000978 if (fd > fd_max)
979 fd_max = fd;
980 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +0000981 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +0000982 syscall_no = vg_waiting_fds[i].syscall_no;
983 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +0000984 case __NR_read:
985 /* In order to catch timeout events on fds which are
986 readable and which have been ioctl(TCSETA)'d with a
987 VTIMEout, we appear to need to ask if the fd is
988 writable, for some reason. Ask me not why. Since this
989 is strange and potentially troublesome we only do it if
990 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +0000991 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +0000992 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +0000993 VKI_FD_SET(fd, &readfds); break;
994 case __NR_write:
995 VKI_FD_SET(fd, &writefds); break;
996 default:
997 VG_(panic)("poll_for_ready_fds: unexpected syscall");
998 /*NOTREACHED*/
999 break;
1000 }
1001 }
1002
sewardje462e202002-04-13 04:09:07 +00001003 /* Short cut: if no fds are waiting, give up now. */
1004 if (fd_max == -1)
1005 return;
1006
sewardje663cb92002-04-12 10:26:32 +00001007 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1008 getting interrupted. */
1009 VG_(block_all_host_signals)( &saved_procmask );
1010
1011 n_ready = VG_(select)
1012 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1013 if (VG_(is_kerror)(n_ready)) {
1014 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
1015 VG_(panic)("poll_for_ready_fds: select failed?!");
1016 /*NOTREACHED*/
1017 }
1018
1019 /* UNBLOCK ALL SIGNALS */
1020 VG_(restore_host_signals)( &saved_procmask );
1021
1022 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1023
1024 if (n_ready == 0)
1025 return;
1026
1027 /* Inspect all the fds we know about, and handle any completions that
1028 have happened. */
1029 /*
1030 VG_(printf)("\n\n");
1031 for (fd = 0; fd < 100; fd++)
1032 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1033 VG_(printf)("X"); } else { VG_(printf)("."); };
1034 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1035 */
1036
1037 for (fd = 0; fd <= fd_max; fd++) {
1038 rd_ok = VKI_FD_ISSET(fd, &readfds);
1039 wr_ok = VKI_FD_ISSET(fd, &writefds);
1040 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1041
1042 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1043 if (n_ok == 0)
1044 continue;
1045 if (n_ok > 1) {
1046 VG_(printf)("offending fd = %d\n", fd);
1047 VG_(panic)("poll_for_ready_fds: multiple events on fd");
1048 }
1049
1050 /* An I/O event completed for fd. Find the thread which
1051 requested this. */
1052 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1053 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1054 continue;
1055 if (vg_waiting_fds[i].fd == fd)
1056 break;
1057 }
1058
1059 /* And a bit more paranoia ... */
1060 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1061
1062 /* Mark the fd as ready. */
1063 vg_assert(! vg_waiting_fds[i].ready);
1064 vg_waiting_fds[i].ready = True;
1065 }
1066}
1067
1068
1069/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001070static
sewardje663cb92002-04-12 10:26:32 +00001071void complete_blocked_syscalls ( void )
1072{
1073 Int fd, i, res, syscall_no;
1074 ThreadId tid;
1075 Char msg_buf[100];
1076
1077 /* Inspect all the outstanding fds we know about. */
1078
1079 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1080 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1081 continue;
1082 if (! vg_waiting_fds[i].ready)
1083 continue;
1084
1085 fd = vg_waiting_fds[i].fd;
1086 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001087 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001088
1089 /* The thread actually has to be waiting for the I/O event it
1090 requested before we can deliver the result! */
1091 if (vg_threads[tid].status != VgTs_WaitFD)
1092 continue;
1093
1094 /* Ok, actually do it! We can safely use %EAX as the syscall
1095 number, because the speculative call made by
1096 sched_do_syscall() doesn't change %EAX in the case where the
1097 call would have blocked. */
1098
1099 syscall_no = vg_waiting_fds[i].syscall_no;
1100 vg_assert(syscall_no == vg_threads[tid].m_eax);
1101 KERNEL_DO_SYSCALL(tid,res);
1102 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
1103
1104 /* Reschedule. */
1105 vg_threads[tid].status = VgTs_Runnable;
1106 /* Mark slot as no longer in use. */
1107 vg_waiting_fds[i].fd = -1;
1108 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001109 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001110 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1111 print_sched_event(tid, msg_buf);
1112 }
1113 }
1114}
1115
1116
1117static
sewardj5f07b662002-04-23 16:52:51 +00001118void check_for_pthread_cond_timedwait ( void )
1119{
sewardj51c0aaf2002-04-25 01:32:10 +00001120 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001121 for (i = 1; i < VG_N_THREADS; i++) {
1122 if (vg_threads[i].status != VgTs_WaitCV)
1123 continue;
1124 if (vg_threads[i].awaken_at == 0xFFFFFFFF /* no timeout */)
1125 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001126 now = VG_(read_millisecond_timer)();
1127 if (now >= vg_threads[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001128 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001129 }
sewardj5f07b662002-04-23 16:52:51 +00001130 }
1131}
1132
1133
1134static
sewardje663cb92002-04-12 10:26:32 +00001135void nanosleep_for_a_while ( void )
1136{
1137 Int res;
1138 struct vki_timespec req;
1139 struct vki_timespec rem;
1140 req.tv_sec = 0;
sewardj51c0aaf2002-04-25 01:32:10 +00001141 req.tv_nsec = 20 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001142 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001143 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001144}
1145
1146
1147/* ---------------------------------------------------------------------
1148 The scheduler proper.
1149 ------------------------------------------------------------------ */
1150
1151/* Run user-space threads until either
1152 * Deadlock occurs
1153 * One thread asks to shutdown Valgrind
1154 * The specified number of basic blocks has gone by.
1155*/
1156VgSchedReturnCode VG_(scheduler) ( void )
1157{
1158 ThreadId tid, tid_next;
1159 UInt trc;
1160 UInt dispatch_ctr_SAVED;
sewardj51c0aaf2002-04-25 01:32:10 +00001161 Int request_code, done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001162 Char msg_buf[100];
1163 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001164 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001165
1166 /* For the LRU structures, records when the epoch began. */
1167 ULong lru_epoch_started_at = 0;
1168
1169 /* Start with the root thread. tid in general indicates the
1170 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001171 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001172
1173 /* This is the top level scheduler loop. It falls into three
1174 phases. */
1175 while (True) {
1176
sewardj6072c362002-04-19 14:40:57 +00001177 /* ======================= Phase 0 of 3 =======================
1178 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001179 stage1:
sewardj6072c362002-04-19 14:40:57 +00001180 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001181 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001182
sewardje663cb92002-04-12 10:26:32 +00001183 /* ======================= Phase 1 of 3 =======================
1184 Handle I/O completions and signals. This may change the
1185 status of various threads. Then select a new thread to run,
1186 or declare deadlock, or sleep if there are no runnable
1187 threads but some are blocked on I/O. */
1188
1189 /* Age the LRU structures if an epoch has been completed. */
1190 if (VG_(bbs_done) - lru_epoch_started_at >= VG_BBS_PER_EPOCH) {
1191 lru_epoch_started_at = VG_(bbs_done);
1192 increment_epoch();
1193 }
1194
1195 /* Was a debug-stop requested? */
1196 if (VG_(bbs_to_go) == 0)
1197 goto debug_stop;
1198
1199 /* Do the following loop until a runnable thread is found, or
1200 deadlock is detected. */
1201 while (True) {
1202
1203 /* For stats purposes only. */
1204 VG_(num_scheduling_events_MAJOR) ++;
1205
1206 /* See if any I/O operations which we were waiting for have
1207 completed, and, if so, make runnable the relevant waiting
1208 threads. */
1209 poll_for_ready_fds();
1210 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001211 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001212
1213 /* See if there are any signals which need to be delivered. If
1214 so, choose thread(s) to deliver them to, and build signal
1215 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001216
1217 /* Be careful about delivering signals to a thread waiting
1218 for a mutex. In particular, when the handler is running,
1219 that thread is temporarily apparently-not-waiting for the
1220 mutex, so if it is unlocked by another thread whilst the
1221 handler is running, this thread is not informed. When the
1222 handler returns, the thread resumes waiting on the mutex,
1223 even if, as a result, it has missed the unlocking of it.
1224 Potential deadlock. This sounds all very strange, but the
1225 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001226 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001227 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001228 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001229
1230 /* Try and find a thread (tid) to run. */
1231 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001232 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001233 while (True) {
1234 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001235 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj54cacf02002-04-12 23:24:59 +00001236 if (vg_threads[tid_next].status == VgTs_WaitFD
sewardj51c0aaf2002-04-25 01:32:10 +00001237 || vg_threads[tid_next].status == VgTs_Sleeping
sewardjb48e5002002-05-13 00:16:03 +00001238 || vg_threads[tid_next].status == VgTs_WaitSIG
sewardj51c0aaf2002-04-25 01:32:10 +00001239 || (vg_threads[tid_next].status == VgTs_WaitCV
1240 && vg_threads[tid_next].awaken_at != 0xFFFFFFFF))
1241 n_in_bounded_wait ++;
sewardje663cb92002-04-12 10:26:32 +00001242 if (vg_threads[tid_next].status == VgTs_Runnable)
1243 break; /* We can run this one. */
1244 if (tid_next == tid)
1245 break; /* been all the way round */
1246 }
1247 tid = tid_next;
1248
1249 if (vg_threads[tid].status == VgTs_Runnable) {
1250 /* Found a suitable candidate. Fall out of this loop, so
1251 we can advance to stage 2 of the scheduler: actually
1252 running the thread. */
1253 break;
1254 }
1255
1256 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001257 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001258 /* No runnable threads and no prospect of any appearing
1259 even if we wait for an arbitrary length of time. In
1260 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001261 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001262 return VgSrc_Deadlock;
1263 }
1264
1265 /* At least one thread is in a fd-wait state. Delay for a
1266 while, and go round again, in the hope that eventually a
1267 thread becomes runnable. */
1268 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001269 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001270 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001271 }
1272
1273
1274 /* ======================= Phase 2 of 3 =======================
1275 Wahey! We've finally decided that thread tid is runnable, so
1276 we now do that. Run it for as much of a quanta as possible.
1277 Trivial requests are handled and the thread continues. The
1278 aim is not to do too many of Phase 1 since it is expensive. */
1279
1280 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001281 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001282
1283 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1284 that it decrements the counter before testing it for zero, so
1285 that if VG_(dispatch_ctr) is set to N you get at most N-1
1286 iterations. Also this means that VG_(dispatch_ctr) must
1287 exceed zero before entering the innerloop. Also also, the
1288 decrement is done before the bb is actually run, so you
1289 always get at least one decrement even if nothing happens.
1290 */
1291 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1292 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1293 else
1294 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1295
1296 /* ... and remember what we asked for. */
1297 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1298
sewardj1e8cdc92002-04-18 11:37:52 +00001299 /* paranoia ... */
1300 vg_assert(vg_threads[tid].tid == tid);
1301
sewardje663cb92002-04-12 10:26:32 +00001302 /* Actually run thread tid. */
1303 while (True) {
1304
sewardj7e87e382002-05-03 19:09:05 +00001305 VG_(last_run_tid) = tid;
1306
sewardje663cb92002-04-12 10:26:32 +00001307 /* For stats purposes only. */
1308 VG_(num_scheduling_events_MINOR) ++;
1309
1310 if (0)
1311 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1312 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001313# if 0
1314 if (VG_(bbs_done) > 31700000 + 0) {
1315 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
1316 VG_(translate)(&vg_threads[tid], vg_threads[tid].m_eip,
1317 NULL,NULL,NULL);
1318 }
1319 vg_assert(vg_threads[tid].m_eip != 0);
1320# endif
sewardje663cb92002-04-12 10:26:32 +00001321
1322 trc = run_thread_for_a_while ( tid );
1323
sewardjb3eef6b2002-05-01 00:05:27 +00001324# if 0
1325 if (0 == vg_threads[tid].m_eip) {
1326 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
1327 vg_assert(0 != vg_threads[tid].m_eip);
1328 }
1329# endif
1330
sewardje663cb92002-04-12 10:26:32 +00001331 /* Deal quickly with trivial scheduling events, and resume the
1332 thread. */
1333
1334 if (trc == VG_TRC_INNER_FASTMISS) {
1335 vg_assert(VG_(dispatch_ctr) > 0);
1336
1337 /* Trivial event. Miss in the fast-cache. Do a full
1338 lookup for it. */
1339 trans_addr
1340 = VG_(search_transtab) ( vg_threads[tid].m_eip );
1341 if (trans_addr == (Addr)0) {
1342 /* Not found; we need to request a translation. */
sewardj1e8cdc92002-04-18 11:37:52 +00001343 create_translation_for( tid, vg_threads[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001344 trans_addr = VG_(search_transtab) ( vg_threads[tid].m_eip );
1345 if (trans_addr == (Addr)0)
1346 VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
1347 }
1348 continue; /* with this thread */
1349 }
1350
1351 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj8ccc2be2002-05-10 20:26:37 +00001352 Bool done;
1353 /* VG_(printf)("request 0x%x\n",
1354 *(UInt*)(vg_threads[tid].m_eax)); */
1355 done = maybe_do_trivial_clientreq(tid);
sewardjd7fd4d22002-04-24 01:57:27 +00001356 if (done) {
1357 /* The request is done. We try and continue with the
1358 same thread if still runnable. If not, go back to
1359 Stage 1 to select a new thread to run. */
1360 if (vg_threads[tid].status == VgTs_Runnable)
1361 continue; /* with this thread */
1362 else
1363 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001364 }
1365 }
1366
sewardj51c0aaf2002-04-25 01:32:10 +00001367 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1368 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001369 to become non-runnable. One special case: spot the
1370 client doing calls to exit() and take this as the cue
1371 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001372# if 0
1373 { UInt* esp; Int i;
1374 esp=(UInt*)vg_threads[tid].m_esp;
1375 VG_(printf)("\nBEFORE\n");
1376 for (i = 10; i >= -10; i--)
1377 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1378 }
1379# endif
1380
sewardj7e87e382002-05-03 19:09:05 +00001381 if (vg_threads[tid].m_eax == __NR_exit)
1382 return VgSrc_ExitSyscall;
1383
sewardj51c0aaf2002-04-25 01:32:10 +00001384 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001385
1386# if 0
1387 { UInt* esp; Int i;
1388 esp=(UInt*)vg_threads[tid].m_esp;
1389 VG_(printf)("AFTER\n");
1390 for (i = 10; i >= -10; i--)
1391 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1392 }
1393# endif
1394
sewardj51c0aaf2002-04-25 01:32:10 +00001395 if (vg_threads[tid].status == VgTs_Runnable)
1396 continue; /* with this thread */
1397 else
1398 goto stage1;
1399 }
1400
sewardjd7fd4d22002-04-24 01:57:27 +00001401 /* It's an event we can't quickly deal with. Give up running
1402 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001403 break;
1404 }
1405
1406 /* ======================= Phase 3 of 3 =======================
1407 Handle non-trivial thread requests, mostly pthread stuff. */
1408
1409 /* Ok, we've fallen out of the dispatcher for a
1410 non-completely-trivial reason. First, update basic-block
1411 counters. */
1412
1413 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1414 vg_assert(done_this_time >= 0);
1415 VG_(bbs_to_go) -= (ULong)done_this_time;
1416 VG_(bbs_done) += (ULong)done_this_time;
1417
1418 if (0 && trc != VG_TRC_INNER_FASTMISS)
1419 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1420 tid, done_this_time, (Int)trc );
1421
1422 if (0 && trc != VG_TRC_INNER_FASTMISS)
1423 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1424 tid, VG_(bbs_done),
1425 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001426
sewardje663cb92002-04-12 10:26:32 +00001427 /* Examine the thread's return code to figure out why it
1428 stopped, and handle requests. */
1429
1430 switch (trc) {
1431
1432 case VG_TRC_INNER_FASTMISS:
1433 VG_(panic)("VG_(scheduler): VG_TRC_INNER_FASTMISS");
1434 /*NOTREACHED*/
1435 break;
1436
1437 case VG_TRC_INNER_COUNTERZERO:
1438 /* Timeslice is out. Let a new thread be scheduled,
1439 simply by doing nothing, causing us to arrive back at
1440 Phase 1. */
1441 if (VG_(bbs_to_go) == 0) {
1442 goto debug_stop;
1443 }
1444 vg_assert(VG_(dispatch_ctr) == 0);
1445 break;
1446
1447 case VG_TRC_UNRESUMABLE_SIGNAL:
1448 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1449 away. Again, do nothing, so we wind up back at Phase
1450 1, whereupon the signal will be "delivered". */
1451 break;
1452
sewardje663cb92002-04-12 10:26:32 +00001453 case VG_TRC_EBP_JMP_CLIENTREQ:
1454 /* Do a client request for the vthread tid. Note that
1455 some requests will have been handled by
1456 maybe_do_trivial_clientreq(), so we don't expect to see
1457 those here.
1458 */
sewardj54cacf02002-04-12 23:24:59 +00001459 /* The thread's %EAX points at an arg block, the first
1460 word of which is the request code. */
1461 request_code = ((UInt*)(vg_threads[tid].m_eax))[0];
sewardje663cb92002-04-12 10:26:32 +00001462 if (0) {
sewardj54cacf02002-04-12 23:24:59 +00001463 VG_(sprintf)(msg_buf, "request 0x%x", request_code );
sewardje663cb92002-04-12 10:26:32 +00001464 print_sched_event(tid, msg_buf);
1465 }
1466 /* Do a non-trivial client request for thread tid. tid's
1467 %EAX points to a short vector of argument words, the
1468 first of which is the request code. The result of the
1469 request is put in tid's %EDX. Alternatively, perhaps
1470 the request causes tid to become non-runnable and/or
1471 other blocked threads become runnable. In general we
1472 can and often do mess with the state of arbitrary
1473 threads at this point. */
sewardj7e87e382002-05-03 19:09:05 +00001474 do_nontrivial_clientreq(tid);
sewardje663cb92002-04-12 10:26:32 +00001475 break;
1476
1477 default:
1478 VG_(printf)("\ntrc = %d\n", trc);
1479 VG_(panic)("VG_(scheduler), phase 3: "
1480 "unexpected thread return code");
1481 /* NOTREACHED */
1482 break;
1483
1484 } /* switch (trc) */
1485
1486 /* That completes Phase 3 of 3. Return now to the top of the
1487 main scheduler loop, to Phase 1 of 3. */
1488
1489 } /* top-level scheduler loop */
1490
1491
1492 /* NOTREACHED */
1493 VG_(panic)("scheduler: post-main-loop ?!");
1494 /* NOTREACHED */
1495
1496 debug_stop:
1497 /* If we exited because of a debug stop, print the translation
1498 of the last block executed -- by translating it again, and
1499 throwing away the result. */
1500 VG_(printf)(
1501 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj1e8cdc92002-04-18 11:37:52 +00001502 VG_(translate)( &vg_threads[tid], vg_threads[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001503 VG_(printf)("\n");
1504 VG_(printf)(
1505 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1506
1507 return VgSrc_BbsDone;
1508}
1509
1510
1511/* ---------------------------------------------------------------------
1512 The pthread implementation.
1513 ------------------------------------------------------------------ */
1514
1515#include <pthread.h>
1516#include <errno.h>
1517
sewardjbf290b92002-05-01 02:28:01 +00001518#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001519 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001520
1521/* /usr/include/bits/pthreadtypes.h:
1522 typedef unsigned long int pthread_t;
1523*/
1524
sewardjc3bd5f52002-05-01 03:24:23 +00001525/* Write a value to the client's %EDX (request return value register)
1526 and set the shadow to indicate it is defined. */
1527#define SET_EDX(zztid, zzval) \
1528 do { vg_threads[zztid].m_edx = (zzval); \
1529 vg_threads[zztid].sh_edx = VGM_WORD_VALID; \
1530 } while (0)
1531
sewardje663cb92002-04-12 10:26:32 +00001532
sewardj604ec3c2002-04-18 22:38:41 +00001533/* -----------------------------------------------------------
1534 Thread CREATION, JOINAGE and CANCELLATION.
1535 -------------------------------------------------------- */
1536
sewardjb48e5002002-05-13 00:16:03 +00001537/* Release resources and generally clean up once a thread has finally
1538 disappeared. */
1539static
1540void cleanup_after_thread_exited ( ThreadId tid )
1541{
1542 vg_assert(VG_(is_valid_tid)(tid));
1543 vg_assert(vg_threads[tid].status == VgTs_Empty);
1544 /* Mark its stack no-access */
1545 if (VG_(clo_instrument) && tid != 1)
1546 VGM_(make_noaccess)( vg_threads[tid].stack_base,
1547 vg_threads[tid].stack_size );
1548 /* Forget about any pending signals directed specifically at this
1549 thread. */
1550 VG_(notify_signal_machinery_of_thread_exit)( tid );
1551
1552 /* Get rid of signal handlers specifically arranged for this
1553 thread. */
1554 VG_(update_sigstate_following_WaitSIG_change)();
1555}
1556
1557
sewardje663cb92002-04-12 10:26:32 +00001558static
sewardj853f55d2002-04-26 00:27:53 +00001559void do_pthread_cancel ( ThreadId tid,
sewardje663cb92002-04-12 10:26:32 +00001560 pthread_t tid_cancellee )
1561{
1562 Char msg_buf[100];
sewardj853f55d2002-04-26 00:27:53 +00001563
sewardjb48e5002002-05-13 00:16:03 +00001564 vg_assert(VG_(is_valid_tid)(tid));
sewardj853f55d2002-04-26 00:27:53 +00001565 vg_assert(vg_threads[tid].status != VgTs_Empty);
1566
sewardjb48e5002002-05-13 00:16:03 +00001567 if (!VG_(is_valid_tid)(tid_cancellee)
sewardj853f55d2002-04-26 00:27:53 +00001568 || vg_threads[tid_cancellee].status == VgTs_Empty) {
sewardjc3bd5f52002-05-01 03:24:23 +00001569 SET_EDX(tid, ESRCH);
sewardj853f55d2002-04-26 00:27:53 +00001570 return;
1571 }
1572
sewardje663cb92002-04-12 10:26:32 +00001573 /* We want make is appear that this thread has returned to
1574 do_pthread_create_bogusRA with PTHREAD_CANCELED as the
1575 return value. So: simple: put PTHREAD_CANCELED into %EAX
1576 and &do_pthread_create_bogusRA into %EIP and keep going! */
sewardj8937c812002-04-12 20:12:20 +00001577 if (VG_(clo_trace_sched)) {
sewardj853f55d2002-04-26 00:27:53 +00001578 VG_(sprintf)(msg_buf, "cancelled by %d", tid);
sewardje663cb92002-04-12 10:26:32 +00001579 print_sched_event(tid_cancellee, msg_buf);
1580 }
1581 vg_threads[tid_cancellee].m_eax = (UInt)PTHREAD_CANCELED;
sewardjbc5b99f2002-04-13 00:08:51 +00001582 vg_threads[tid_cancellee].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
sewardje663cb92002-04-12 10:26:32 +00001583 vg_threads[tid_cancellee].status = VgTs_Runnable;
sewardj853f55d2002-04-26 00:27:53 +00001584
1585 /* We return with success (0). */
sewardjc3bd5f52002-05-01 03:24:23 +00001586 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001587}
1588
1589
sewardj3b5d8862002-04-20 13:53:23 +00001590static
1591void do_pthread_exit ( ThreadId tid, void* retval )
1592{
1593 Char msg_buf[100];
1594 /* We want make is appear that this thread has returned to
1595 do_pthread_create_bogusRA with retval as the
1596 return value. So: simple: put retval into %EAX
1597 and &do_pthread_create_bogusRA into %EIP and keep going! */
1598 if (VG_(clo_trace_sched)) {
1599 VG_(sprintf)(msg_buf, "exiting with %p", retval);
1600 print_sched_event(tid, msg_buf);
1601 }
1602 vg_threads[tid].m_eax = (UInt)retval;
1603 vg_threads[tid].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
1604 vg_threads[tid].status = VgTs_Runnable;
1605}
1606
sewardje663cb92002-04-12 10:26:32 +00001607
1608/* Thread tid is exiting, by returning from the function it was
sewardjbc5b99f2002-04-13 00:08:51 +00001609 created with. Or possibly due to pthread_exit or cancellation.
1610 The main complication here is to resume any thread waiting to join
1611 with this one. */
sewardje663cb92002-04-12 10:26:32 +00001612static
sewardjbc5b99f2002-04-13 00:08:51 +00001613void handle_pthread_return ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00001614{
1615 ThreadId jnr; /* joiner, the thread calling pthread_join. */
1616 UInt* jnr_args;
1617 void** jnr_thread_return;
1618 Char msg_buf[100];
1619
1620 /* Mark it as not in use. Leave the stack in place so the next
1621 user of this slot doesn't reallocate it. */
sewardjb48e5002002-05-13 00:16:03 +00001622 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001623 vg_assert(vg_threads[tid].status != VgTs_Empty);
1624
sewardjbc5b99f2002-04-13 00:08:51 +00001625 vg_threads[tid].retval = retval;
sewardje663cb92002-04-12 10:26:32 +00001626
1627 if (vg_threads[tid].joiner == VG_INVALID_THREADID) {
1628 /* No one has yet done a join on me */
1629 vg_threads[tid].status = VgTs_WaitJoiner;
sewardj8937c812002-04-12 20:12:20 +00001630 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001631 VG_(sprintf)(msg_buf,
1632 "root fn returns, waiting for a call pthread_join(%d)",
1633 tid);
1634 print_sched_event(tid, msg_buf);
1635 }
1636 } else {
1637 /* Some is waiting; make their join call return with success,
1638 putting my exit code in the place specified by the caller's
1639 thread_return param. This is all very horrible, since we
1640 need to consult the joiner's arg block -- pointed to by its
1641 %EAX -- in order to extract the 2nd param of its pthread_join
1642 call. TODO: free properly the slot (also below).
1643 */
1644 jnr = vg_threads[tid].joiner;
sewardjb48e5002002-05-13 00:16:03 +00001645 vg_assert(VG_(is_valid_tid)(jnr));
sewardje663cb92002-04-12 10:26:32 +00001646 vg_assert(vg_threads[jnr].status == VgTs_WaitJoinee);
1647 jnr_args = (UInt*)vg_threads[jnr].m_eax;
1648 jnr_thread_return = (void**)(jnr_args[2]);
1649 if (jnr_thread_return != NULL)
1650 *jnr_thread_return = vg_threads[tid].retval;
sewardjc3bd5f52002-05-01 03:24:23 +00001651 SET_EDX(jnr, 0); /* success */
sewardje663cb92002-04-12 10:26:32 +00001652 vg_threads[jnr].status = VgTs_Runnable;
1653 vg_threads[tid].status = VgTs_Empty; /* bye! */
sewardjb48e5002002-05-13 00:16:03 +00001654 cleanup_after_thread_exited ( tid );
sewardj8937c812002-04-12 20:12:20 +00001655 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001656 VG_(sprintf)(msg_buf,
1657 "root fn returns, to find a waiting pthread_join(%d)", tid);
1658 print_sched_event(tid, msg_buf);
1659 VG_(sprintf)(msg_buf,
1660 "my pthread_join(%d) returned; resuming", tid);
1661 print_sched_event(jnr, msg_buf);
1662 }
1663 }
1664
1665 /* Return value is irrelevant; this thread will not get
1666 rescheduled. */
1667}
1668
1669
1670static
1671void do_pthread_join ( ThreadId tid, ThreadId jee, void** thread_return )
1672{
1673 Char msg_buf[100];
1674
1675 /* jee, the joinee, is the thread specified as an arg in thread
1676 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00001677 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001678 vg_assert(vg_threads[tid].status == VgTs_Runnable);
1679
1680 if (jee == tid) {
sewardjc3bd5f52002-05-01 03:24:23 +00001681 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardje663cb92002-04-12 10:26:32 +00001682 vg_threads[tid].status = VgTs_Runnable;
1683 return;
1684 }
1685
1686 if (jee < 0
1687 || jee >= VG_N_THREADS
1688 || vg_threads[jee].status == VgTs_Empty) {
1689 /* Invalid thread to join to. */
sewardjc3bd5f52002-05-01 03:24:23 +00001690 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00001691 vg_threads[tid].status = VgTs_Runnable;
1692 return;
1693 }
1694
1695 if (vg_threads[jee].joiner != VG_INVALID_THREADID) {
1696 /* Someone already did join on this thread */
sewardjc3bd5f52002-05-01 03:24:23 +00001697 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00001698 vg_threads[tid].status = VgTs_Runnable;
1699 return;
1700 }
1701
1702 /* if (vg_threads[jee].detached) ... */
1703
1704 /* Perhaps the joinee has already finished? If so return
1705 immediately with its return code, and free up the slot. TODO:
1706 free it properly (also above). */
1707 if (vg_threads[jee].status == VgTs_WaitJoiner) {
1708 vg_assert(vg_threads[jee].joiner == VG_INVALID_THREADID);
sewardjc3bd5f52002-05-01 03:24:23 +00001709 SET_EDX(tid, 0); /* success */
1710 if (thread_return != NULL) {
sewardje663cb92002-04-12 10:26:32 +00001711 *thread_return = vg_threads[jee].retval;
sewardjc3bd5f52002-05-01 03:24:23 +00001712 /* Not really right, since it makes the thread's return value
1713 appear to be defined even if it isn't. */
1714 if (VG_(clo_instrument))
1715 VGM_(make_readable)( (Addr)thread_return, sizeof(void*) );
1716 }
sewardje663cb92002-04-12 10:26:32 +00001717 vg_threads[tid].status = VgTs_Runnable;
1718 vg_threads[jee].status = VgTs_Empty; /* bye! */
sewardjb48e5002002-05-13 00:16:03 +00001719 cleanup_after_thread_exited ( jee );
sewardj8937c812002-04-12 20:12:20 +00001720 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001721 VG_(sprintf)(msg_buf,
1722 "someone called pthread_join() on me; bye!");
1723 print_sched_event(jee, msg_buf);
1724 VG_(sprintf)(msg_buf,
1725 "my pthread_join(%d) returned immediately",
1726 jee );
1727 print_sched_event(tid, msg_buf);
1728 }
1729 return;
1730 }
1731
1732 /* Ok, so we'll have to wait on jee. */
1733 vg_threads[jee].joiner = tid;
1734 vg_threads[tid].status = VgTs_WaitJoinee;
sewardj8937c812002-04-12 20:12:20 +00001735 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001736 VG_(sprintf)(msg_buf,
1737 "blocking on call of pthread_join(%d)", jee );
1738 print_sched_event(tid, msg_buf);
1739 }
1740 /* So tid's join call does not return just now. */
1741}
1742
1743
1744static
1745void do_pthread_create ( ThreadId parent_tid,
1746 pthread_t* thread,
1747 pthread_attr_t* attr,
1748 void* (*start_routine)(void *),
1749 void* arg )
1750{
sewardj5f07b662002-04-23 16:52:51 +00001751 Int i;
sewardje663cb92002-04-12 10:26:32 +00001752 Addr new_stack;
1753 UInt new_stk_szb;
1754 ThreadId tid;
1755 Char msg_buf[100];
1756
1757 /* Paranoia ... */
1758 vg_assert(sizeof(pthread_t) == sizeof(UInt));
1759
1760 vg_assert(vg_threads[parent_tid].status != VgTs_Empty);
1761
sewardj1e8cdc92002-04-18 11:37:52 +00001762 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00001763
1764 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00001765 vg_assert(tid != 1);
sewardjb48e5002002-05-13 00:16:03 +00001766 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001767
1768 /* Copy the parent's CPU state into the child's, in a roundabout
1769 way (via baseBlock). */
1770 VG_(load_thread_state)(parent_tid);
1771 VG_(save_thread_state)(tid);
1772
1773 /* Consider allocating the child a stack, if the one it already has
1774 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00001775 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00001776
1777 if (new_stk_szb > vg_threads[tid].stack_size) {
1778 /* Again, for good measure :) We definitely don't want to be
1779 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00001780 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00001781 /* for now, we don't handle the case of anything other than
1782 assigning it for the first time. */
1783 vg_assert(vg_threads[tid].stack_size == 0);
1784 vg_assert(vg_threads[tid].stack_base == (Addr)NULL);
1785 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb );
1786 vg_threads[tid].stack_base = new_stack;
1787 vg_threads[tid].stack_size = new_stk_szb;
sewardj1e8cdc92002-04-18 11:37:52 +00001788 vg_threads[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00001789 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00001790 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00001791 }
sewardj1e8cdc92002-04-18 11:37:52 +00001792
1793 vg_threads[tid].m_esp
1794 = vg_threads[tid].stack_base
1795 + vg_threads[tid].stack_size
1796 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
1797
sewardje663cb92002-04-12 10:26:32 +00001798 if (VG_(clo_instrument))
1799 VGM_(make_noaccess)( vg_threads[tid].m_esp,
1800 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
1801
1802 /* push arg */
1803 vg_threads[tid].m_esp -= 4;
1804 * (UInt*)(vg_threads[tid].m_esp) = (UInt)arg;
1805
1806 /* push (magical) return address */
1807 vg_threads[tid].m_esp -= 4;
sewardjbc5b99f2002-04-13 00:08:51 +00001808 * (UInt*)(vg_threads[tid].m_esp) = (UInt)VG_(pthreadreturn_bogusRA);
sewardje663cb92002-04-12 10:26:32 +00001809
1810 if (VG_(clo_instrument))
1811 VGM_(make_readable)( vg_threads[tid].m_esp, 2 * 4 );
1812
1813 /* this is where we start */
1814 vg_threads[tid].m_eip = (UInt)start_routine;
1815
sewardj8937c812002-04-12 20:12:20 +00001816 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001817 VG_(sprintf)(msg_buf,
1818 "new thread, created by %d", parent_tid );
1819 print_sched_event(tid, msg_buf);
1820 }
1821
1822 /* store the thread id in *thread. */
1823 // if (VG_(clo_instrument))
1824 // ***** CHECK *thread is writable
1825 *thread = (pthread_t)tid;
sewardjc3bd5f52002-05-01 03:24:23 +00001826 if (VG_(clo_instrument))
1827 VGM_(make_readable)( (Addr)thread, sizeof(pthread_t) );
sewardje663cb92002-04-12 10:26:32 +00001828
sewardj3b5d8862002-04-20 13:53:23 +00001829 vg_threads[tid].associated_mx = NULL;
1830 vg_threads[tid].associated_cv = NULL;
1831 vg_threads[tid].joiner = VG_INVALID_THREADID;
1832 vg_threads[tid].status = VgTs_Runnable;
sewardj604ec3c2002-04-18 22:38:41 +00001833
sewardj5f07b662002-04-23 16:52:51 +00001834 for (i = 0; i < VG_N_THREAD_KEYS; i++)
1835 vg_threads[tid].specifics[i] = NULL;
1836
sewardjb48e5002002-05-13 00:16:03 +00001837 /* We inherit our parent's signal mask. (?!) */
1838 vg_threads[tid].sig_mask = vg_threads[parent_tid].sig_mask;
1839 VG_(ksigemptyset)(&vg_threads[i].sigs_waited_for);
1840
sewardj604ec3c2002-04-18 22:38:41 +00001841 /* return zero */
sewardj1de04f12002-05-10 02:16:19 +00001842 SET_EDX(parent_tid, 0); /* success */
sewardje663cb92002-04-12 10:26:32 +00001843}
1844
1845
sewardj604ec3c2002-04-18 22:38:41 +00001846/* -----------------------------------------------------------
1847 MUTEXes
1848 -------------------------------------------------------- */
1849
sewardj604ec3c2002-04-18 22:38:41 +00001850/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00001851 typedef struct
1852 {
1853 int __m_reserved; -- Reserved for future use
1854 int __m_count; -- Depth of recursive locking
1855 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
1856 int __m_kind; -- Mutex kind: fast, recursive or errcheck
1857 struct _pthread_fastlock __m_lock; -- Underlying fast lock
1858 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00001859
sewardj6072c362002-04-19 14:40:57 +00001860 #define PTHREAD_MUTEX_INITIALIZER \
1861 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
1862 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
1863 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
1864 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
1865 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
1866 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
1867 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00001868
sewardj6072c362002-04-19 14:40:57 +00001869 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00001870
sewardj6072c362002-04-19 14:40:57 +00001871 __m_kind never changes and indicates whether or not it is recursive.
1872
1873 __m_count indicates the lock count; if 0, the mutex is not owned by
1874 anybody.
1875
1876 __m_owner has a ThreadId value stuffed into it. We carefully arrange
1877 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
1878 statically initialised mutexes correctly appear
1879 to belong to nobody.
1880
1881 In summary, a not-in-use mutex is distinguised by having __m_owner
1882 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
1883 conditions holds, the other should too.
1884
1885 There is no linked list of threads waiting for this mutex. Instead
1886 a thread in WaitMX state points at the mutex with its waited_on_mx
1887 field. This makes _unlock() inefficient, but simple to implement the
1888 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00001889
sewardj604ec3c2002-04-18 22:38:41 +00001890 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00001891 deals with that for us.
1892*/
sewardje663cb92002-04-12 10:26:32 +00001893
sewardj3b5d8862002-04-20 13:53:23 +00001894/* Helper fns ... */
1895static
1896void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
1897 Char* caller )
1898{
1899 Int i;
1900 Char msg_buf[100];
1901
1902 /* Find some arbitrary thread waiting on this mutex, and make it
1903 runnable. If none are waiting, mark the mutex as not held. */
1904 for (i = 1; i < VG_N_THREADS; i++) {
1905 if (vg_threads[i].status == VgTs_Empty)
1906 continue;
1907 if (vg_threads[i].status == VgTs_WaitMX
1908 && vg_threads[i].associated_mx == mutex)
1909 break;
1910 }
1911
1912 vg_assert(i <= VG_N_THREADS);
1913 if (i == VG_N_THREADS) {
1914 /* Nobody else is waiting on it. */
1915 mutex->__m_count = 0;
1916 mutex->__m_owner = VG_INVALID_THREADID;
1917 } else {
1918 /* Notionally transfer the hold to thread i, whose
1919 pthread_mutex_lock() call now returns with 0 (success). */
1920 /* The .count is already == 1. */
1921 vg_assert(vg_threads[i].associated_mx == mutex);
1922 mutex->__m_owner = (_pthread_descr)i;
1923 vg_threads[i].status = VgTs_Runnable;
1924 vg_threads[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00001925 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00001926
1927 if (VG_(clo_trace_pthread_level) >= 1) {
1928 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
1929 caller, mutex );
1930 print_pthread_event(i, msg_buf);
1931 }
1932 }
1933}
1934
sewardje663cb92002-04-12 10:26:32 +00001935
1936static
sewardj30671ff2002-04-21 00:13:57 +00001937void do_pthread_mutex_lock( ThreadId tid,
1938 Bool is_trylock,
sewardjd7fd4d22002-04-24 01:57:27 +00001939 void* /* pthread_mutex_t* */ mutexV )
sewardje663cb92002-04-12 10:26:32 +00001940{
sewardj30671ff2002-04-21 00:13:57 +00001941 Char msg_buf[100];
1942 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00001943 = is_trylock ? "pthread_mutex_trylock"
1944 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00001945
sewardjd7fd4d22002-04-24 01:57:27 +00001946 pthread_mutex_t* mutex = (pthread_mutex_t*)mutexV;
1947
sewardj604ec3c2002-04-18 22:38:41 +00001948 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00001949 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00001950 print_pthread_event(tid, msg_buf);
1951 }
1952
1953 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00001954 vg_assert(VG_(is_valid_tid)(tid)
sewardj604ec3c2002-04-18 22:38:41 +00001955 && vg_threads[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001956
1957 /* POSIX doesn't mandate this, but for sanity ... */
1958 if (mutex == NULL) {
sewardj8e651d72002-05-10 21:00:19 +00001959 /* VG_(printf)("NULL mutex\n"); */
sewardjc3bd5f52002-05-01 03:24:23 +00001960 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00001961 return;
1962 }
1963
sewardj604ec3c2002-04-18 22:38:41 +00001964 /* More paranoia ... */
1965 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00001966# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00001967 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00001968 case PTHREAD_MUTEX_ADAPTIVE_NP:
1969# endif
sewardja1679dd2002-05-10 22:31:40 +00001970# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00001971 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00001972# endif
sewardj604ec3c2002-04-18 22:38:41 +00001973 case PTHREAD_MUTEX_RECURSIVE_NP:
1974 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00001975 if (mutex->__m_count >= 0) break;
1976 /* else fall thru */
1977 default:
sewardj8e651d72002-05-10 21:00:19 +00001978 /* VG_(printf)("unknown __m_kind %d in mutex\n", mutex->__m_kind); */
sewardjc3bd5f52002-05-01 03:24:23 +00001979 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00001980 return;
sewardje663cb92002-04-12 10:26:32 +00001981 }
1982
sewardj604ec3c2002-04-18 22:38:41 +00001983 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00001984
sewardjb48e5002002-05-13 00:16:03 +00001985 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00001986
1987 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00001988 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00001989 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00001990 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00001991 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00001992 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00001993 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00001994 if (0)
1995 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
1996 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00001997 return;
1998 } else {
sewardj30671ff2002-04-21 00:13:57 +00001999 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002000 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002001 else
sewardjc3bd5f52002-05-01 03:24:23 +00002002 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002003 return;
2004 }
2005 } else {
sewardj6072c362002-04-19 14:40:57 +00002006 /* Someone else has it; we have to wait. Mark ourselves
2007 thusly. */
sewardj05553872002-04-20 20:53:17 +00002008 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002009 if (is_trylock) {
2010 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002011 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002012 } else {
2013 vg_threads[tid].status = VgTs_WaitMX;
2014 vg_threads[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002015 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002016 if (VG_(clo_trace_pthread_level) >= 1) {
2017 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2018 caller, mutex );
2019 print_pthread_event(tid, msg_buf);
2020 }
2021 }
sewardje663cb92002-04-12 10:26:32 +00002022 return;
2023 }
sewardjf8f819e2002-04-17 23:21:37 +00002024
sewardje663cb92002-04-12 10:26:32 +00002025 } else {
sewardj6072c362002-04-19 14:40:57 +00002026 /* Nobody owns it. Sanity check ... */
2027 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002028 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002029 mutex->__m_count = 1;
2030 mutex->__m_owner = (_pthread_descr)tid;
sewardj3b5d8862002-04-20 13:53:23 +00002031 vg_assert(vg_threads[tid].associated_mx == NULL);
sewardje663cb92002-04-12 10:26:32 +00002032 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002033 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002034 }
sewardjf8f819e2002-04-17 23:21:37 +00002035
sewardje663cb92002-04-12 10:26:32 +00002036}
2037
2038
2039static
2040void do_pthread_mutex_unlock ( ThreadId tid,
sewardjd7fd4d22002-04-24 01:57:27 +00002041 void* /* pthread_mutex_t* */ mutexV )
sewardje663cb92002-04-12 10:26:32 +00002042{
sewardj3b5d8862002-04-20 13:53:23 +00002043 Char msg_buf[100];
sewardjd7fd4d22002-04-24 01:57:27 +00002044 pthread_mutex_t* mutex = (pthread_mutex_t*)mutexV;
sewardje663cb92002-04-12 10:26:32 +00002045
sewardj45b4b372002-04-16 22:50:32 +00002046 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002047 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002048 print_pthread_event(tid, msg_buf);
2049 }
2050
sewardj604ec3c2002-04-18 22:38:41 +00002051 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002052 vg_assert(VG_(is_valid_tid)(tid)
sewardj604ec3c2002-04-18 22:38:41 +00002053 && vg_threads[tid].status == VgTs_Runnable);
2054
2055 if (mutex == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002056 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002057 return;
2058 }
2059
2060 /* More paranoia ... */
2061 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002062# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002063 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002064 case PTHREAD_MUTEX_ADAPTIVE_NP:
2065# endif
sewardja1679dd2002-05-10 22:31:40 +00002066# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002067 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002068# endif
sewardj604ec3c2002-04-18 22:38:41 +00002069 case PTHREAD_MUTEX_RECURSIVE_NP:
2070 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002071 if (mutex->__m_count >= 0) break;
2072 /* else fall thru */
2073 default:
sewardjc3bd5f52002-05-01 03:24:23 +00002074 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002075 return;
2076 }
sewardje663cb92002-04-12 10:26:32 +00002077
2078 /* Barf if we don't currently hold the mutex. */
sewardj604ec3c2002-04-18 22:38:41 +00002079 if (mutex->__m_count == 0 /* nobody holds it */
2080 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardjc3bd5f52002-05-01 03:24:23 +00002081 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002082 return;
2083 }
2084
sewardjf8f819e2002-04-17 23:21:37 +00002085 /* If it's a multiply-locked recursive mutex, just decrement the
2086 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002087 if (mutex->__m_count > 1) {
2088 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2089 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002090 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002091 return;
2092 }
2093
sewardj604ec3c2002-04-18 22:38:41 +00002094 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002095 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002096 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002097 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002098
sewardj3b5d8862002-04-20 13:53:23 +00002099 /* Release at max one thread waiting on this mutex. */
2100 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002101
sewardj3b5d8862002-04-20 13:53:23 +00002102 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002103 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002104}
2105
2106
sewardj6072c362002-04-19 14:40:57 +00002107/* -----------------------------------------------------------
2108 CONDITION VARIABLES
2109 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002110
sewardj6072c362002-04-19 14:40:57 +00002111/* The relevant native types are as follows:
2112 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002113
sewardj6072c362002-04-19 14:40:57 +00002114 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2115 typedef struct
2116 {
2117 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2118 _pthread_descr __c_waiting; -- Threads waiting on this condition
2119 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002120
sewardj6072c362002-04-19 14:40:57 +00002121 -- Attribute for conditionally variables.
2122 typedef struct
2123 {
2124 int __dummy;
2125 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002126
sewardj6072c362002-04-19 14:40:57 +00002127 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002128
sewardj3b5d8862002-04-20 13:53:23 +00002129 We don't use any fields of pthread_cond_t for anything at all.
2130 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002131
2132 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002133 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002134
sewardj77e466c2002-04-14 02:29:29 +00002135
sewardj5f07b662002-04-23 16:52:51 +00002136static
2137void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2138{
2139 Char msg_buf[100];
2140 pthread_mutex_t* mx;
2141 pthread_cond_t* cv;
2142
sewardjb48e5002002-05-13 00:16:03 +00002143 vg_assert(VG_(is_valid_tid)(tid)
sewardj5f07b662002-04-23 16:52:51 +00002144 && vg_threads[tid].status == VgTs_WaitCV
2145 && vg_threads[tid].awaken_at != 0xFFFFFFFF);
2146 mx = vg_threads[tid].associated_mx;
2147 vg_assert(mx != NULL);
2148 cv = vg_threads[tid].associated_cv;
2149 vg_assert(cv != NULL);
2150
2151 if (mx->__m_owner == VG_INVALID_THREADID) {
2152 /* Currently unheld; hand it out to thread tid. */
2153 vg_assert(mx->__m_count == 0);
2154 vg_threads[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002155 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj5f07b662002-04-23 16:52:51 +00002156 vg_threads[tid].associated_cv = NULL;
2157 vg_threads[tid].associated_mx = NULL;
2158 mx->__m_owner = (_pthread_descr)tid;
2159 mx->__m_count = 1;
2160
2161 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002162 VG_(sprintf)(msg_buf,
2163 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2164 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002165 print_pthread_event(tid, msg_buf);
2166 }
2167 } else {
2168 /* Currently held. Make thread tid be blocked on it. */
2169 vg_assert(mx->__m_count > 0);
2170 vg_threads[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002171 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj5f07b662002-04-23 16:52:51 +00002172 vg_threads[tid].associated_cv = NULL;
2173 vg_threads[tid].associated_mx = mx;
2174 if (VG_(clo_trace_pthread_level) >= 1) {
2175 VG_(sprintf)(msg_buf,
2176 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2177 cv, mx );
2178 print_pthread_event(tid, msg_buf);
2179 }
2180
2181 }
2182}
2183
2184
sewardj3b5d8862002-04-20 13:53:23 +00002185static
2186void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2187 Int n_to_release,
2188 Char* caller )
2189{
2190 Int i;
2191 Char msg_buf[100];
2192 pthread_mutex_t* mx;
2193
2194 while (True) {
2195 if (n_to_release == 0)
2196 return;
2197
2198 /* Find a thread waiting on this CV. */
2199 for (i = 1; i < VG_N_THREADS; i++) {
2200 if (vg_threads[i].status == VgTs_Empty)
2201 continue;
2202 if (vg_threads[i].status == VgTs_WaitCV
2203 && vg_threads[i].associated_cv == cond)
2204 break;
2205 }
2206 vg_assert(i <= VG_N_THREADS);
2207
2208 if (i == VG_N_THREADS) {
2209 /* Nobody else is waiting on it. */
2210 return;
2211 }
2212
2213 mx = vg_threads[i].associated_mx;
2214 vg_assert(mx != NULL);
2215
2216 if (mx->__m_owner == VG_INVALID_THREADID) {
2217 /* Currently unheld; hand it out to thread i. */
2218 vg_assert(mx->__m_count == 0);
2219 vg_threads[i].status = VgTs_Runnable;
2220 vg_threads[i].associated_cv = NULL;
2221 vg_threads[i].associated_mx = NULL;
2222 mx->__m_owner = (_pthread_descr)i;
2223 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002224 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002225
2226 if (VG_(clo_trace_pthread_level) >= 1) {
2227 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2228 caller, cond, mx );
2229 print_pthread_event(i, msg_buf);
2230 }
2231
2232 } else {
2233 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002234 vg_assert(mx->__m_count > 0);
sewardj3b5d8862002-04-20 13:53:23 +00002235 vg_threads[i].status = VgTs_WaitMX;
2236 vg_threads[i].associated_cv = NULL;
2237 vg_threads[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002238 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002239
2240 if (VG_(clo_trace_pthread_level) >= 1) {
2241 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2242 caller, cond, mx );
2243 print_pthread_event(i, msg_buf);
2244 }
2245
2246 }
2247
2248 n_to_release--;
2249 }
2250}
2251
2252
2253static
2254void do_pthread_cond_wait ( ThreadId tid,
2255 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002256 pthread_mutex_t *mutex,
2257 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002258{
2259 Char msg_buf[100];
2260
sewardj5f07b662002-04-23 16:52:51 +00002261 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2262 ms_end is the ending millisecond. */
2263
sewardj3b5d8862002-04-20 13:53:23 +00002264 /* pre: mutex should be a valid mutex and owned by tid. */
2265 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002266 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2267 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002268 print_pthread_event(tid, msg_buf);
2269 }
2270
2271 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002272 vg_assert(VG_(is_valid_tid)(tid)
sewardj3b5d8862002-04-20 13:53:23 +00002273 && vg_threads[tid].status == VgTs_Runnable);
2274
2275 if (mutex == NULL || cond == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002276 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002277 return;
2278 }
2279
2280 /* More paranoia ... */
2281 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002282# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002283 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002284 case PTHREAD_MUTEX_ADAPTIVE_NP:
2285# endif
sewardja1679dd2002-05-10 22:31:40 +00002286# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002287 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002288# endif
sewardj3b5d8862002-04-20 13:53:23 +00002289 case PTHREAD_MUTEX_RECURSIVE_NP:
2290 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002291 if (mutex->__m_count >= 0) break;
2292 /* else fall thru */
2293 default:
sewardjc3bd5f52002-05-01 03:24:23 +00002294 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002295 return;
2296 }
2297
2298 /* Barf if we don't currently hold the mutex. */
2299 if (mutex->__m_count == 0 /* nobody holds it */
2300 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardjc3bd5f52002-05-01 03:24:23 +00002301 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002302 return;
2303 }
2304
2305 /* Queue ourselves on the condition. */
2306 vg_threads[tid].status = VgTs_WaitCV;
2307 vg_threads[tid].associated_cv = cond;
2308 vg_threads[tid].associated_mx = mutex;
sewardj5f07b662002-04-23 16:52:51 +00002309 vg_threads[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002310
2311 if (VG_(clo_trace_pthread_level) >= 1) {
2312 VG_(sprintf)(msg_buf,
2313 "pthread_cond_wait cv %p, mx %p: BLOCK",
2314 cond, mutex );
2315 print_pthread_event(tid, msg_buf);
2316 }
2317
2318 /* Release the mutex. */
2319 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2320}
2321
2322
2323static
2324void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2325 Bool broadcast,
2326 pthread_cond_t *cond )
2327{
2328 Char msg_buf[100];
2329 Char* caller
2330 = broadcast ? "pthread_cond_broadcast"
2331 : "pthread_cond_signal ";
2332
2333 if (VG_(clo_trace_pthread_level) >= 2) {
2334 VG_(sprintf)(msg_buf, "%s cv %p ...",
2335 caller, cond );
2336 print_pthread_event(tid, msg_buf);
2337 }
2338
2339 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002340 vg_assert(VG_(is_valid_tid)(tid)
sewardj3b5d8862002-04-20 13:53:23 +00002341 && vg_threads[tid].status == VgTs_Runnable);
2342
2343 if (cond == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002344 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002345 return;
2346 }
2347
2348 release_N_threads_waiting_on_cond (
2349 cond,
2350 broadcast ? VG_N_THREADS : 1,
2351 caller
2352 );
2353
sewardjc3bd5f52002-05-01 03:24:23 +00002354 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002355}
2356
sewardj77e466c2002-04-14 02:29:29 +00002357
sewardj5f07b662002-04-23 16:52:51 +00002358/* -----------------------------------------------------------
2359 THREAD SPECIFIC DATA
2360 -------------------------------------------------------- */
2361
2362static __inline__
2363Bool is_valid_key ( ThreadKey k )
2364{
2365 /* k unsigned; hence no < 0 check */
2366 if (k >= VG_N_THREAD_KEYS) return False;
2367 if (!vg_thread_keys[k].inuse) return False;
2368 return True;
2369}
2370
2371static
2372void do_pthread_key_create ( ThreadId tid,
2373 pthread_key_t* key,
2374 void (*destructor)(void*) )
2375{
2376 Int i;
2377 Char msg_buf[100];
2378
2379 if (VG_(clo_trace_pthread_level) >= 1) {
2380 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2381 key, destructor );
2382 print_pthread_event(tid, msg_buf);
2383 }
2384
2385 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002386 vg_assert(VG_(is_valid_tid)(tid)
sewardj5f07b662002-04-23 16:52:51 +00002387 && vg_threads[tid].status == VgTs_Runnable);
2388
2389 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2390 if (!vg_thread_keys[i].inuse)
2391 break;
2392
2393 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002394 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002395 return;
2396 */
2397 VG_(panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2398 " increase and recompile");
2399 }
2400
2401 vg_thread_keys[i].inuse = True;
sewardjc3bd5f52002-05-01 03:24:23 +00002402
sewardj5f07b662002-04-23 16:52:51 +00002403 /* TODO: check key for addressibility */
2404 *key = i;
sewardjc3bd5f52002-05-01 03:24:23 +00002405 if (VG_(clo_instrument))
2406 VGM_(make_readable)( (Addr)key, sizeof(pthread_key_t) );
2407
2408 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002409}
2410
2411
2412static
2413void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2414{
2415 Char msg_buf[100];
2416 if (VG_(clo_trace_pthread_level) >= 1) {
2417 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2418 key );
2419 print_pthread_event(tid, msg_buf);
2420 }
2421
sewardjb48e5002002-05-13 00:16:03 +00002422 vg_assert(VG_(is_valid_tid)(tid)
sewardj5f07b662002-04-23 16:52:51 +00002423 && vg_threads[tid].status == VgTs_Runnable);
2424
2425 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002426 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002427 return;
2428 }
2429
2430 vg_thread_keys[key].inuse = False;
2431
2432 /* Optional. We're not required to do this, although it shouldn't
2433 make any difference to programs which use the key/specifics
2434 functions correctly. */
sewardj3b13f0e2002-04-25 20:17:29 +00002435# if 1
sewardj5f07b662002-04-23 16:52:51 +00002436 for (tid = 1; tid < VG_N_THREADS; tid++) {
2437 if (vg_threads[tid].status != VgTs_Empty)
2438 vg_threads[tid].specifics[key] = NULL;
2439 }
sewardj3b13f0e2002-04-25 20:17:29 +00002440# endif
sewardj5f07b662002-04-23 16:52:51 +00002441}
2442
2443
2444static
2445void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
2446{
2447 Char msg_buf[100];
2448 if (VG_(clo_trace_pthread_level) >= 1) {
2449 VG_(sprintf)(msg_buf, "pthread_getspecific key %d",
2450 key );
2451 print_pthread_event(tid, msg_buf);
2452 }
2453
sewardjb48e5002002-05-13 00:16:03 +00002454 vg_assert(VG_(is_valid_tid)(tid)
sewardj5f07b662002-04-23 16:52:51 +00002455 && vg_threads[tid].status == VgTs_Runnable);
2456
2457 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002458 SET_EDX(tid, (UInt)NULL);
sewardj5f07b662002-04-23 16:52:51 +00002459 return;
2460 }
2461
sewardjc3bd5f52002-05-01 03:24:23 +00002462 SET_EDX(tid, (UInt)vg_threads[tid].specifics[key]);
sewardj5f07b662002-04-23 16:52:51 +00002463}
2464
2465
2466static
2467void do_pthread_setspecific ( ThreadId tid,
2468 pthread_key_t key,
2469 void *pointer )
2470{
2471 Char msg_buf[100];
2472 if (VG_(clo_trace_pthread_level) >= 1) {
2473 VG_(sprintf)(msg_buf, "pthread_setspecific key %d, ptr %p",
2474 key, pointer );
2475 print_pthread_event(tid, msg_buf);
2476 }
2477
sewardjb48e5002002-05-13 00:16:03 +00002478 vg_assert(VG_(is_valid_tid)(tid)
sewardj5f07b662002-04-23 16:52:51 +00002479 && vg_threads[tid].status == VgTs_Runnable);
2480
2481 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002482 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002483 return;
2484 }
2485
2486 vg_threads[tid].specifics[key] = pointer;
sewardjc3bd5f52002-05-01 03:24:23 +00002487 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002488}
2489
2490
sewardjb48e5002002-05-13 00:16:03 +00002491/* ---------------------------------------------------
2492 SIGNALS
2493 ------------------------------------------------ */
2494
2495/* See comment in vg_libthread.c:pthread_sigmask() regarding
2496 deliberate confusion of types sigset_t and vki_sigset_t. Also re
2497 meaning of the mashed_how value. Return 0 for OK and 1 for some
2498 kind of addressing error, which the vg_libpthread.c routine turns
2499 into return values 0 and EFAULT respectively. */
2500static
2501void do_pthread_sigmask ( ThreadId tid,
2502 Int mashed_how,
2503 vki_ksigset_t* newmask,
2504 vki_ksigset_t* oldmask )
2505{
2506 Char msg_buf[100];
2507 if (VG_(clo_trace_pthread_level) >= 1) {
2508 VG_(sprintf)(msg_buf,
2509 "pthread_sigmask m_how %d, newmask %p, oldmask %p",
2510 mashed_how, newmask, oldmask );
2511 print_pthread_event(tid, msg_buf);
2512 }
2513
2514 vg_assert(VG_(is_valid_tid)(tid)
2515 && vg_threads[tid].status == VgTs_Runnable);
2516
2517 if (VG_(clo_instrument)) {
2518 /* TODO check newmask/oldmask are addressible/defined */
2519 }
2520
2521 if (oldmask != NULL) {
2522 *oldmask = vg_threads[tid].sig_mask;
2523 if (VG_(clo_instrument)) {
2524 VGM_(make_readable)( (Addr)oldmask, sizeof(vki_ksigset_t) );
2525 }
2526 }
2527
2528 switch (mashed_how) {
2529 case 1: /* SIG_SETMASK */
2530 vg_threads[tid].sig_mask = *newmask;
2531 break;
2532 case 2: /* SIG_BLOCK */
2533 VG_(ksigaddset_from_set)( & vg_threads[tid].sig_mask, newmask);
2534 break;
2535 case 3: /* SIG_UNBLOCK */
2536 VG_(ksigdelset_from_set)( & vg_threads[tid].sig_mask, newmask);
2537 break;
2538 default:
2539 VG_(panic)("do_pthread_sigmask: invalid mashed_how");
2540 /*NOTREACHED*/
2541 break;
2542 }
2543
2544 SET_EDX(tid, 0);
2545}
2546
2547
2548static
2549void do_sigwait ( ThreadId tid,
2550 vki_ksigset_t* set,
2551 Int* sig )
2552{
2553 Char msg_buf[100];
2554 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
2555 VG_(sprintf)(msg_buf,
2556 "suspend due to sigwait(): set %p, sig %p",
2557 set, sig );
2558 print_pthread_event(tid, msg_buf);
2559 }
2560
2561 vg_assert(VG_(is_valid_tid)(tid)
2562 && vg_threads[tid].status == VgTs_Runnable);
2563
2564 vg_threads[tid].sigs_waited_for = *set;
2565 vg_threads[tid].status = VgTs_WaitSIG;
2566 VG_(update_sigstate_following_WaitSIG_change)();
2567}
2568
2569
sewardje663cb92002-04-12 10:26:32 +00002570/* ---------------------------------------------------------------------
2571 Handle non-trivial client requests.
2572 ------------------------------------------------------------------ */
2573
2574static
2575void do_nontrivial_clientreq ( ThreadId tid )
2576{
2577 UInt* arg = (UInt*)(vg_threads[tid].m_eax);
2578 UInt req_no = arg[0];
2579 switch (req_no) {
2580
2581 case VG_USERREQ__PTHREAD_CREATE:
2582 do_pthread_create( tid,
2583 (pthread_t*)arg[1],
2584 (pthread_attr_t*)arg[2],
2585 (void*(*)(void*))arg[3],
2586 (void*)arg[4] );
2587 break;
2588
sewardjbc5b99f2002-04-13 00:08:51 +00002589 case VG_USERREQ__PTHREAD_RETURNS:
2590 handle_pthread_return( tid, (void*)arg[1] );
sewardje663cb92002-04-12 10:26:32 +00002591 break;
2592
2593 case VG_USERREQ__PTHREAD_JOIN:
2594 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
2595 break;
2596
sewardje663cb92002-04-12 10:26:32 +00002597 case VG_USERREQ__PTHREAD_CANCEL:
2598 do_pthread_cancel( tid, (pthread_t)(arg[1]) );
2599 break;
2600
sewardj3b5d8862002-04-20 13:53:23 +00002601 case VG_USERREQ__PTHREAD_EXIT:
2602 do_pthread_exit( tid, (void*)(arg[1]) );
2603 break;
2604
2605 case VG_USERREQ__PTHREAD_COND_WAIT:
2606 do_pthread_cond_wait( tid,
2607 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00002608 (pthread_mutex_t *)(arg[2]),
2609 0xFFFFFFFF /* no timeout */ );
2610 break;
2611
2612 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
2613 do_pthread_cond_wait( tid,
2614 (pthread_cond_t *)(arg[1]),
2615 (pthread_mutex_t *)(arg[2]),
2616 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00002617 break;
2618
2619 case VG_USERREQ__PTHREAD_COND_SIGNAL:
2620 do_pthread_cond_signal_or_broadcast(
2621 tid,
2622 False, /* signal, not broadcast */
2623 (pthread_cond_t *)(arg[1]) );
2624 break;
2625
2626 case VG_USERREQ__PTHREAD_COND_BROADCAST:
2627 do_pthread_cond_signal_or_broadcast(
2628 tid,
2629 True, /* broadcast, not signal */
2630 (pthread_cond_t *)(arg[1]) );
2631 break;
2632
sewardj5f07b662002-04-23 16:52:51 +00002633 case VG_USERREQ__PTHREAD_KEY_CREATE:
2634 do_pthread_key_create ( tid,
2635 (pthread_key_t*)(arg[1]),
2636 (void(*)(void*))(arg[2]) );
2637 break;
2638
2639 case VG_USERREQ__PTHREAD_KEY_DELETE:
2640 do_pthread_key_delete ( tid,
2641 (pthread_key_t)(arg[1]) );
2642 break;
2643
sewardj5f07b662002-04-23 16:52:51 +00002644 case VG_USERREQ__PTHREAD_SETSPECIFIC:
2645 do_pthread_setspecific ( tid,
2646 (pthread_key_t)(arg[1]),
2647 (void*)(arg[2]) );
2648 break;
2649
sewardjb48e5002002-05-13 00:16:03 +00002650 case VG_USERREQ__PTHREAD_SIGMASK:
2651 do_pthread_sigmask ( tid,
2652 arg[1],
2653 (vki_ksigset_t*)(arg[2]),
2654 (vki_ksigset_t*)(arg[3]) );
2655 break;
2656
2657 case VG_USERREQ__SIGWAIT:
2658 do_sigwait ( tid,
2659 (vki_ksigset_t*)(arg[1]),
2660 (Int*)(arg[2]) );
2661 break;
2662
sewardje663cb92002-04-12 10:26:32 +00002663 case VG_USERREQ__MAKE_NOACCESS:
2664 case VG_USERREQ__MAKE_WRITABLE:
2665 case VG_USERREQ__MAKE_READABLE:
2666 case VG_USERREQ__DISCARD:
2667 case VG_USERREQ__CHECK_WRITABLE:
2668 case VG_USERREQ__CHECK_READABLE:
2669 case VG_USERREQ__MAKE_NOACCESS_STACK:
2670 case VG_USERREQ__RUNNING_ON_VALGRIND:
2671 case VG_USERREQ__DO_LEAK_CHECK:
sewardjc3bd5f52002-05-01 03:24:23 +00002672 SET_EDX(
2673 tid,
2674 VG_(handle_client_request) ( &vg_threads[tid], arg )
2675 );
sewardje663cb92002-04-12 10:26:32 +00002676 break;
2677
sewardj77e466c2002-04-14 02:29:29 +00002678 case VG_USERREQ__SIGNAL_RETURNS:
2679 handle_signal_return(tid);
2680 break;
sewardj54cacf02002-04-12 23:24:59 +00002681
sewardje663cb92002-04-12 10:26:32 +00002682 default:
2683 VG_(printf)("panic'd on private request = 0x%x\n", arg[0] );
2684 VG_(panic)("handle_private_client_pthread_request: "
2685 "unknown request");
2686 /*NOTREACHED*/
2687 break;
2688 }
2689}
2690
2691
sewardj6072c362002-04-19 14:40:57 +00002692/* ---------------------------------------------------------------------
2693 Sanity checking.
2694 ------------------------------------------------------------------ */
2695
2696/* Internal consistency checks on the sched/pthread structures. */
2697static
2698void scheduler_sanity ( void )
2699{
sewardj3b5d8862002-04-20 13:53:23 +00002700 pthread_mutex_t* mx;
2701 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00002702 Int i;
sewardj5f07b662002-04-23 16:52:51 +00002703
sewardj6072c362002-04-19 14:40:57 +00002704 /* VG_(printf)("scheduler_sanity\n"); */
2705 for (i = 1; i < VG_N_THREADS; i++) {
sewardj3b5d8862002-04-20 13:53:23 +00002706 mx = vg_threads[i].associated_mx;
2707 cv = vg_threads[i].associated_cv;
sewardj6072c362002-04-19 14:40:57 +00002708 if (vg_threads[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00002709 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
2710 it's actually held by someone, since otherwise this thread
2711 is deadlocked, (4) the mutex's owner is not us, since
2712 otherwise this thread is also deadlocked. The logic in
2713 do_pthread_mutex_lock rejects attempts by a thread to lock
2714 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00002715
sewardjbf290b92002-05-01 02:28:01 +00002716 (2) has been seen to fail sometimes. I don't know why.
2717 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00002718 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00002719 /* 1 */ vg_assert(mx != NULL);
2720 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00002721 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00002722 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00002723 } else
2724 if (vg_threads[i].status == VgTs_WaitCV) {
2725 vg_assert(cv != NULL);
2726 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00002727 } else {
sewardj05553872002-04-20 20:53:17 +00002728 /* Unfortunately these don't hold true when a sighandler is
2729 running. To be fixed. */
2730 /* vg_assert(cv == NULL); */
2731 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00002732 }
sewardjbf290b92002-05-01 02:28:01 +00002733
2734 if (vg_threads[i].status != VgTs_Empty) {
2735 Int
2736 stack_used = (Addr)vg_threads[i].stack_highest_word
2737 - (Addr)vg_threads[i].m_esp;
2738 if (i > 1 /* not the root thread */
2739 && stack_used
2740 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
2741 VG_(message)(Vg_UserMsg,
2742 "Warning: STACK OVERFLOW: "
2743 "thread %d: stack used %d, available %d",
2744 i, stack_used, VG_PTHREAD_STACK_MIN );
2745 VG_(message)(Vg_UserMsg,
2746 "Terminating Valgrind. If thread(s) "
2747 "really need more stack, increase");
2748 VG_(message)(Vg_UserMsg,
2749 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
2750 VG_(exit)(1);
2751 }
sewardjb48e5002002-05-13 00:16:03 +00002752
2753 if (vg_threads[i].status == VgTs_WaitSIG) {
2754 vg_assert( ! VG_(kisemptysigset)(
2755 & vg_threads[i].sigs_waited_for) );
2756 } else {
2757 vg_assert( VG_(kisemptysigset)(
2758 & vg_threads[i].sigs_waited_for) );
2759 }
2760
sewardjbf290b92002-05-01 02:28:01 +00002761 }
sewardj6072c362002-04-19 14:40:57 +00002762 }
sewardj5f07b662002-04-23 16:52:51 +00002763
2764 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
2765 if (!vg_thread_keys[i].inuse)
2766 vg_assert(vg_thread_keys[i].destructor == NULL);
2767 }
sewardj6072c362002-04-19 14:40:57 +00002768}
2769
2770
sewardje663cb92002-04-12 10:26:32 +00002771/*--------------------------------------------------------------------*/
2772/*--- end vg_scheduler.c ---*/
2773/*--------------------------------------------------------------------*/