blob: d1d792a000c784f045d47a3a511df1d81dd3f871 [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
sewardj018f7622002-05-15 21:13:39 +000081/* Globals. A statically allocated array of threads. NOTE: [0] is
82 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000083 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000084ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000085
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;
sewardj018f7622002-05-15 21:13:39 +0000164 if (VG_(threads)[tid].status == VgTs_Empty) return False;
165 return True;
166}
167
168
169__inline__
170Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
171{
172 /* tid is unsigned, hence no < 0 test. */
173 if (tid == 0) return False;
174 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000175 return True;
176}
177
178
sewardj1e8cdc92002-04-18 11:37:52 +0000179/* For constructing error messages only: try and identify a thread
180 whose stack this address currently falls within, or return
181 VG_INVALID_THREADID if it doesn't. A small complication is dealing
182 with any currently VG_(baseBlock)-resident thread.
183*/
184ThreadId VG_(identify_stack_addr)( Addr a )
185{
186 ThreadId tid, tid_to_skip;
187
188 tid_to_skip = VG_INVALID_THREADID;
189
190 /* First check to see if there's a currently-loaded thread in
191 VG_(baseBlock). */
192 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
193 tid = vg_tid_currently_in_baseBlock;
194 if (VG_(baseBlock)[VGOFF_(m_esp)] <= a
sewardj018f7622002-05-15 21:13:39 +0000195 && a <= VG_(threads)[tid].stack_highest_word)
sewardj1e8cdc92002-04-18 11:37:52 +0000196 return tid;
197 else
198 tid_to_skip = tid;
199 }
200
sewardj6072c362002-04-19 14:40:57 +0000201 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000202 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardj1e8cdc92002-04-18 11:37:52 +0000203 if (tid == tid_to_skip) continue;
sewardj018f7622002-05-15 21:13:39 +0000204 if (VG_(threads)[tid].m_esp <= a
205 && a <= VG_(threads)[tid].stack_highest_word)
sewardj1e8cdc92002-04-18 11:37:52 +0000206 return tid;
207 }
208 return VG_INVALID_THREADID;
209}
210
211
sewardj15a43e12002-04-17 19:35:12 +0000212/* Print the scheduler status. */
213void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000214{
215 Int i;
216 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000217 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000218 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000219 VG_(printf)("\nThread %d: status = ", i);
sewardj018f7622002-05-15 21:13:39 +0000220 switch (VG_(threads)[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000221 case VgTs_Runnable: VG_(printf)("Runnable"); break;
222 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
223 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner(%d)",
sewardj018f7622002-05-15 21:13:39 +0000224 VG_(threads)[i].joiner); break;
sewardj6072c362002-04-19 14:40:57 +0000225 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee"); break;
226 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
227 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000228 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000229 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000230 default: VG_(printf)("???"); break;
231 }
sewardj3b5d8862002-04-20 13:53:23 +0000232 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000233 VG_(threads)[i].associated_mx,
234 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000235 VG_(pp_ExeContext)(
sewardj018f7622002-05-15 21:13:39 +0000236 VG_(get_ExeContext)( False, VG_(threads)[i].m_eip,
237 VG_(threads)[i].m_ebp ));
sewardje663cb92002-04-12 10:26:32 +0000238 }
239 VG_(printf)("\n");
240}
241
242static
243void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no )
244{
245 Int i;
246
247 vg_assert(fd != -1); /* avoid total chaos */
248
249 for (i = 0; i < VG_N_WAITING_FDS; i++)
250 if (vg_waiting_fds[i].fd == -1)
251 break;
252
253 if (i == VG_N_WAITING_FDS)
254 VG_(panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
255 /*
256 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
257 tid, fd, i);
258 */
259 vg_waiting_fds[i].fd = fd;
260 vg_waiting_fds[i].tid = tid;
261 vg_waiting_fds[i].ready = False;
262 vg_waiting_fds[i].syscall_no = syscall_no;
263}
264
265
266
267static
268void print_sched_event ( ThreadId tid, Char* what )
269{
sewardj45b4b372002-04-16 22:50:32 +0000270 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000271}
272
273
274static
275void print_pthread_event ( ThreadId tid, Char* what )
276{
277 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000278}
279
280
281static
282Char* name_of_sched_event ( UInt event )
283{
284 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000285 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
286 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
287 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
288 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
289 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
290 default: return "??UNKNOWN??";
291 }
292}
293
294
295/* Create a translation of the client basic block beginning at
296 orig_addr, and add it to the translation cache & translation table.
297 This probably doesn't really belong here, but, hey ...
298*/
sewardj1e8cdc92002-04-18 11:37:52 +0000299static
300void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000301{
302 Addr trans_addr;
303 TTEntry tte;
304 Int orig_size, trans_size;
305 /* Ensure there is space to hold a translation. */
306 VG_(maybe_do_lru_pass)();
sewardj018f7622002-05-15 21:13:39 +0000307 VG_(translate)( &VG_(threads)[tid],
sewardj1e8cdc92002-04-18 11:37:52 +0000308 orig_addr, &orig_size, &trans_addr, &trans_size );
sewardje663cb92002-04-12 10:26:32 +0000309 /* Copy data at trans_addr into the translation cache.
310 Returned pointer is to the code, not to the 4-byte
311 header. */
312 /* Since the .orig_size and .trans_size fields are
313 UShort, be paranoid. */
314 vg_assert(orig_size > 0 && orig_size < 65536);
315 vg_assert(trans_size > 0 && trans_size < 65536);
316 tte.orig_size = orig_size;
317 tte.orig_addr = orig_addr;
318 tte.trans_size = trans_size;
319 tte.trans_addr = VG_(copy_to_transcache)
320 ( trans_addr, trans_size );
321 tte.mru_epoch = VG_(current_epoch);
322 /* Free the intermediary -- was allocated by VG_(emit_code). */
323 VG_(jitfree)( (void*)trans_addr );
324 /* Add to trans tab and set back pointer. */
325 VG_(add_to_trans_tab) ( &tte );
326 /* Update stats. */
327 VG_(this_epoch_in_count) ++;
328 VG_(this_epoch_in_osize) += orig_size;
329 VG_(this_epoch_in_tsize) += trans_size;
330 VG_(overall_in_count) ++;
331 VG_(overall_in_osize) += orig_size;
332 VG_(overall_in_tsize) += trans_size;
333 /* Record translated area for SMC detection. */
334 VG_(smc_mark_original) ( orig_addr, orig_size );
335}
336
337
338/* Allocate a completely empty ThreadState record. */
339static
340ThreadId vg_alloc_ThreadState ( void )
341{
342 Int i;
sewardj6072c362002-04-19 14:40:57 +0000343 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000344 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000345 return i;
346 }
347 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
348 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
349 VG_(panic)("VG_N_THREADS is too low");
350 /*NOTREACHED*/
351}
352
353
sewardj1e8cdc92002-04-18 11:37:52 +0000354ThreadState* VG_(get_current_thread_state) ( void )
355{
sewardj018f7622002-05-15 21:13:39 +0000356 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
357 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000358}
359
360
361ThreadId VG_(get_current_tid) ( void )
362{
sewardj018f7622002-05-15 21:13:39 +0000363 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
sewardj1e8cdc92002-04-18 11:37:52 +0000364 return vg_tid_currently_in_baseBlock;
365}
366
367
sewardje663cb92002-04-12 10:26:32 +0000368/* Copy the saved state of a thread into VG_(baseBlock), ready for it
369 to be run. */
370__inline__
371void VG_(load_thread_state) ( ThreadId tid )
372{
373 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000374 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
375
sewardj018f7622002-05-15 21:13:39 +0000376 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
377 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
378 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
379 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
380 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
381 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
382 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
383 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
384 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags;
385 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000386
387 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000388 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000389
sewardj018f7622002-05-15 21:13:39 +0000390 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
391 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
392 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
393 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
394 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
395 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
396 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
397 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
398 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
sewardj1e8cdc92002-04-18 11:37:52 +0000399
400 vg_tid_currently_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000401}
402
403
404/* Copy the state of a thread from VG_(baseBlock), presumably after it
405 has been descheduled. For sanity-check purposes, fill the vacated
406 VG_(baseBlock) with garbage so as to make the system more likely to
407 fail quickly if we erroneously continue to poke around inside
408 VG_(baseBlock) without first doing a load_thread_state().
409*/
410__inline__
411void VG_(save_thread_state) ( ThreadId tid )
412{
413 Int i;
414 const UInt junk = 0xDEADBEEF;
415
sewardj1e8cdc92002-04-18 11:37:52 +0000416 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
417
sewardj018f7622002-05-15 21:13:39 +0000418 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
419 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
420 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
421 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
422 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
423 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
424 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
425 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
426 VG_(threads)[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
427 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000428
429 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000430 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000431
sewardj018f7622002-05-15 21:13:39 +0000432 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
433 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
434 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
435 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
436 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
437 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
438 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
439 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
440 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
sewardje663cb92002-04-12 10:26:32 +0000441
442 /* Fill it up with junk. */
443 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
444 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
445 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
446 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
447 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
448 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
449 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
450 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
451 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
452 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
453
454 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
455 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000456
457 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000458}
459
460
461/* Run the thread tid for a while, and return a VG_TRC_* value to the
462 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000463static
sewardje663cb92002-04-12 10:26:32 +0000464UInt run_thread_for_a_while ( ThreadId tid )
465{
sewardj7ccc5c22002-04-24 21:39:11 +0000466 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000467 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000468 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000469 vg_assert(VG_(bbs_to_go) > 0);
470
sewardj671ff542002-05-07 09:25:30 +0000471 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000472 VG_(load_thread_state) ( tid );
473 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
474 /* try this ... */
475 trc = VG_(run_innerloop)();
476 /* We get here if the client didn't take a fault. */
477 } else {
478 /* We get here if the client took a fault, which caused our
479 signal handler to longjmp. */
480 vg_assert(trc == 0);
481 trc = VG_TRC_UNRESUMABLE_SIGNAL;
482 }
483 VG_(save_thread_state) ( tid );
sewardj671ff542002-05-07 09:25:30 +0000484 VGP_POPCC;
sewardje663cb92002-04-12 10:26:32 +0000485 return trc;
486}
487
488
489/* Increment the LRU epoch counter. */
490static
491void increment_epoch ( void )
492{
493 VG_(current_epoch)++;
494 if (VG_(clo_verbosity) > 2) {
495 UInt tt_used, tc_used;
496 VG_(get_tt_tc_used) ( &tt_used, &tc_used );
497 VG_(message)(Vg_UserMsg,
498 "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
499 VG_(bbs_done),
500 VG_(this_epoch_in_count),
501 VG_(this_epoch_in_osize),
502 VG_(this_epoch_in_tsize),
503 VG_(this_epoch_out_count),
504 VG_(this_epoch_out_osize),
505 VG_(this_epoch_out_tsize),
506 tt_used, tc_used
507 );
508 }
509 VG_(this_epoch_in_count) = 0;
510 VG_(this_epoch_in_osize) = 0;
511 VG_(this_epoch_in_tsize) = 0;
512 VG_(this_epoch_out_count) = 0;
513 VG_(this_epoch_out_osize) = 0;
514 VG_(this_epoch_out_tsize) = 0;
515}
516
517
518/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000519 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000520 caller takes care to park the client's state is parked in
521 VG_(baseBlock).
522*/
523void VG_(scheduler_init) ( void )
524{
525 Int i;
526 Addr startup_esp;
527 ThreadId tid_main;
528
529 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000530
531 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
532 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)) {
533 /* Jolly good! */
534 } else {
535 VG_(printf)("%%esp at startup = %p is not near %p or %p; aborting\n",
536 (void*)startup_esp,
537 (void*)VG_STARTUP_STACK_BASE_1,
538 (void*)VG_STARTUP_STACK_BASE_2 );
sewardje663cb92002-04-12 10:26:32 +0000539 VG_(panic)("unexpected %esp at startup");
540 }
541
sewardj6072c362002-04-19 14:40:57 +0000542 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000543 VG_(threads)[i].status = VgTs_Empty;
544 VG_(threads)[i].stack_size = 0;
545 VG_(threads)[i].stack_base = (Addr)NULL;
546 VG_(threads)[i].tid = i;
547 VG_(ksigemptyset)(&VG_(threads)[i].sig_mask);
548 VG_(ksigemptyset)(&VG_(threads)[i].sigs_waited_for);
sewardje663cb92002-04-12 10:26:32 +0000549 }
550
551 for (i = 0; i < VG_N_WAITING_FDS; i++)
552 vg_waiting_fds[i].fd = -1; /* not in use */
553
sewardj5f07b662002-04-23 16:52:51 +0000554 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
555 vg_thread_keys[i].inuse = False;
556 vg_thread_keys[i].destructor = NULL;
557 }
558
sewardje663cb92002-04-12 10:26:32 +0000559 /* Assert this is thread zero, which has certain magic
560 properties. */
561 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000562 vg_assert(tid_main == 1);
sewardje663cb92002-04-12 10:26:32 +0000563
sewardj018f7622002-05-15 21:13:39 +0000564 VG_(threads)[tid_main].status = VgTs_Runnable;
565 VG_(threads)[tid_main].joiner = VG_INVALID_THREADID;
566 VG_(threads)[tid_main].associated_mx = NULL;
567 VG_(threads)[tid_main].associated_cv = NULL;
568 VG_(threads)[tid_main].retval = NULL; /* not important */
sewardj5f07b662002-04-23 16:52:51 +0000569 for (i = 0; i < VG_N_THREAD_KEYS; i++)
sewardj018f7622002-05-15 21:13:39 +0000570 VG_(threads)[tid_main].specifics[i] = NULL;
sewardje663cb92002-04-12 10:26:32 +0000571
572 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000573 vg_tid_currently_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000574 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000575
sewardj018f7622002-05-15 21:13:39 +0000576 VG_(threads)[tid_main].stack_highest_word
577 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000578
sewardj1e8cdc92002-04-18 11:37:52 +0000579 /* So now ... */
580 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardje663cb92002-04-12 10:26:32 +0000581}
582
583
584/* What if fd isn't a valid fd? */
585static
586void set_fd_nonblocking ( Int fd )
587{
588 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
589 vg_assert(!VG_(is_kerror)(res));
590 res |= VKI_O_NONBLOCK;
591 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
592 vg_assert(!VG_(is_kerror)(res));
593}
594
595static
596void set_fd_blocking ( Int fd )
597{
598 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
599 vg_assert(!VG_(is_kerror)(res));
600 res &= ~VKI_O_NONBLOCK;
601 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
602 vg_assert(!VG_(is_kerror)(res));
603}
604
605static
606Bool fd_is_blockful ( Int fd )
607{
608 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
609 vg_assert(!VG_(is_kerror)(res));
610 return (res & VKI_O_NONBLOCK) ? False : True;
611}
612
613
614
sewardjd7fd4d22002-04-24 01:57:27 +0000615/* Possibly do a for tid. Return values are:
sewardje663cb92002-04-12 10:26:32 +0000616
sewardjd7fd4d22002-04-24 01:57:27 +0000617 True = request done. Thread may or may not be still runnable;
618 caller must check. If it is still runnable, the result will be in
619 the thread's %EDX as expected.
620
621 False = request not done. A more capable but slower mechanism will
622 deal with it.
sewardje663cb92002-04-12 10:26:32 +0000623*/
sewardjd7fd4d22002-04-24 01:57:27 +0000624static
sewardje663cb92002-04-12 10:26:32 +0000625Bool maybe_do_trivial_clientreq ( ThreadId tid )
626{
627# define SIMPLE_RETURN(vvv) \
sewardj8c824512002-04-14 04:16:48 +0000628 { tst->m_edx = (vvv); \
sewardjc3bd5f52002-05-01 03:24:23 +0000629 tst->sh_edx = VGM_WORD_VALID; \
sewardje663cb92002-04-12 10:26:32 +0000630 return True; \
631 }
632
sewardj018f7622002-05-15 21:13:39 +0000633 ThreadState* tst = &VG_(threads)[tid];
sewardj8c824512002-04-14 04:16:48 +0000634 UInt* arg = (UInt*)(tst->m_eax);
635 UInt req_no = arg[0];
636
sewardj8ccc2be2002-05-10 20:26:37 +0000637 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +0000638 switch (req_no) {
639 case VG_USERREQ__MALLOC:
640 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000641 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
sewardje663cb92002-04-12 10:26:32 +0000642 );
643 case VG_USERREQ__BUILTIN_NEW:
644 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000645 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
sewardje663cb92002-04-12 10:26:32 +0000646 );
647 case VG_USERREQ__BUILTIN_VEC_NEW:
648 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000649 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
sewardje663cb92002-04-12 10:26:32 +0000650 );
651 case VG_USERREQ__FREE:
sewardj8c824512002-04-14 04:16:48 +0000652 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
sewardje663cb92002-04-12 10:26:32 +0000653 SIMPLE_RETURN(0); /* irrelevant */
654 case VG_USERREQ__BUILTIN_DELETE:
sewardj8c824512002-04-14 04:16:48 +0000655 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
sewardje663cb92002-04-12 10:26:32 +0000656 SIMPLE_RETURN(0); /* irrelevant */
657 case VG_USERREQ__BUILTIN_VEC_DELETE:
sewardj8c824512002-04-14 04:16:48 +0000658 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
sewardje663cb92002-04-12 10:26:32 +0000659 SIMPLE_RETURN(0); /* irrelevant */
660 case VG_USERREQ__CALLOC:
661 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000662 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000663 );
664 case VG_USERREQ__REALLOC:
665 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000666 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000667 );
668 case VG_USERREQ__MEMALIGN:
669 SIMPLE_RETURN(
sewardj8c824512002-04-14 04:16:48 +0000670 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
sewardje663cb92002-04-12 10:26:32 +0000671 );
sewardj9650c992002-04-16 03:44:31 +0000672
sewardj5f07b662002-04-23 16:52:51 +0000673 /* These are heavily used -- or at least we want them to be
674 cheap. */
sewardj9650c992002-04-16 03:44:31 +0000675 case VG_USERREQ__PTHREAD_GET_THREADID:
676 SIMPLE_RETURN(tid);
677 case VG_USERREQ__RUNNING_ON_VALGRIND:
678 SIMPLE_RETURN(1);
sewardj45b4b372002-04-16 22:50:32 +0000679 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
680 SIMPLE_RETURN(VG_(clo_trace_pthread_level));
sewardj5f07b662002-04-23 16:52:51 +0000681 case VG_USERREQ__READ_MILLISECOND_TIMER:
682 SIMPLE_RETURN(VG_(read_millisecond_timer)());
sewardj9650c992002-04-16 03:44:31 +0000683
sewardjd7fd4d22002-04-24 01:57:27 +0000684 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
685 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
686 return True;
687
688 /* This may make thread tid non-runnable, but the scheduler
689 checks for that on return from this function. */
690 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
691 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
692 return True;
693
sewardj14e03422002-04-24 19:51:31 +0000694 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
695 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
696 return True;
697
sewardj51c0aaf2002-04-25 01:32:10 +0000698 case VG_USERREQ__PTHREAD_GETSPECIFIC:
699 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
700 return True;
701
sewardje663cb92002-04-12 10:26:32 +0000702 default:
703 /* Too hard; wimp out. */
704 return False;
705 }
706# undef SIMPLE_RETURN
707}
708
709
sewardj6072c362002-04-19 14:40:57 +0000710/* vthread tid is returning from a signal handler; modify its
711 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000712
713/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
714 for read or write, has been interrupted by a signal. Find and
715 clear the relevant vg_waiting_fd[] entry. Most of the code in this
716 procedure is total paranoia, if you look closely. */
717static
718void cleanup_waiting_fd_table ( ThreadId tid )
719{
720 Int i, waiters;
721
sewardjb48e5002002-05-13 00:16:03 +0000722 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000723 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
724 vg_assert(VG_(threads)[tid].m_eax == __NR_read
725 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000726
727 /* Excessively paranoidly ... find the fd this op was waiting
728 for, and mark it as not being waited on. */
729 waiters = 0;
730 for (i = 0; i < VG_N_WAITING_FDS; i++) {
731 if (vg_waiting_fds[i].tid == tid) {
732 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000733 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000734 }
735 }
736 vg_assert(waiters == 1);
737 for (i = 0; i < VG_N_WAITING_FDS; i++)
738 if (vg_waiting_fds[i].tid == tid)
739 break;
740 vg_assert(i < VG_N_WAITING_FDS);
741 vg_assert(vg_waiting_fds[i].fd != -1);
742 vg_waiting_fds[i].fd = -1; /* not in use */
743}
744
745
sewardj6072c362002-04-19 14:40:57 +0000746static
747void handle_signal_return ( ThreadId tid )
748{
749 Char msg_buf[100];
750 Bool restart_blocked_syscalls;
751
sewardjb48e5002002-05-13 00:16:03 +0000752 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000753
754 restart_blocked_syscalls = VG_(signal_returns)(tid);
755
756 if (restart_blocked_syscalls)
757 /* Easy; we don't have to do anything. */
758 return;
759
sewardj018f7622002-05-15 21:13:39 +0000760 if (VG_(threads)[tid].status == VgTs_WaitFD
761 && (VG_(threads)[tid].m_eax == __NR_read
762 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000763 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000764 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000765 VG_(threads)[tid].m_eax = -VKI_EINTR;
766 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000767
sewardj6072c362002-04-19 14:40:57 +0000768 if (VG_(clo_trace_sched)) {
769 VG_(sprintf)(msg_buf,
770 "read() / write() interrupted by signal; return EINTR" );
771 print_sched_event(tid, msg_buf);
772 }
773 return;
774 }
775
sewardj018f7622002-05-15 21:13:39 +0000776 if (VG_(threads)[tid].status == VgTs_WaitFD
777 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000778 /* We interrupted a nanosleep(). The right thing to do is to
779 write the unused time to nanosleep's second param and return
780 EINTR, but I'm too lazy for that. */
781 return;
782 }
783
sewardj018f7622002-05-15 21:13:39 +0000784 if (VG_(threads)[tid].status == VgTs_WaitFD) {
sewardj1ffa8da2002-04-26 22:47:57 +0000785 VG_(panic)("handle_signal_return: unknown interrupted syscall");
786 }
787
sewardj6072c362002-04-19 14:40:57 +0000788 /* All other cases? Just return. */
789}
790
791
sewardje663cb92002-04-12 10:26:32 +0000792static
793void sched_do_syscall ( ThreadId tid )
794{
795 UInt saved_eax;
796 UInt res, syscall_no;
797 UInt fd;
sewardje663cb92002-04-12 10:26:32 +0000798 Bool orig_fd_blockness;
799 Char msg_buf[100];
800
sewardjb48e5002002-05-13 00:16:03 +0000801 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000802 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000803
sewardj018f7622002-05-15 21:13:39 +0000804 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000805
806 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000807 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000808 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000809 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000810 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000811 t_awaken
812 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000813 + (UInt)1000ULL * (UInt)(req->tv_sec)
814 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000815 VG_(threads)[tid].status = VgTs_Sleeping;
816 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000817 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000818 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000819 t_now, t_awaken-t_now);
820 print_sched_event(tid, msg_buf);
821 }
822 /* Force the scheduler to run something else for a while. */
823 return;
824 }
825
sewardjaec22c02002-04-29 01:58:08 +0000826 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000827 /* We think it's non-blocking. Just do it in the normal way. */
828 VG_(perform_assumed_nonblocking_syscall)(tid);
829 /* The thread is still runnable. */
830 return;
831 }
832
sewardje663cb92002-04-12 10:26:32 +0000833 /* Set the fd to nonblocking, and do the syscall, which will return
834 immediately, in order to lodge a request with the Linux kernel.
835 We later poll for I/O completion using select(). */
836
sewardj018f7622002-05-15 21:13:39 +0000837 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardje663cb92002-04-12 10:26:32 +0000838 orig_fd_blockness = fd_is_blockful(fd);
839 set_fd_nonblocking(fd);
840 vg_assert(!fd_is_blockful(fd));
841 VG_(check_known_blocking_syscall)(tid, syscall_no, NULL /* PRE */);
842
843 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000844 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000845 KERNEL_DO_SYSCALL(tid,res);
846
847 /* Restore original blockfulness of the fd. */
848 if (orig_fd_blockness)
849 set_fd_blocking(fd);
850 else
851 set_fd_nonblocking(fd);
852
sewardjaec22c02002-04-29 01:58:08 +0000853 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
854 /* Finish off in the normal way. Don't restore %EAX, since that
855 now (correctly) holds the result of the call. We get here if either:
856 1. The call didn't block, or
857 2. The fd was already in nonblocking mode before we started to
858 mess with it. In this case, we're not expecting to handle
859 the I/O completion -- the client is. So don't file a
860 completion-wait entry.
861 */
sewardje663cb92002-04-12 10:26:32 +0000862 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
863 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000864 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000865
866 } else {
867
sewardjaec22c02002-04-29 01:58:08 +0000868 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
869
sewardje663cb92002-04-12 10:26:32 +0000870 /* It would have blocked. First, restore %EAX to what it was
871 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000872 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000873 /* Put this fd in a table of fds on which we are waiting for
874 completion. The arguments for select() later are constructed
875 from this table. */
876 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */);
877 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000878 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000879 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000880 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
881 print_sched_event(tid, msg_buf);
882 }
883
884 }
885}
886
887
888/* Find out which of the fds in vg_waiting_fds are now ready to go, by
889 making enquiries with select(), and mark them as ready. We have to
890 wait for the requesting threads to fall into the the WaitFD state
891 before we can actually finally deliver the results, so this
892 procedure doesn't do that; complete_blocked_syscalls() does it.
893
894 It might seem odd that a thread which has done a blocking syscall
895 is not in WaitFD state; the way this can happen is if it initially
896 becomes WaitFD, but then a signal is delivered to it, so it becomes
897 Runnable for a while. In this case we have to wait for the
898 sighandler to return, whereupon the WaitFD state is resumed, and
899 only at that point can the I/O result be delivered to it. However,
900 this point may be long after the fd is actually ready.
901
902 So, poll_for_ready_fds() merely detects fds which are ready.
903 complete_blocked_syscalls() does the second half of the trick,
904 possibly much later: it delivers the results from ready fds to
905 threads in WaitFD state.
906*/
sewardj9a199dc2002-04-14 13:01:38 +0000907static
sewardje663cb92002-04-12 10:26:32 +0000908void poll_for_ready_fds ( void )
909{
910 vki_ksigset_t saved_procmask;
911 vki_fd_set readfds;
912 vki_fd_set writefds;
913 vki_fd_set exceptfds;
914 struct vki_timeval timeout;
915 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
916 ThreadId tid;
917 Bool rd_ok, wr_ok, ex_ok;
918 Char msg_buf[100];
919
sewardje462e202002-04-13 04:09:07 +0000920 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000921 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000922
sewardje663cb92002-04-12 10:26:32 +0000923 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000924 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000925 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000926 break;
sewardj6072c362002-04-19 14:40:57 +0000927
sewardj5f07b662002-04-23 16:52:51 +0000928 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000929 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000930 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000931 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000932 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000933 continue;
sewardj018f7622002-05-15 21:13:39 +0000934 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +0000935 /* Resume this thread. Set to zero the remaining-time
936 (second) arg of nanosleep, since it's used up all its
937 time. */
sewardj018f7622002-05-15 21:13:39 +0000938 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
939 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +0000940 if (rem != NULL) {
941 rem->tv_sec = 0;
942 rem->tv_nsec = 0;
943 }
944 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +0000945 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +0000946 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +0000947 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000948 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000949 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +0000950 t_now);
951 print_sched_event(tid, msg_buf);
952 }
sewardje663cb92002-04-12 10:26:32 +0000953 }
954 }
955 }
sewardje663cb92002-04-12 10:26:32 +0000956
sewardje462e202002-04-13 04:09:07 +0000957 /* And look for threads waiting on file descriptors which are now
958 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +0000959 timeout.tv_sec = 0;
960 timeout.tv_usec = 0;
961
962 VKI_FD_ZERO(&readfds);
963 VKI_FD_ZERO(&writefds);
964 VKI_FD_ZERO(&exceptfds);
965 fd_max = -1;
966 for (i = 0; i < VG_N_WAITING_FDS; i++) {
967 if (vg_waiting_fds[i].fd == -1 /* not in use */)
968 continue;
969 if (vg_waiting_fds[i].ready /* already ready? */)
970 continue;
971 fd = vg_waiting_fds[i].fd;
972 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +0000973 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +0000974 if (fd > fd_max)
975 fd_max = fd;
976 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +0000977 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +0000978 syscall_no = vg_waiting_fds[i].syscall_no;
979 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +0000980 case __NR_read:
981 /* In order to catch timeout events on fds which are
982 readable and which have been ioctl(TCSETA)'d with a
983 VTIMEout, we appear to need to ask if the fd is
984 writable, for some reason. Ask me not why. Since this
985 is strange and potentially troublesome we only do it if
986 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +0000987 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +0000988 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +0000989 VKI_FD_SET(fd, &readfds); break;
990 case __NR_write:
991 VKI_FD_SET(fd, &writefds); break;
992 default:
993 VG_(panic)("poll_for_ready_fds: unexpected syscall");
994 /*NOTREACHED*/
995 break;
996 }
997 }
998
sewardje462e202002-04-13 04:09:07 +0000999 /* Short cut: if no fds are waiting, give up now. */
1000 if (fd_max == -1)
1001 return;
1002
sewardje663cb92002-04-12 10:26:32 +00001003 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1004 getting interrupted. */
1005 VG_(block_all_host_signals)( &saved_procmask );
1006
1007 n_ready = VG_(select)
1008 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1009 if (VG_(is_kerror)(n_ready)) {
1010 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
1011 VG_(panic)("poll_for_ready_fds: select failed?!");
1012 /*NOTREACHED*/
1013 }
1014
1015 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001016 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001017
1018 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1019
1020 if (n_ready == 0)
1021 return;
1022
1023 /* Inspect all the fds we know about, and handle any completions that
1024 have happened. */
1025 /*
1026 VG_(printf)("\n\n");
1027 for (fd = 0; fd < 100; fd++)
1028 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1029 VG_(printf)("X"); } else { VG_(printf)("."); };
1030 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1031 */
1032
1033 for (fd = 0; fd <= fd_max; fd++) {
1034 rd_ok = VKI_FD_ISSET(fd, &readfds);
1035 wr_ok = VKI_FD_ISSET(fd, &writefds);
1036 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1037
1038 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1039 if (n_ok == 0)
1040 continue;
1041 if (n_ok > 1) {
1042 VG_(printf)("offending fd = %d\n", fd);
1043 VG_(panic)("poll_for_ready_fds: multiple events on fd");
1044 }
1045
1046 /* An I/O event completed for fd. Find the thread which
1047 requested this. */
1048 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1049 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1050 continue;
1051 if (vg_waiting_fds[i].fd == fd)
1052 break;
1053 }
1054
1055 /* And a bit more paranoia ... */
1056 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1057
1058 /* Mark the fd as ready. */
1059 vg_assert(! vg_waiting_fds[i].ready);
1060 vg_waiting_fds[i].ready = True;
1061 }
1062}
1063
1064
1065/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001066static
sewardje663cb92002-04-12 10:26:32 +00001067void complete_blocked_syscalls ( void )
1068{
1069 Int fd, i, res, syscall_no;
1070 ThreadId tid;
1071 Char msg_buf[100];
1072
1073 /* Inspect all the outstanding fds we know about. */
1074
1075 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1076 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1077 continue;
1078 if (! vg_waiting_fds[i].ready)
1079 continue;
1080
1081 fd = vg_waiting_fds[i].fd;
1082 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001083 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001084
1085 /* The thread actually has to be waiting for the I/O event it
1086 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001087 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001088 continue;
1089
1090 /* Ok, actually do it! We can safely use %EAX as the syscall
1091 number, because the speculative call made by
1092 sched_do_syscall() doesn't change %EAX in the case where the
1093 call would have blocked. */
1094
1095 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001096 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardje663cb92002-04-12 10:26:32 +00001097 KERNEL_DO_SYSCALL(tid,res);
1098 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
1099
1100 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001101 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001102 /* Mark slot as no longer in use. */
1103 vg_waiting_fds[i].fd = -1;
1104 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001105 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001106 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1107 print_sched_event(tid, msg_buf);
1108 }
1109 }
1110}
1111
1112
1113static
sewardj5f07b662002-04-23 16:52:51 +00001114void check_for_pthread_cond_timedwait ( void )
1115{
sewardj51c0aaf2002-04-25 01:32:10 +00001116 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001117 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001118 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001119 continue;
sewardj018f7622002-05-15 21:13:39 +00001120 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001121 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001122 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001123 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001124 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001125 }
sewardj5f07b662002-04-23 16:52:51 +00001126 }
1127}
1128
1129
1130static
sewardje663cb92002-04-12 10:26:32 +00001131void nanosleep_for_a_while ( void )
1132{
1133 Int res;
1134 struct vki_timespec req;
1135 struct vki_timespec rem;
1136 req.tv_sec = 0;
sewardj51c0aaf2002-04-25 01:32:10 +00001137 req.tv_nsec = 20 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001138 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001139 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001140}
1141
1142
1143/* ---------------------------------------------------------------------
1144 The scheduler proper.
1145 ------------------------------------------------------------------ */
1146
1147/* Run user-space threads until either
1148 * Deadlock occurs
1149 * One thread asks to shutdown Valgrind
1150 * The specified number of basic blocks has gone by.
1151*/
1152VgSchedReturnCode VG_(scheduler) ( void )
1153{
1154 ThreadId tid, tid_next;
1155 UInt trc;
1156 UInt dispatch_ctr_SAVED;
sewardj51c0aaf2002-04-25 01:32:10 +00001157 Int request_code, done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001158 Char msg_buf[100];
1159 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001160 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001161
1162 /* For the LRU structures, records when the epoch began. */
1163 ULong lru_epoch_started_at = 0;
1164
1165 /* Start with the root thread. tid in general indicates the
1166 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001167 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001168
1169 /* This is the top level scheduler loop. It falls into three
1170 phases. */
1171 while (True) {
1172
sewardj6072c362002-04-19 14:40:57 +00001173 /* ======================= Phase 0 of 3 =======================
1174 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001175 stage1:
sewardj6072c362002-04-19 14:40:57 +00001176 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001177 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001178
sewardje663cb92002-04-12 10:26:32 +00001179 /* ======================= Phase 1 of 3 =======================
1180 Handle I/O completions and signals. This may change the
1181 status of various threads. Then select a new thread to run,
1182 or declare deadlock, or sleep if there are no runnable
1183 threads but some are blocked on I/O. */
1184
1185 /* Age the LRU structures if an epoch has been completed. */
1186 if (VG_(bbs_done) - lru_epoch_started_at >= VG_BBS_PER_EPOCH) {
1187 lru_epoch_started_at = VG_(bbs_done);
1188 increment_epoch();
1189 }
1190
1191 /* Was a debug-stop requested? */
1192 if (VG_(bbs_to_go) == 0)
1193 goto debug_stop;
1194
1195 /* Do the following loop until a runnable thread is found, or
1196 deadlock is detected. */
1197 while (True) {
1198
1199 /* For stats purposes only. */
1200 VG_(num_scheduling_events_MAJOR) ++;
1201
1202 /* See if any I/O operations which we were waiting for have
1203 completed, and, if so, make runnable the relevant waiting
1204 threads. */
1205 poll_for_ready_fds();
1206 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001207 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001208
1209 /* See if there are any signals which need to be delivered. If
1210 so, choose thread(s) to deliver them to, and build signal
1211 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001212
1213 /* Be careful about delivering signals to a thread waiting
1214 for a mutex. In particular, when the handler is running,
1215 that thread is temporarily apparently-not-waiting for the
1216 mutex, so if it is unlocked by another thread whilst the
1217 handler is running, this thread is not informed. When the
1218 handler returns, the thread resumes waiting on the mutex,
1219 even if, as a result, it has missed the unlocking of it.
1220 Potential deadlock. This sounds all very strange, but the
1221 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001222 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001223 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001224 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001225
1226 /* Try and find a thread (tid) to run. */
1227 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001228 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001229 while (True) {
1230 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001231 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001232 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1233 || VG_(threads)[tid_next].status == VgTs_Sleeping
1234 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1235 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1236 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001237 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001238 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001239 break; /* We can run this one. */
1240 if (tid_next == tid)
1241 break; /* been all the way round */
1242 }
1243 tid = tid_next;
1244
sewardj018f7622002-05-15 21:13:39 +00001245 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001246 /* Found a suitable candidate. Fall out of this loop, so
1247 we can advance to stage 2 of the scheduler: actually
1248 running the thread. */
1249 break;
1250 }
1251
1252 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001253 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001254 /* No runnable threads and no prospect of any appearing
1255 even if we wait for an arbitrary length of time. In
1256 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001257 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001258 return VgSrc_Deadlock;
1259 }
1260
1261 /* At least one thread is in a fd-wait state. Delay for a
1262 while, and go round again, in the hope that eventually a
1263 thread becomes runnable. */
1264 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001265 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001266 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001267 }
1268
1269
1270 /* ======================= Phase 2 of 3 =======================
1271 Wahey! We've finally decided that thread tid is runnable, so
1272 we now do that. Run it for as much of a quanta as possible.
1273 Trivial requests are handled and the thread continues. The
1274 aim is not to do too many of Phase 1 since it is expensive. */
1275
1276 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001277 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001278
1279 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1280 that it decrements the counter before testing it for zero, so
1281 that if VG_(dispatch_ctr) is set to N you get at most N-1
1282 iterations. Also this means that VG_(dispatch_ctr) must
1283 exceed zero before entering the innerloop. Also also, the
1284 decrement is done before the bb is actually run, so you
1285 always get at least one decrement even if nothing happens.
1286 */
1287 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1288 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1289 else
1290 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1291
1292 /* ... and remember what we asked for. */
1293 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1294
sewardj1e8cdc92002-04-18 11:37:52 +00001295 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001296 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001297
sewardje663cb92002-04-12 10:26:32 +00001298 /* Actually run thread tid. */
1299 while (True) {
1300
sewardj7e87e382002-05-03 19:09:05 +00001301 VG_(last_run_tid) = tid;
1302
sewardje663cb92002-04-12 10:26:32 +00001303 /* For stats purposes only. */
1304 VG_(num_scheduling_events_MINOR) ++;
1305
1306 if (0)
1307 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1308 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001309# if 0
1310 if (VG_(bbs_done) > 31700000 + 0) {
1311 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001312 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001313 NULL,NULL,NULL);
1314 }
sewardj018f7622002-05-15 21:13:39 +00001315 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001316# endif
sewardje663cb92002-04-12 10:26:32 +00001317
1318 trc = run_thread_for_a_while ( tid );
1319
sewardjb3eef6b2002-05-01 00:05:27 +00001320# if 0
sewardj018f7622002-05-15 21:13:39 +00001321 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001322 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001323 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001324 }
1325# endif
1326
sewardje663cb92002-04-12 10:26:32 +00001327 /* Deal quickly with trivial scheduling events, and resume the
1328 thread. */
1329
1330 if (trc == VG_TRC_INNER_FASTMISS) {
1331 vg_assert(VG_(dispatch_ctr) > 0);
1332
1333 /* Trivial event. Miss in the fast-cache. Do a full
1334 lookup for it. */
1335 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001336 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001337 if (trans_addr == (Addr)0) {
1338 /* Not found; we need to request a translation. */
sewardj018f7622002-05-15 21:13:39 +00001339 create_translation_for( tid, VG_(threads)[tid].m_eip );
1340 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001341 if (trans_addr == (Addr)0)
1342 VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
1343 }
1344 continue; /* with this thread */
1345 }
1346
1347 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj8ccc2be2002-05-10 20:26:37 +00001348 Bool done;
1349 /* VG_(printf)("request 0x%x\n",
sewardj018f7622002-05-15 21:13:39 +00001350 *(UInt*)(VG_(threads)[tid].m_eax)); */
sewardj8ccc2be2002-05-10 20:26:37 +00001351 done = maybe_do_trivial_clientreq(tid);
sewardjd7fd4d22002-04-24 01:57:27 +00001352 if (done) {
1353 /* The request is done. We try and continue with the
1354 same thread if still runnable. If not, go back to
1355 Stage 1 to select a new thread to run. */
sewardj018f7622002-05-15 21:13:39 +00001356 if (VG_(threads)[tid].status == VgTs_Runnable)
sewardjd7fd4d22002-04-24 01:57:27 +00001357 continue; /* with this thread */
1358 else
1359 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001360 }
1361 }
1362
sewardj51c0aaf2002-04-25 01:32:10 +00001363 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1364 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001365 to become non-runnable. One special case: spot the
1366 client doing calls to exit() and take this as the cue
1367 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001368# if 0
1369 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001370 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001371 VG_(printf)("\nBEFORE\n");
1372 for (i = 10; i >= -10; i--)
1373 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1374 }
1375# endif
1376
sewardj018f7622002-05-15 21:13:39 +00001377 if (VG_(threads)[tid].m_eax == __NR_exit)
sewardj7e87e382002-05-03 19:09:05 +00001378 return VgSrc_ExitSyscall;
1379
sewardj51c0aaf2002-04-25 01:32:10 +00001380 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001381
1382# if 0
1383 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001384 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001385 VG_(printf)("AFTER\n");
1386 for (i = 10; i >= -10; i--)
1387 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1388 }
1389# endif
1390
sewardj018f7622002-05-15 21:13:39 +00001391 if (VG_(threads)[tid].status == VgTs_Runnable)
sewardj51c0aaf2002-04-25 01:32:10 +00001392 continue; /* with this thread */
1393 else
1394 goto stage1;
1395 }
1396
sewardjd7fd4d22002-04-24 01:57:27 +00001397 /* It's an event we can't quickly deal with. Give up running
1398 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001399 break;
1400 }
1401
1402 /* ======================= Phase 3 of 3 =======================
1403 Handle non-trivial thread requests, mostly pthread stuff. */
1404
1405 /* Ok, we've fallen out of the dispatcher for a
1406 non-completely-trivial reason. First, update basic-block
1407 counters. */
1408
1409 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1410 vg_assert(done_this_time >= 0);
1411 VG_(bbs_to_go) -= (ULong)done_this_time;
1412 VG_(bbs_done) += (ULong)done_this_time;
1413
1414 if (0 && trc != VG_TRC_INNER_FASTMISS)
1415 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1416 tid, done_this_time, (Int)trc );
1417
1418 if (0 && trc != VG_TRC_INNER_FASTMISS)
1419 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1420 tid, VG_(bbs_done),
1421 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001422
sewardje663cb92002-04-12 10:26:32 +00001423 /* Examine the thread's return code to figure out why it
1424 stopped, and handle requests. */
1425
1426 switch (trc) {
1427
1428 case VG_TRC_INNER_FASTMISS:
1429 VG_(panic)("VG_(scheduler): VG_TRC_INNER_FASTMISS");
1430 /*NOTREACHED*/
1431 break;
1432
1433 case VG_TRC_INNER_COUNTERZERO:
1434 /* Timeslice is out. Let a new thread be scheduled,
1435 simply by doing nothing, causing us to arrive back at
1436 Phase 1. */
1437 if (VG_(bbs_to_go) == 0) {
1438 goto debug_stop;
1439 }
1440 vg_assert(VG_(dispatch_ctr) == 0);
1441 break;
1442
1443 case VG_TRC_UNRESUMABLE_SIGNAL:
1444 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1445 away. Again, do nothing, so we wind up back at Phase
1446 1, whereupon the signal will be "delivered". */
1447 break;
1448
sewardje663cb92002-04-12 10:26:32 +00001449 case VG_TRC_EBP_JMP_CLIENTREQ:
1450 /* Do a client request for the vthread tid. Note that
1451 some requests will have been handled by
1452 maybe_do_trivial_clientreq(), so we don't expect to see
1453 those here.
1454 */
sewardj54cacf02002-04-12 23:24:59 +00001455 /* The thread's %EAX points at an arg block, the first
1456 word of which is the request code. */
sewardj018f7622002-05-15 21:13:39 +00001457 request_code = ((UInt*)(VG_(threads)[tid].m_eax))[0];
sewardje663cb92002-04-12 10:26:32 +00001458 if (0) {
sewardj54cacf02002-04-12 23:24:59 +00001459 VG_(sprintf)(msg_buf, "request 0x%x", request_code );
sewardje663cb92002-04-12 10:26:32 +00001460 print_sched_event(tid, msg_buf);
1461 }
1462 /* Do a non-trivial client request for thread tid. tid's
1463 %EAX points to a short vector of argument words, the
1464 first of which is the request code. The result of the
1465 request is put in tid's %EDX. Alternatively, perhaps
1466 the request causes tid to become non-runnable and/or
1467 other blocked threads become runnable. In general we
1468 can and often do mess with the state of arbitrary
1469 threads at this point. */
sewardj7e87e382002-05-03 19:09:05 +00001470 do_nontrivial_clientreq(tid);
sewardje663cb92002-04-12 10:26:32 +00001471 break;
1472
1473 default:
1474 VG_(printf)("\ntrc = %d\n", trc);
1475 VG_(panic)("VG_(scheduler), phase 3: "
1476 "unexpected thread return code");
1477 /* NOTREACHED */
1478 break;
1479
1480 } /* switch (trc) */
1481
1482 /* That completes Phase 3 of 3. Return now to the top of the
1483 main scheduler loop, to Phase 1 of 3. */
1484
1485 } /* top-level scheduler loop */
1486
1487
1488 /* NOTREACHED */
1489 VG_(panic)("scheduler: post-main-loop ?!");
1490 /* NOTREACHED */
1491
1492 debug_stop:
1493 /* If we exited because of a debug stop, print the translation
1494 of the last block executed -- by translating it again, and
1495 throwing away the result. */
1496 VG_(printf)(
1497 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001498 VG_(translate)( &VG_(threads)[tid],
1499 VG_(threads)[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001500 VG_(printf)("\n");
1501 VG_(printf)(
1502 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1503
1504 return VgSrc_BbsDone;
1505}
1506
1507
1508/* ---------------------------------------------------------------------
1509 The pthread implementation.
1510 ------------------------------------------------------------------ */
1511
1512#include <pthread.h>
1513#include <errno.h>
1514
sewardjbf290b92002-05-01 02:28:01 +00001515#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001516 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001517
1518/* /usr/include/bits/pthreadtypes.h:
1519 typedef unsigned long int pthread_t;
1520*/
1521
sewardje663cb92002-04-12 10:26:32 +00001522
sewardj604ec3c2002-04-18 22:38:41 +00001523/* -----------------------------------------------------------
1524 Thread CREATION, JOINAGE and CANCELLATION.
1525 -------------------------------------------------------- */
1526
sewardjb48e5002002-05-13 00:16:03 +00001527/* Release resources and generally clean up once a thread has finally
1528 disappeared. */
1529static
1530void cleanup_after_thread_exited ( ThreadId tid )
1531{
sewardj3a951cf2002-05-15 22:25:47 +00001532 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001533 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1534 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
sewardjb48e5002002-05-13 00:16:03 +00001535 /* Mark its stack no-access */
1536 if (VG_(clo_instrument) && tid != 1)
sewardj018f7622002-05-15 21:13:39 +00001537 VGM_(make_noaccess)( VG_(threads)[tid].stack_base,
1538 VG_(threads)[tid].stack_size );
sewardjb48e5002002-05-13 00:16:03 +00001539 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001540 thread, and get rid of signal handlers specifically arranged for
1541 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001542 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001543 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardjb48e5002002-05-13 00:16:03 +00001544}
1545
1546
sewardje663cb92002-04-12 10:26:32 +00001547static
sewardj853f55d2002-04-26 00:27:53 +00001548void do_pthread_cancel ( ThreadId tid,
sewardje663cb92002-04-12 10:26:32 +00001549 pthread_t tid_cancellee )
1550{
1551 Char msg_buf[100];
sewardj853f55d2002-04-26 00:27:53 +00001552
sewardjb48e5002002-05-13 00:16:03 +00001553 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001554 vg_assert(VG_(threads)[tid].status != VgTs_Empty);
sewardj853f55d2002-04-26 00:27:53 +00001555
sewardjb48e5002002-05-13 00:16:03 +00001556 if (!VG_(is_valid_tid)(tid_cancellee)
sewardj018f7622002-05-15 21:13:39 +00001557 || VG_(threads)[tid_cancellee].status == VgTs_Empty) {
sewardjc3bd5f52002-05-01 03:24:23 +00001558 SET_EDX(tid, ESRCH);
sewardj853f55d2002-04-26 00:27:53 +00001559 return;
1560 }
1561
sewardje663cb92002-04-12 10:26:32 +00001562 /* We want make is appear that this thread has returned to
1563 do_pthread_create_bogusRA with PTHREAD_CANCELED as the
1564 return value. So: simple: put PTHREAD_CANCELED into %EAX
1565 and &do_pthread_create_bogusRA into %EIP and keep going! */
sewardj8937c812002-04-12 20:12:20 +00001566 if (VG_(clo_trace_sched)) {
sewardj853f55d2002-04-26 00:27:53 +00001567 VG_(sprintf)(msg_buf, "cancelled by %d", tid);
sewardje663cb92002-04-12 10:26:32 +00001568 print_sched_event(tid_cancellee, msg_buf);
1569 }
sewardj018f7622002-05-15 21:13:39 +00001570 VG_(threads)[tid_cancellee].m_eax = (UInt)PTHREAD_CANCELED;
1571 VG_(threads)[tid_cancellee].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
1572 VG_(threads)[tid_cancellee].status = VgTs_Runnable;
sewardj853f55d2002-04-26 00:27:53 +00001573
1574 /* We return with success (0). */
sewardjc3bd5f52002-05-01 03:24:23 +00001575 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001576}
1577
1578
sewardj3b5d8862002-04-20 13:53:23 +00001579static
1580void do_pthread_exit ( ThreadId tid, void* retval )
1581{
1582 Char msg_buf[100];
1583 /* We want make is appear that this thread has returned to
1584 do_pthread_create_bogusRA with retval as the
1585 return value. So: simple: put retval into %EAX
1586 and &do_pthread_create_bogusRA into %EIP and keep going! */
1587 if (VG_(clo_trace_sched)) {
1588 VG_(sprintf)(msg_buf, "exiting with %p", retval);
1589 print_sched_event(tid, msg_buf);
1590 }
sewardj018f7622002-05-15 21:13:39 +00001591 VG_(threads)[tid].m_eax = (UInt)retval;
1592 VG_(threads)[tid].m_eip = (UInt)&VG_(pthreadreturn_bogusRA);
1593 VG_(threads)[tid].status = VgTs_Runnable;
sewardj3b5d8862002-04-20 13:53:23 +00001594}
1595
sewardje663cb92002-04-12 10:26:32 +00001596
1597/* Thread tid is exiting, by returning from the function it was
sewardjbc5b99f2002-04-13 00:08:51 +00001598 created with. Or possibly due to pthread_exit or cancellation.
1599 The main complication here is to resume any thread waiting to join
1600 with this one. */
sewardje663cb92002-04-12 10:26:32 +00001601static
sewardjbc5b99f2002-04-13 00:08:51 +00001602void handle_pthread_return ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00001603{
1604 ThreadId jnr; /* joiner, the thread calling pthread_join. */
1605 UInt* jnr_args;
1606 void** jnr_thread_return;
1607 Char msg_buf[100];
1608
1609 /* Mark it as not in use. Leave the stack in place so the next
1610 user of this slot doesn't reallocate it. */
sewardjb48e5002002-05-13 00:16:03 +00001611 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001612 vg_assert(VG_(threads)[tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00001613
sewardj018f7622002-05-15 21:13:39 +00001614 VG_(threads)[tid].retval = retval;
sewardje663cb92002-04-12 10:26:32 +00001615
sewardj018f7622002-05-15 21:13:39 +00001616 if (VG_(threads)[tid].joiner == VG_INVALID_THREADID) {
sewardje663cb92002-04-12 10:26:32 +00001617 /* No one has yet done a join on me */
sewardj018f7622002-05-15 21:13:39 +00001618 VG_(threads)[tid].status = VgTs_WaitJoiner;
sewardj8937c812002-04-12 20:12:20 +00001619 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001620 VG_(sprintf)(msg_buf,
1621 "root fn returns, waiting for a call pthread_join(%d)",
1622 tid);
1623 print_sched_event(tid, msg_buf);
1624 }
1625 } else {
1626 /* Some is waiting; make their join call return with success,
1627 putting my exit code in the place specified by the caller's
1628 thread_return param. This is all very horrible, since we
1629 need to consult the joiner's arg block -- pointed to by its
1630 %EAX -- in order to extract the 2nd param of its pthread_join
1631 call. TODO: free properly the slot (also below).
1632 */
sewardj018f7622002-05-15 21:13:39 +00001633 jnr = VG_(threads)[tid].joiner;
sewardjb48e5002002-05-13 00:16:03 +00001634 vg_assert(VG_(is_valid_tid)(jnr));
sewardj018f7622002-05-15 21:13:39 +00001635 vg_assert(VG_(threads)[jnr].status == VgTs_WaitJoinee);
1636 jnr_args = (UInt*)VG_(threads)[jnr].m_eax;
sewardje663cb92002-04-12 10:26:32 +00001637 jnr_thread_return = (void**)(jnr_args[2]);
1638 if (jnr_thread_return != NULL)
sewardj018f7622002-05-15 21:13:39 +00001639 *jnr_thread_return = VG_(threads)[tid].retval;
sewardjc3bd5f52002-05-01 03:24:23 +00001640 SET_EDX(jnr, 0); /* success */
sewardj018f7622002-05-15 21:13:39 +00001641 VG_(threads)[jnr].status = VgTs_Runnable;
1642 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
sewardjb48e5002002-05-13 00:16:03 +00001643 cleanup_after_thread_exited ( tid );
sewardj8937c812002-04-12 20:12:20 +00001644 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001645 VG_(sprintf)(msg_buf,
1646 "root fn returns, to find a waiting pthread_join(%d)", tid);
1647 print_sched_event(tid, msg_buf);
1648 VG_(sprintf)(msg_buf,
1649 "my pthread_join(%d) returned; resuming", tid);
1650 print_sched_event(jnr, msg_buf);
1651 }
1652 }
1653
1654 /* Return value is irrelevant; this thread will not get
1655 rescheduled. */
1656}
1657
1658
1659static
1660void do_pthread_join ( ThreadId tid, ThreadId jee, void** thread_return )
1661{
1662 Char msg_buf[100];
1663
1664 /* jee, the joinee, is the thread specified as an arg in thread
1665 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00001666 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001667 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001668
1669 if (jee == tid) {
sewardjc3bd5f52002-05-01 03:24:23 +00001670 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00001671 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001672 return;
1673 }
1674
1675 if (jee < 0
1676 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00001677 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00001678 /* Invalid thread to join to. */
sewardjc3bd5f52002-05-01 03:24:23 +00001679 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00001680 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001681 return;
1682 }
1683
sewardj018f7622002-05-15 21:13:39 +00001684 if (VG_(threads)[jee].joiner != VG_INVALID_THREADID) {
sewardje663cb92002-04-12 10:26:32 +00001685 /* Someone already did join on this thread */
sewardjc3bd5f52002-05-01 03:24:23 +00001686 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00001687 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001688 return;
1689 }
1690
sewardj018f7622002-05-15 21:13:39 +00001691 /* if (VG_(threads)[jee].detached) ... */
sewardje663cb92002-04-12 10:26:32 +00001692
1693 /* Perhaps the joinee has already finished? If so return
1694 immediately with its return code, and free up the slot. TODO:
1695 free it properly (also above). */
sewardj018f7622002-05-15 21:13:39 +00001696 if (VG_(threads)[jee].status == VgTs_WaitJoiner) {
1697 vg_assert(VG_(threads)[jee].joiner == VG_INVALID_THREADID);
sewardjc3bd5f52002-05-01 03:24:23 +00001698 SET_EDX(tid, 0); /* success */
1699 if (thread_return != NULL) {
sewardj018f7622002-05-15 21:13:39 +00001700 *thread_return = VG_(threads)[jee].retval;
sewardjc3bd5f52002-05-01 03:24:23 +00001701 /* Not really right, since it makes the thread's return value
1702 appear to be defined even if it isn't. */
1703 if (VG_(clo_instrument))
1704 VGM_(make_readable)( (Addr)thread_return, sizeof(void*) );
1705 }
sewardj018f7622002-05-15 21:13:39 +00001706 VG_(threads)[tid].status = VgTs_Runnable;
1707 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
sewardjb48e5002002-05-13 00:16:03 +00001708 cleanup_after_thread_exited ( jee );
sewardj8937c812002-04-12 20:12:20 +00001709 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001710 VG_(sprintf)(msg_buf,
1711 "someone called pthread_join() on me; bye!");
1712 print_sched_event(jee, msg_buf);
1713 VG_(sprintf)(msg_buf,
1714 "my pthread_join(%d) returned immediately",
1715 jee );
1716 print_sched_event(tid, msg_buf);
1717 }
1718 return;
1719 }
1720
1721 /* Ok, so we'll have to wait on jee. */
sewardj018f7622002-05-15 21:13:39 +00001722 VG_(threads)[jee].joiner = tid;
1723 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj8937c812002-04-12 20:12:20 +00001724 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001725 VG_(sprintf)(msg_buf,
1726 "blocking on call of pthread_join(%d)", jee );
1727 print_sched_event(tid, msg_buf);
1728 }
1729 /* So tid's join call does not return just now. */
1730}
1731
1732
1733static
1734void do_pthread_create ( ThreadId parent_tid,
1735 pthread_t* thread,
1736 pthread_attr_t* attr,
1737 void* (*start_routine)(void *),
1738 void* arg )
1739{
sewardj5f07b662002-04-23 16:52:51 +00001740 Int i;
sewardje663cb92002-04-12 10:26:32 +00001741 Addr new_stack;
1742 UInt new_stk_szb;
1743 ThreadId tid;
1744 Char msg_buf[100];
1745
1746 /* Paranoia ... */
1747 vg_assert(sizeof(pthread_t) == sizeof(UInt));
1748
sewardj018f7622002-05-15 21:13:39 +00001749 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00001750
sewardj1e8cdc92002-04-18 11:37:52 +00001751 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00001752
1753 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00001754 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00001755 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001756
1757 /* Copy the parent's CPU state into the child's, in a roundabout
1758 way (via baseBlock). */
1759 VG_(load_thread_state)(parent_tid);
1760 VG_(save_thread_state)(tid);
1761
1762 /* Consider allocating the child a stack, if the one it already has
1763 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00001764 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00001765
sewardj018f7622002-05-15 21:13:39 +00001766 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00001767 /* Again, for good measure :) We definitely don't want to be
1768 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00001769 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00001770 /* for now, we don't handle the case of anything other than
1771 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00001772 vg_assert(VG_(threads)[tid].stack_size == 0);
1773 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje663cb92002-04-12 10:26:32 +00001774 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb );
sewardj018f7622002-05-15 21:13:39 +00001775 VG_(threads)[tid].stack_base = new_stack;
1776 VG_(threads)[tid].stack_size = new_stk_szb;
1777 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00001778 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00001779 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00001780 }
sewardj1e8cdc92002-04-18 11:37:52 +00001781
sewardj018f7622002-05-15 21:13:39 +00001782 VG_(threads)[tid].m_esp
1783 = VG_(threads)[tid].stack_base
1784 + VG_(threads)[tid].stack_size
sewardj1e8cdc92002-04-18 11:37:52 +00001785 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
1786
sewardje663cb92002-04-12 10:26:32 +00001787 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00001788 VGM_(make_noaccess)( VG_(threads)[tid].m_esp,
sewardje663cb92002-04-12 10:26:32 +00001789 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
1790
1791 /* push arg */
sewardj018f7622002-05-15 21:13:39 +00001792 VG_(threads)[tid].m_esp -= 4;
1793 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)arg;
sewardje663cb92002-04-12 10:26:32 +00001794
1795 /* push (magical) return address */
sewardj018f7622002-05-15 21:13:39 +00001796 VG_(threads)[tid].m_esp -= 4;
1797 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)VG_(pthreadreturn_bogusRA);
sewardje663cb92002-04-12 10:26:32 +00001798
1799 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00001800 VGM_(make_readable)( VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00001801
1802 /* this is where we start */
sewardj018f7622002-05-15 21:13:39 +00001803 VG_(threads)[tid].m_eip = (UInt)start_routine;
sewardje663cb92002-04-12 10:26:32 +00001804
sewardj8937c812002-04-12 20:12:20 +00001805 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001806 VG_(sprintf)(msg_buf,
1807 "new thread, created by %d", parent_tid );
1808 print_sched_event(tid, msg_buf);
1809 }
1810
1811 /* store the thread id in *thread. */
1812 // if (VG_(clo_instrument))
1813 // ***** CHECK *thread is writable
1814 *thread = (pthread_t)tid;
sewardjc3bd5f52002-05-01 03:24:23 +00001815 if (VG_(clo_instrument))
1816 VGM_(make_readable)( (Addr)thread, sizeof(pthread_t) );
sewardje663cb92002-04-12 10:26:32 +00001817
sewardj018f7622002-05-15 21:13:39 +00001818 VG_(threads)[tid].associated_mx = NULL;
1819 VG_(threads)[tid].associated_cv = NULL;
1820 VG_(threads)[tid].joiner = VG_INVALID_THREADID;
1821 VG_(threads)[tid].status = VgTs_Runnable;
sewardj604ec3c2002-04-18 22:38:41 +00001822
sewardj5f07b662002-04-23 16:52:51 +00001823 for (i = 0; i < VG_N_THREAD_KEYS; i++)
sewardj018f7622002-05-15 21:13:39 +00001824 VG_(threads)[tid].specifics[i] = NULL;
sewardj5f07b662002-04-23 16:52:51 +00001825
sewardj018f7622002-05-15 21:13:39 +00001826 /* We inherit our parent's signal mask. */
1827 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
1828 VG_(ksigemptyset)(&VG_(threads)[i].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00001829
sewardj604ec3c2002-04-18 22:38:41 +00001830 /* return zero */
sewardj1de04f12002-05-10 02:16:19 +00001831 SET_EDX(parent_tid, 0); /* success */
sewardje663cb92002-04-12 10:26:32 +00001832}
1833
1834
sewardj604ec3c2002-04-18 22:38:41 +00001835/* -----------------------------------------------------------
1836 MUTEXes
1837 -------------------------------------------------------- */
1838
sewardj604ec3c2002-04-18 22:38:41 +00001839/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00001840 typedef struct
1841 {
1842 int __m_reserved; -- Reserved for future use
1843 int __m_count; -- Depth of recursive locking
1844 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
1845 int __m_kind; -- Mutex kind: fast, recursive or errcheck
1846 struct _pthread_fastlock __m_lock; -- Underlying fast lock
1847 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00001848
sewardj6072c362002-04-19 14:40:57 +00001849 #define PTHREAD_MUTEX_INITIALIZER \
1850 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
1851 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
1852 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
1853 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
1854 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
1855 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
1856 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00001857
sewardj6072c362002-04-19 14:40:57 +00001858 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00001859
sewardj6072c362002-04-19 14:40:57 +00001860 __m_kind never changes and indicates whether or not it is recursive.
1861
1862 __m_count indicates the lock count; if 0, the mutex is not owned by
1863 anybody.
1864
1865 __m_owner has a ThreadId value stuffed into it. We carefully arrange
1866 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
1867 statically initialised mutexes correctly appear
1868 to belong to nobody.
1869
1870 In summary, a not-in-use mutex is distinguised by having __m_owner
1871 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
1872 conditions holds, the other should too.
1873
1874 There is no linked list of threads waiting for this mutex. Instead
1875 a thread in WaitMX state points at the mutex with its waited_on_mx
1876 field. This makes _unlock() inefficient, but simple to implement the
1877 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00001878
sewardj604ec3c2002-04-18 22:38:41 +00001879 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00001880 deals with that for us.
1881*/
sewardje663cb92002-04-12 10:26:32 +00001882
sewardj3b5d8862002-04-20 13:53:23 +00001883/* Helper fns ... */
1884static
1885void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
1886 Char* caller )
1887{
1888 Int i;
1889 Char msg_buf[100];
1890
1891 /* Find some arbitrary thread waiting on this mutex, and make it
1892 runnable. If none are waiting, mark the mutex as not held. */
1893 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001894 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00001895 continue;
sewardj018f7622002-05-15 21:13:39 +00001896 if (VG_(threads)[i].status == VgTs_WaitMX
1897 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00001898 break;
1899 }
1900
1901 vg_assert(i <= VG_N_THREADS);
1902 if (i == VG_N_THREADS) {
1903 /* Nobody else is waiting on it. */
1904 mutex->__m_count = 0;
1905 mutex->__m_owner = VG_INVALID_THREADID;
1906 } else {
1907 /* Notionally transfer the hold to thread i, whose
1908 pthread_mutex_lock() call now returns with 0 (success). */
1909 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00001910 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00001911 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00001912 VG_(threads)[i].status = VgTs_Runnable;
1913 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00001914 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00001915
1916 if (VG_(clo_trace_pthread_level) >= 1) {
1917 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
1918 caller, mutex );
1919 print_pthread_event(i, msg_buf);
1920 }
1921 }
1922}
1923
sewardje663cb92002-04-12 10:26:32 +00001924
1925static
sewardj30671ff2002-04-21 00:13:57 +00001926void do_pthread_mutex_lock( ThreadId tid,
1927 Bool is_trylock,
sewardjd7fd4d22002-04-24 01:57:27 +00001928 void* /* pthread_mutex_t* */ mutexV )
sewardje663cb92002-04-12 10:26:32 +00001929{
sewardj30671ff2002-04-21 00:13:57 +00001930 Char msg_buf[100];
1931 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00001932 = is_trylock ? "pthread_mutex_trylock"
1933 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00001934
sewardjd7fd4d22002-04-24 01:57:27 +00001935 pthread_mutex_t* mutex = (pthread_mutex_t*)mutexV;
1936
sewardj604ec3c2002-04-18 22:38:41 +00001937 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00001938 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00001939 print_pthread_event(tid, msg_buf);
1940 }
1941
1942 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00001943 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00001944 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001945
1946 /* POSIX doesn't mandate this, but for sanity ... */
1947 if (mutex == NULL) {
sewardj8e651d72002-05-10 21:00:19 +00001948 /* VG_(printf)("NULL mutex\n"); */
sewardjc3bd5f52002-05-01 03:24:23 +00001949 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00001950 return;
1951 }
1952
sewardj604ec3c2002-04-18 22:38:41 +00001953 /* More paranoia ... */
1954 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00001955# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00001956 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00001957 case PTHREAD_MUTEX_ADAPTIVE_NP:
1958# endif
sewardja1679dd2002-05-10 22:31:40 +00001959# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00001960 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00001961# endif
sewardj604ec3c2002-04-18 22:38:41 +00001962 case PTHREAD_MUTEX_RECURSIVE_NP:
1963 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00001964 if (mutex->__m_count >= 0) break;
1965 /* else fall thru */
1966 default:
sewardj8e651d72002-05-10 21:00:19 +00001967 /* VG_(printf)("unknown __m_kind %d in mutex\n", mutex->__m_kind); */
sewardjc3bd5f52002-05-01 03:24:23 +00001968 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00001969 return;
sewardje663cb92002-04-12 10:26:32 +00001970 }
1971
sewardj604ec3c2002-04-18 22:38:41 +00001972 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00001973
sewardjb48e5002002-05-13 00:16:03 +00001974 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00001975
1976 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00001977 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00001978 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00001979 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00001980 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00001981 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00001982 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00001983 if (0)
1984 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
1985 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00001986 return;
1987 } else {
sewardj30671ff2002-04-21 00:13:57 +00001988 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00001989 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00001990 else
sewardjc3bd5f52002-05-01 03:24:23 +00001991 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00001992 return;
1993 }
1994 } else {
sewardj6072c362002-04-19 14:40:57 +00001995 /* Someone else has it; we have to wait. Mark ourselves
1996 thusly. */
sewardj05553872002-04-20 20:53:17 +00001997 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00001998 if (is_trylock) {
1999 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002000 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002001 } else {
sewardj018f7622002-05-15 21:13:39 +00002002 VG_(threads)[tid].status = VgTs_WaitMX;
2003 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002004 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002005 if (VG_(clo_trace_pthread_level) >= 1) {
2006 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2007 caller, mutex );
2008 print_pthread_event(tid, msg_buf);
2009 }
2010 }
sewardje663cb92002-04-12 10:26:32 +00002011 return;
2012 }
sewardjf8f819e2002-04-17 23:21:37 +00002013
sewardje663cb92002-04-12 10:26:32 +00002014 } else {
sewardj6072c362002-04-19 14:40:57 +00002015 /* Nobody owns it. Sanity check ... */
2016 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002017 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002018 mutex->__m_count = 1;
2019 mutex->__m_owner = (_pthread_descr)tid;
sewardj018f7622002-05-15 21:13:39 +00002020 vg_assert(VG_(threads)[tid].associated_mx == NULL);
sewardje663cb92002-04-12 10:26:32 +00002021 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002022 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002023 }
sewardjf8f819e2002-04-17 23:21:37 +00002024
sewardje663cb92002-04-12 10:26:32 +00002025}
2026
2027
2028static
2029void do_pthread_mutex_unlock ( ThreadId tid,
sewardjd7fd4d22002-04-24 01:57:27 +00002030 void* /* pthread_mutex_t* */ mutexV )
sewardje663cb92002-04-12 10:26:32 +00002031{
sewardj3b5d8862002-04-20 13:53:23 +00002032 Char msg_buf[100];
sewardjd7fd4d22002-04-24 01:57:27 +00002033 pthread_mutex_t* mutex = (pthread_mutex_t*)mutexV;
sewardje663cb92002-04-12 10:26:32 +00002034
sewardj45b4b372002-04-16 22:50:32 +00002035 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002036 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002037 print_pthread_event(tid, msg_buf);
2038 }
2039
sewardj604ec3c2002-04-18 22:38:41 +00002040 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002041 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002042 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002043
2044 if (mutex == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002045 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002046 return;
2047 }
2048
2049 /* More paranoia ... */
2050 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002051# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002052 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002053 case PTHREAD_MUTEX_ADAPTIVE_NP:
2054# endif
sewardja1679dd2002-05-10 22:31:40 +00002055# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002056 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002057# endif
sewardj604ec3c2002-04-18 22:38:41 +00002058 case PTHREAD_MUTEX_RECURSIVE_NP:
2059 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002060 if (mutex->__m_count >= 0) break;
2061 /* else fall thru */
2062 default:
sewardjc3bd5f52002-05-01 03:24:23 +00002063 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002064 return;
2065 }
sewardje663cb92002-04-12 10:26:32 +00002066
2067 /* Barf if we don't currently hold the mutex. */
sewardj604ec3c2002-04-18 22:38:41 +00002068 if (mutex->__m_count == 0 /* nobody holds it */
2069 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardjc3bd5f52002-05-01 03:24:23 +00002070 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002071 return;
2072 }
2073
sewardjf8f819e2002-04-17 23:21:37 +00002074 /* If it's a multiply-locked recursive mutex, just decrement the
2075 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002076 if (mutex->__m_count > 1) {
2077 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2078 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002079 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002080 return;
2081 }
2082
sewardj604ec3c2002-04-18 22:38:41 +00002083 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002084 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002085 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002086 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002087
sewardj3b5d8862002-04-20 13:53:23 +00002088 /* Release at max one thread waiting on this mutex. */
2089 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002090
sewardj3b5d8862002-04-20 13:53:23 +00002091 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002092 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002093}
2094
2095
sewardj6072c362002-04-19 14:40:57 +00002096/* -----------------------------------------------------------
2097 CONDITION VARIABLES
2098 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002099
sewardj6072c362002-04-19 14:40:57 +00002100/* The relevant native types are as follows:
2101 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002102
sewardj6072c362002-04-19 14:40:57 +00002103 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2104 typedef struct
2105 {
2106 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2107 _pthread_descr __c_waiting; -- Threads waiting on this condition
2108 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002109
sewardj6072c362002-04-19 14:40:57 +00002110 -- Attribute for conditionally variables.
2111 typedef struct
2112 {
2113 int __dummy;
2114 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002115
sewardj6072c362002-04-19 14:40:57 +00002116 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002117
sewardj3b5d8862002-04-20 13:53:23 +00002118 We don't use any fields of pthread_cond_t for anything at all.
2119 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002120
2121 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002122 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002123
sewardj77e466c2002-04-14 02:29:29 +00002124
sewardj5f07b662002-04-23 16:52:51 +00002125static
2126void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2127{
2128 Char msg_buf[100];
2129 pthread_mutex_t* mx;
2130 pthread_cond_t* cv;
2131
sewardjb48e5002002-05-13 00:16:03 +00002132 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002133 && VG_(threads)[tid].status == VgTs_WaitCV
2134 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2135 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002136 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002137 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002138 vg_assert(cv != NULL);
2139
2140 if (mx->__m_owner == VG_INVALID_THREADID) {
2141 /* Currently unheld; hand it out to thread tid. */
2142 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002143 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002144 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002145 VG_(threads)[tid].associated_cv = NULL;
2146 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002147 mx->__m_owner = (_pthread_descr)tid;
2148 mx->__m_count = 1;
2149
2150 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002151 VG_(sprintf)(msg_buf,
2152 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2153 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002154 print_pthread_event(tid, msg_buf);
2155 }
2156 } else {
2157 /* Currently held. Make thread tid be blocked on it. */
2158 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002159 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002160 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002161 VG_(threads)[tid].associated_cv = NULL;
2162 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002163 if (VG_(clo_trace_pthread_level) >= 1) {
2164 VG_(sprintf)(msg_buf,
2165 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2166 cv, mx );
2167 print_pthread_event(tid, msg_buf);
2168 }
2169
2170 }
2171}
2172
2173
sewardj3b5d8862002-04-20 13:53:23 +00002174static
2175void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2176 Int n_to_release,
2177 Char* caller )
2178{
2179 Int i;
2180 Char msg_buf[100];
2181 pthread_mutex_t* mx;
2182
2183 while (True) {
2184 if (n_to_release == 0)
2185 return;
2186
2187 /* Find a thread waiting on this CV. */
2188 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002189 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002190 continue;
sewardj018f7622002-05-15 21:13:39 +00002191 if (VG_(threads)[i].status == VgTs_WaitCV
2192 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002193 break;
2194 }
2195 vg_assert(i <= VG_N_THREADS);
2196
2197 if (i == VG_N_THREADS) {
2198 /* Nobody else is waiting on it. */
2199 return;
2200 }
2201
sewardj018f7622002-05-15 21:13:39 +00002202 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002203 vg_assert(mx != NULL);
2204
2205 if (mx->__m_owner == VG_INVALID_THREADID) {
2206 /* Currently unheld; hand it out to thread i. */
2207 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002208 VG_(threads)[i].status = VgTs_Runnable;
2209 VG_(threads)[i].associated_cv = NULL;
2210 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002211 mx->__m_owner = (_pthread_descr)i;
2212 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002213 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002214
2215 if (VG_(clo_trace_pthread_level) >= 1) {
2216 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2217 caller, cond, mx );
2218 print_pthread_event(i, msg_buf);
2219 }
2220
2221 } else {
2222 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002223 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002224 VG_(threads)[i].status = VgTs_WaitMX;
2225 VG_(threads)[i].associated_cv = NULL;
2226 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002227 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002228
2229 if (VG_(clo_trace_pthread_level) >= 1) {
2230 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2231 caller, cond, mx );
2232 print_pthread_event(i, msg_buf);
2233 }
2234
2235 }
2236
2237 n_to_release--;
2238 }
2239}
2240
2241
2242static
2243void do_pthread_cond_wait ( ThreadId tid,
2244 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002245 pthread_mutex_t *mutex,
2246 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002247{
2248 Char msg_buf[100];
2249
sewardj5f07b662002-04-23 16:52:51 +00002250 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2251 ms_end is the ending millisecond. */
2252
sewardj3b5d8862002-04-20 13:53:23 +00002253 /* pre: mutex should be a valid mutex and owned by tid. */
2254 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002255 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2256 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002257 print_pthread_event(tid, msg_buf);
2258 }
2259
2260 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002261 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002262 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002263
2264 if (mutex == NULL || cond == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002265 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002266 return;
2267 }
2268
2269 /* More paranoia ... */
2270 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002271# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002272 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002273 case PTHREAD_MUTEX_ADAPTIVE_NP:
2274# endif
sewardja1679dd2002-05-10 22:31:40 +00002275# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002276 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002277# endif
sewardj3b5d8862002-04-20 13:53:23 +00002278 case PTHREAD_MUTEX_RECURSIVE_NP:
2279 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002280 if (mutex->__m_count >= 0) break;
2281 /* else fall thru */
2282 default:
sewardjc3bd5f52002-05-01 03:24:23 +00002283 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002284 return;
2285 }
2286
2287 /* Barf if we don't currently hold the mutex. */
2288 if (mutex->__m_count == 0 /* nobody holds it */
2289 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardjc3bd5f52002-05-01 03:24:23 +00002290 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002291 return;
2292 }
2293
2294 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002295 VG_(threads)[tid].status = VgTs_WaitCV;
2296 VG_(threads)[tid].associated_cv = cond;
2297 VG_(threads)[tid].associated_mx = mutex;
2298 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002299
2300 if (VG_(clo_trace_pthread_level) >= 1) {
2301 VG_(sprintf)(msg_buf,
2302 "pthread_cond_wait cv %p, mx %p: BLOCK",
2303 cond, mutex );
2304 print_pthread_event(tid, msg_buf);
2305 }
2306
2307 /* Release the mutex. */
2308 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2309}
2310
2311
2312static
2313void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2314 Bool broadcast,
2315 pthread_cond_t *cond )
2316{
2317 Char msg_buf[100];
2318 Char* caller
2319 = broadcast ? "pthread_cond_broadcast"
2320 : "pthread_cond_signal ";
2321
2322 if (VG_(clo_trace_pthread_level) >= 2) {
2323 VG_(sprintf)(msg_buf, "%s cv %p ...",
2324 caller, cond );
2325 print_pthread_event(tid, msg_buf);
2326 }
2327
2328 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002329 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002330 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002331
2332 if (cond == NULL) {
sewardjc3bd5f52002-05-01 03:24:23 +00002333 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002334 return;
2335 }
2336
2337 release_N_threads_waiting_on_cond (
2338 cond,
2339 broadcast ? VG_N_THREADS : 1,
2340 caller
2341 );
2342
sewardjc3bd5f52002-05-01 03:24:23 +00002343 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002344}
2345
sewardj77e466c2002-04-14 02:29:29 +00002346
sewardj5f07b662002-04-23 16:52:51 +00002347/* -----------------------------------------------------------
2348 THREAD SPECIFIC DATA
2349 -------------------------------------------------------- */
2350
2351static __inline__
2352Bool is_valid_key ( ThreadKey k )
2353{
2354 /* k unsigned; hence no < 0 check */
2355 if (k >= VG_N_THREAD_KEYS) return False;
2356 if (!vg_thread_keys[k].inuse) return False;
2357 return True;
2358}
2359
2360static
2361void do_pthread_key_create ( ThreadId tid,
2362 pthread_key_t* key,
2363 void (*destructor)(void*) )
2364{
2365 Int i;
2366 Char msg_buf[100];
2367
2368 if (VG_(clo_trace_pthread_level) >= 1) {
2369 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2370 key, destructor );
2371 print_pthread_event(tid, msg_buf);
2372 }
2373
2374 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002375 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002376 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002377
2378 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2379 if (!vg_thread_keys[i].inuse)
2380 break;
2381
2382 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002383 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002384 return;
2385 */
2386 VG_(panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2387 " increase and recompile");
2388 }
2389
2390 vg_thread_keys[i].inuse = True;
sewardjc3bd5f52002-05-01 03:24:23 +00002391
sewardj5f07b662002-04-23 16:52:51 +00002392 /* TODO: check key for addressibility */
2393 *key = i;
sewardjc3bd5f52002-05-01 03:24:23 +00002394 if (VG_(clo_instrument))
2395 VGM_(make_readable)( (Addr)key, sizeof(pthread_key_t) );
2396
2397 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002398}
2399
2400
2401static
2402void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2403{
2404 Char msg_buf[100];
2405 if (VG_(clo_trace_pthread_level) >= 1) {
2406 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2407 key );
2408 print_pthread_event(tid, msg_buf);
2409 }
2410
sewardjb48e5002002-05-13 00:16:03 +00002411 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002412 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002413
2414 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002415 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002416 return;
2417 }
2418
2419 vg_thread_keys[key].inuse = False;
2420
2421 /* Optional. We're not required to do this, although it shouldn't
2422 make any difference to programs which use the key/specifics
2423 functions correctly. */
sewardj3b13f0e2002-04-25 20:17:29 +00002424# if 1
sewardj5f07b662002-04-23 16:52:51 +00002425 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00002426 if (VG_(threads)[tid].status != VgTs_Empty)
2427 VG_(threads)[tid].specifics[key] = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002428 }
sewardj3b13f0e2002-04-25 20:17:29 +00002429# endif
sewardj5f07b662002-04-23 16:52:51 +00002430}
2431
2432
2433static
2434void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
2435{
2436 Char msg_buf[100];
2437 if (VG_(clo_trace_pthread_level) >= 1) {
2438 VG_(sprintf)(msg_buf, "pthread_getspecific key %d",
2439 key );
2440 print_pthread_event(tid, msg_buf);
2441 }
2442
sewardjb48e5002002-05-13 00:16:03 +00002443 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002444 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002445
2446 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002447 SET_EDX(tid, (UInt)NULL);
sewardj5f07b662002-04-23 16:52:51 +00002448 return;
2449 }
2450
sewardj018f7622002-05-15 21:13:39 +00002451 SET_EDX(tid, (UInt)VG_(threads)[tid].specifics[key]);
sewardj5f07b662002-04-23 16:52:51 +00002452}
2453
2454
2455static
2456void do_pthread_setspecific ( ThreadId tid,
2457 pthread_key_t key,
2458 void *pointer )
2459{
2460 Char msg_buf[100];
2461 if (VG_(clo_trace_pthread_level) >= 1) {
2462 VG_(sprintf)(msg_buf, "pthread_setspecific key %d, ptr %p",
2463 key, pointer );
2464 print_pthread_event(tid, msg_buf);
2465 }
2466
sewardjb48e5002002-05-13 00:16:03 +00002467 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002468 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002469
2470 if (!is_valid_key(key)) {
sewardjc3bd5f52002-05-01 03:24:23 +00002471 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002472 return;
2473 }
2474
sewardj018f7622002-05-15 21:13:39 +00002475 VG_(threads)[tid].specifics[key] = pointer;
sewardjc3bd5f52002-05-01 03:24:23 +00002476 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002477}
2478
2479
sewardjb48e5002002-05-13 00:16:03 +00002480/* ---------------------------------------------------
2481 SIGNALS
2482 ------------------------------------------------ */
2483
2484/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002485 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2486 for OK and 1 for some kind of addressing error, which the
2487 vg_libpthread.c routine turns into return values 0 and EFAULT
2488 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002489static
2490void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002491 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002492 vki_ksigset_t* newmask,
2493 vki_ksigset_t* oldmask )
2494{
2495 Char msg_buf[100];
2496 if (VG_(clo_trace_pthread_level) >= 1) {
2497 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00002498 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
2499 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002500 print_pthread_event(tid, msg_buf);
2501 }
2502
2503 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002504 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002505
2506 if (VG_(clo_instrument)) {
2507 /* TODO check newmask/oldmask are addressible/defined */
2508 }
2509
sewardj018f7622002-05-15 21:13:39 +00002510 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002511
sewardj3a951cf2002-05-15 22:25:47 +00002512 if (newmask && VG_(clo_instrument)) {
2513 VGM_(make_readable)( (Addr)newmask, sizeof(vki_ksigset_t) );
2514 }
2515
sewardj018f7622002-05-15 21:13:39 +00002516 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00002517 SET_EDX(tid, 0);
2518}
2519
2520
2521static
2522void do_sigwait ( ThreadId tid,
2523 vki_ksigset_t* set,
2524 Int* sig )
2525{
sewardj018f7622002-05-15 21:13:39 +00002526 vki_ksigset_t irrelevant_sigmask;
2527 Char msg_buf[100];
2528
sewardjb48e5002002-05-13 00:16:03 +00002529 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
2530 VG_(sprintf)(msg_buf,
2531 "suspend due to sigwait(): set %p, sig %p",
2532 set, sig );
2533 print_pthread_event(tid, msg_buf);
2534 }
2535
2536 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002537 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002538
sewardj018f7622002-05-15 21:13:39 +00002539 /* Change SCSS */
2540 VG_(threads)[tid].sigs_waited_for = *set;
2541 VG_(threads)[tid].status = VgTs_WaitSIG;
2542
2543 VG_(block_all_host_signals)( &irrelevant_sigmask );
2544 VG_(handle_SCSS_change)( False /* lazy update */ );
2545}
2546
2547
2548static
2549void do_pthread_kill ( ThreadId tid, /* me */
2550 ThreadId thread, /* thread to signal */
2551 Int sig )
2552{
2553 Char msg_buf[100];
2554
2555 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
2556 VG_(sprintf)(msg_buf,
2557 "pthread_kill thread %d, signo %d",
2558 thread, sig );
2559 print_pthread_event(tid, msg_buf);
2560 }
2561
2562 vg_assert(VG_(is_valid_tid)(tid)
2563 && VG_(threads)[tid].status == VgTs_Runnable);
2564
2565 if (!VG_(is_valid_tid)(tid)) {
2566 SET_EDX(tid, -VKI_ESRCH);
2567 return;
2568 }
2569
2570 if (sig < 1 || sig > VKI_KNSIG) {
2571 SET_EDX(tid, -VKI_EINVAL);
2572 return;
2573 }
2574
2575 VG_(send_signal_to_thread)( thread, sig );
2576 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00002577}
2578
2579
sewardje663cb92002-04-12 10:26:32 +00002580/* ---------------------------------------------------------------------
2581 Handle non-trivial client requests.
2582 ------------------------------------------------------------------ */
2583
2584static
2585void do_nontrivial_clientreq ( ThreadId tid )
2586{
sewardj018f7622002-05-15 21:13:39 +00002587 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
sewardje663cb92002-04-12 10:26:32 +00002588 UInt req_no = arg[0];
2589 switch (req_no) {
2590
2591 case VG_USERREQ__PTHREAD_CREATE:
2592 do_pthread_create( tid,
2593 (pthread_t*)arg[1],
2594 (pthread_attr_t*)arg[2],
2595 (void*(*)(void*))arg[3],
2596 (void*)arg[4] );
2597 break;
2598
sewardjbc5b99f2002-04-13 00:08:51 +00002599 case VG_USERREQ__PTHREAD_RETURNS:
2600 handle_pthread_return( tid, (void*)arg[1] );
sewardje663cb92002-04-12 10:26:32 +00002601 break;
2602
2603 case VG_USERREQ__PTHREAD_JOIN:
2604 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
2605 break;
2606
sewardje663cb92002-04-12 10:26:32 +00002607 case VG_USERREQ__PTHREAD_CANCEL:
2608 do_pthread_cancel( tid, (pthread_t)(arg[1]) );
2609 break;
2610
sewardj3b5d8862002-04-20 13:53:23 +00002611 case VG_USERREQ__PTHREAD_EXIT:
2612 do_pthread_exit( tid, (void*)(arg[1]) );
2613 break;
2614
2615 case VG_USERREQ__PTHREAD_COND_WAIT:
2616 do_pthread_cond_wait( tid,
2617 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00002618 (pthread_mutex_t *)(arg[2]),
2619 0xFFFFFFFF /* no timeout */ );
2620 break;
2621
2622 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
2623 do_pthread_cond_wait( tid,
2624 (pthread_cond_t *)(arg[1]),
2625 (pthread_mutex_t *)(arg[2]),
2626 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00002627 break;
2628
2629 case VG_USERREQ__PTHREAD_COND_SIGNAL:
2630 do_pthread_cond_signal_or_broadcast(
2631 tid,
2632 False, /* signal, not broadcast */
2633 (pthread_cond_t *)(arg[1]) );
2634 break;
2635
2636 case VG_USERREQ__PTHREAD_COND_BROADCAST:
2637 do_pthread_cond_signal_or_broadcast(
2638 tid,
2639 True, /* broadcast, not signal */
2640 (pthread_cond_t *)(arg[1]) );
2641 break;
2642
sewardj5f07b662002-04-23 16:52:51 +00002643 case VG_USERREQ__PTHREAD_KEY_CREATE:
2644 do_pthread_key_create ( tid,
2645 (pthread_key_t*)(arg[1]),
2646 (void(*)(void*))(arg[2]) );
2647 break;
2648
2649 case VG_USERREQ__PTHREAD_KEY_DELETE:
2650 do_pthread_key_delete ( tid,
2651 (pthread_key_t)(arg[1]) );
2652 break;
2653
sewardj5f07b662002-04-23 16:52:51 +00002654 case VG_USERREQ__PTHREAD_SETSPECIFIC:
2655 do_pthread_setspecific ( tid,
2656 (pthread_key_t)(arg[1]),
2657 (void*)(arg[2]) );
2658 break;
2659
sewardjb48e5002002-05-13 00:16:03 +00002660 case VG_USERREQ__PTHREAD_SIGMASK:
2661 do_pthread_sigmask ( tid,
2662 arg[1],
2663 (vki_ksigset_t*)(arg[2]),
2664 (vki_ksigset_t*)(arg[3]) );
2665 break;
2666
2667 case VG_USERREQ__SIGWAIT:
2668 do_sigwait ( tid,
2669 (vki_ksigset_t*)(arg[1]),
2670 (Int*)(arg[2]) );
2671 break;
2672
sewardj018f7622002-05-15 21:13:39 +00002673 case VG_USERREQ__PTHREAD_KILL:
2674 do_pthread_kill ( tid, arg[1], arg[2] );
2675 break;
2676
2677
sewardje663cb92002-04-12 10:26:32 +00002678 case VG_USERREQ__MAKE_NOACCESS:
2679 case VG_USERREQ__MAKE_WRITABLE:
2680 case VG_USERREQ__MAKE_READABLE:
2681 case VG_USERREQ__DISCARD:
2682 case VG_USERREQ__CHECK_WRITABLE:
2683 case VG_USERREQ__CHECK_READABLE:
2684 case VG_USERREQ__MAKE_NOACCESS_STACK:
2685 case VG_USERREQ__RUNNING_ON_VALGRIND:
2686 case VG_USERREQ__DO_LEAK_CHECK:
sewardjc3bd5f52002-05-01 03:24:23 +00002687 SET_EDX(
2688 tid,
sewardj018f7622002-05-15 21:13:39 +00002689 VG_(handle_client_request) ( &VG_(threads)[tid], arg )
sewardjc3bd5f52002-05-01 03:24:23 +00002690 );
sewardje663cb92002-04-12 10:26:32 +00002691 break;
2692
sewardj77e466c2002-04-14 02:29:29 +00002693 case VG_USERREQ__SIGNAL_RETURNS:
2694 handle_signal_return(tid);
2695 break;
sewardj54cacf02002-04-12 23:24:59 +00002696
sewardje663cb92002-04-12 10:26:32 +00002697 default:
2698 VG_(printf)("panic'd on private request = 0x%x\n", arg[0] );
2699 VG_(panic)("handle_private_client_pthread_request: "
2700 "unknown request");
2701 /*NOTREACHED*/
2702 break;
2703 }
2704}
2705
2706
sewardj6072c362002-04-19 14:40:57 +00002707/* ---------------------------------------------------------------------
2708 Sanity checking.
2709 ------------------------------------------------------------------ */
2710
2711/* Internal consistency checks on the sched/pthread structures. */
2712static
2713void scheduler_sanity ( void )
2714{
sewardj3b5d8862002-04-20 13:53:23 +00002715 pthread_mutex_t* mx;
2716 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00002717 Int i;
sewardj5f07b662002-04-23 16:52:51 +00002718
sewardj6072c362002-04-19 14:40:57 +00002719 /* VG_(printf)("scheduler_sanity\n"); */
2720 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002721 mx = VG_(threads)[i].associated_mx;
2722 cv = VG_(threads)[i].associated_cv;
2723 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00002724 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
2725 it's actually held by someone, since otherwise this thread
2726 is deadlocked, (4) the mutex's owner is not us, since
2727 otherwise this thread is also deadlocked. The logic in
2728 do_pthread_mutex_lock rejects attempts by a thread to lock
2729 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00002730
sewardjbf290b92002-05-01 02:28:01 +00002731 (2) has been seen to fail sometimes. I don't know why.
2732 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00002733 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00002734 /* 1 */ vg_assert(mx != NULL);
2735 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00002736 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00002737 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00002738 } else
sewardj018f7622002-05-15 21:13:39 +00002739 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00002740 vg_assert(cv != NULL);
2741 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00002742 } else {
sewardj05553872002-04-20 20:53:17 +00002743 /* Unfortunately these don't hold true when a sighandler is
2744 running. To be fixed. */
2745 /* vg_assert(cv == NULL); */
2746 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00002747 }
sewardjbf290b92002-05-01 02:28:01 +00002748
sewardj018f7622002-05-15 21:13:39 +00002749 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00002750 Int
sewardj018f7622002-05-15 21:13:39 +00002751 stack_used = (Addr)VG_(threads)[i].stack_highest_word
2752 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00002753 if (i > 1 /* not the root thread */
2754 && stack_used
2755 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
2756 VG_(message)(Vg_UserMsg,
2757 "Warning: STACK OVERFLOW: "
2758 "thread %d: stack used %d, available %d",
2759 i, stack_used, VG_PTHREAD_STACK_MIN );
2760 VG_(message)(Vg_UserMsg,
2761 "Terminating Valgrind. If thread(s) "
2762 "really need more stack, increase");
2763 VG_(message)(Vg_UserMsg,
2764 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
2765 VG_(exit)(1);
2766 }
sewardjb48e5002002-05-13 00:16:03 +00002767
sewardj018f7622002-05-15 21:13:39 +00002768 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00002769 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00002770 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00002771 } else {
2772 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00002773 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00002774 }
2775
sewardjbf290b92002-05-01 02:28:01 +00002776 }
sewardj6072c362002-04-19 14:40:57 +00002777 }
sewardj5f07b662002-04-23 16:52:51 +00002778
2779 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
2780 if (!vg_thread_keys[i].inuse)
2781 vg_assert(vg_thread_keys[i].destructor == NULL);
2782 }
sewardj6072c362002-04-19 14:40:57 +00002783}
2784
2785
sewardje663cb92002-04-12 10:26:32 +00002786/*--------------------------------------------------------------------*/
2787/*--- end vg_scheduler.c ---*/
2788/*--------------------------------------------------------------------*/