blob: 8881f9ae64c5312ad5c40f077aec1aa1ab0f39dc [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
sewardjb60c1ad2002-05-29 20:23:26 +000036/* BORKAGE/ISSUES as of 29 May 02
sewardje663cb92002-04-12 10:26:32 +000037
sewardj77e466c2002-04-14 02:29:29 +000038- Currently, when a signal is run, just the ThreadStatus.status fields
39 are saved in the signal frame, along with the CPU state. Question:
40 should I also save and restore:
41 ThreadStatus.joiner
42 ThreadStatus.waited_on_mid
43 ThreadStatus.awaken_at
44 ThreadStatus.retval
45 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000046
sewardj77e466c2002-04-14 02:29:29 +000047- Signals interrupting read/write and nanosleep: SA_RESTART settings.
48 Read/write correctly return with EINTR when SA_RESTART isn't
49 specified and they are interrupted by a signal. nanosleep just
50 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000051
sewardj705d3cb2002-05-23 13:13:12 +000052- So, what's the deal with signals and mutexes? If a thread is
sewardj6072c362002-04-19 14:40:57 +000053 blocked on a mutex, or for a condition variable for that matter, can
54 signals still be delivered to it? This has serious consequences --
55 deadlocks, etc.
56
sewardj705d3cb2002-05-23 13:13:12 +000057- Signals still not really right. Each thread should have its
58 own pending-set, but there is just one process-wide pending set.
59
sewardjb60c1ad2002-05-29 20:23:26 +000060 TODO for valgrind-1.0:
61
sewardj055fbb82002-05-30 00:40:55 +000062- Update assertion checking in scheduler_sanity().
63
sewardjb60c1ad2002-05-29 20:23:26 +000064 TODO sometime:
65
sewardj645030e2002-06-06 01:27:39 +000066- poll() in the vg_libpthread.c -- should it handle the nanosleep
67 being interrupted by a signal? Ditto accept?
68
sewardjb60c1ad2002-05-29 20:23:26 +000069- Mutex scrubbing - clearup_after_thread_exit: look for threads
70 blocked on mutexes held by the exiting thread, and release them
71 appropriately. (??)
72
73- pthread_atfork
74
sewardje462e202002-04-13 04:09:07 +000075*/
sewardje663cb92002-04-12 10:26:32 +000076
77
78/* ---------------------------------------------------------------------
79 Types and globals for the scheduler.
80 ------------------------------------------------------------------ */
81
82/* type ThreadId is defined in vg_include.h. */
83
84/* struct ThreadState is defined in vg_include.h. */
85
sewardj018f7622002-05-15 21:13:39 +000086/* Globals. A statically allocated array of threads. NOTE: [0] is
87 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000088 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000089ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000090
sewardj2cb00342002-06-28 01:46:26 +000091/* The process' fork-handler stack. */
92static Int vg_fhstack_used = 0;
93static ForkHandlerEntry vg_fhstack[VG_N_FORKHANDLERSTACK];
94
95
sewardj1e8cdc92002-04-18 11:37:52 +000096/* The tid of the thread currently in VG_(baseBlock). */
97static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
98
sewardje663cb92002-04-12 10:26:32 +000099
100/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
101jmp_buf VG_(scheduler_jmpbuf);
102/* ... and if so, here's the signal which caused it to do so. */
103Int VG_(longjmpd_on_signal);
104
105
106/* Machinery to keep track of which threads are waiting on which
107 fds. */
108typedef
109 struct {
110 /* The thread which made the request. */
111 ThreadId tid;
112
113 /* The next two fields describe the request. */
114 /* File descriptor waited for. -1 means this slot is not in use */
115 Int fd;
116 /* The syscall number the fd is used in. */
117 Int syscall_no;
118
119 /* False => still waiting for select to tell us the fd is ready
120 to go. True => the fd is ready, but the results have not yet
121 been delivered back to the calling thread. Once the latter
122 happens, this entire record is marked as no longer in use, by
123 making the fd field be -1. */
124 Bool ready;
125 }
126 VgWaitedOnFd;
127
128static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
129
130
sewardj5f07b662002-04-23 16:52:51 +0000131/* Keeping track of keys. */
132typedef
133 struct {
134 /* Has this key been allocated ? */
135 Bool inuse;
136 /* If .inuse==True, records the address of the associated
137 destructor, or NULL if none. */
138 void (*destructor)(void*);
139 }
140 ThreadKeyState;
141
142/* And our array of thread keys. */
143static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
144
145typedef UInt ThreadKey;
146
147
sewardje663cb92002-04-12 10:26:32 +0000148/* Forwards */
sewardj124ca2a2002-06-20 10:19:38 +0000149static void do_client_request ( ThreadId tid );
sewardj6072c362002-04-19 14:40:57 +0000150static void scheduler_sanity ( void );
sewardj124ca2a2002-06-20 10:19:38 +0000151static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
sewardjd140e442002-05-29 01:21:19 +0000152
153
sewardje663cb92002-04-12 10:26:32 +0000154/* ---------------------------------------------------------------------
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;
sewardj20917d82002-05-28 01:36:45 +0000223 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee(%d)",
224 VG_(threads)[i].joiner_jee_tid);
225 break;
226 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner"); break;
sewardj6072c362002-04-19 14:40:57 +0000227 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
228 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000229 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000230 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000231 default: VG_(printf)("???"); break;
232 }
sewardj3b5d8862002-04-20 13:53:23 +0000233 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000234 VG_(threads)[i].associated_mx,
235 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000236 VG_(pp_ExeContext)(
sewardj018f7622002-05-15 21:13:39 +0000237 VG_(get_ExeContext)( False, VG_(threads)[i].m_eip,
238 VG_(threads)[i].m_ebp ));
sewardje663cb92002-04-12 10:26:32 +0000239 }
240 VG_(printf)("\n");
241}
242
243static
244void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no )
245{
246 Int i;
247
248 vg_assert(fd != -1); /* avoid total chaos */
249
250 for (i = 0; i < VG_N_WAITING_FDS; i++)
251 if (vg_waiting_fds[i].fd == -1)
252 break;
253
254 if (i == VG_N_WAITING_FDS)
255 VG_(panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
256 /*
257 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
258 tid, fd, i);
259 */
260 vg_waiting_fds[i].fd = fd;
261 vg_waiting_fds[i].tid = tid;
262 vg_waiting_fds[i].ready = False;
263 vg_waiting_fds[i].syscall_no = syscall_no;
264}
265
266
267
268static
269void print_sched_event ( ThreadId tid, Char* what )
270{
sewardj45b4b372002-04-16 22:50:32 +0000271 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000272}
273
274
275static
276void print_pthread_event ( ThreadId tid, Char* what )
277{
278 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000279}
280
281
282static
283Char* name_of_sched_event ( UInt event )
284{
285 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000286 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
287 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
288 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
289 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
290 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
291 default: return "??UNKNOWN??";
292 }
293}
294
295
296/* Create a translation of the client basic block beginning at
297 orig_addr, and add it to the translation cache & translation table.
298 This probably doesn't really belong here, but, hey ...
299*/
sewardj1e8cdc92002-04-18 11:37:52 +0000300static
301void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000302{
303 Addr trans_addr;
304 TTEntry tte;
305 Int orig_size, trans_size;
306 /* Ensure there is space to hold a translation. */
307 VG_(maybe_do_lru_pass)();
sewardj018f7622002-05-15 21:13:39 +0000308 VG_(translate)( &VG_(threads)[tid],
sewardj1e8cdc92002-04-18 11:37:52 +0000309 orig_addr, &orig_size, &trans_addr, &trans_size );
sewardje663cb92002-04-12 10:26:32 +0000310 /* Copy data at trans_addr into the translation cache.
311 Returned pointer is to the code, not to the 4-byte
312 header. */
313 /* Since the .orig_size and .trans_size fields are
314 UShort, be paranoid. */
315 vg_assert(orig_size > 0 && orig_size < 65536);
316 vg_assert(trans_size > 0 && trans_size < 65536);
317 tte.orig_size = orig_size;
318 tte.orig_addr = orig_addr;
319 tte.trans_size = trans_size;
320 tte.trans_addr = VG_(copy_to_transcache)
321 ( trans_addr, trans_size );
322 tte.mru_epoch = VG_(current_epoch);
323 /* Free the intermediary -- was allocated by VG_(emit_code). */
324 VG_(jitfree)( (void*)trans_addr );
325 /* Add to trans tab and set back pointer. */
326 VG_(add_to_trans_tab) ( &tte );
327 /* Update stats. */
328 VG_(this_epoch_in_count) ++;
329 VG_(this_epoch_in_osize) += orig_size;
330 VG_(this_epoch_in_tsize) += trans_size;
331 VG_(overall_in_count) ++;
332 VG_(overall_in_osize) += orig_size;
333 VG_(overall_in_tsize) += trans_size;
sewardje663cb92002-04-12 10:26:32 +0000334}
335
336
337/* Allocate a completely empty ThreadState record. */
338static
339ThreadId vg_alloc_ThreadState ( void )
340{
341 Int i;
sewardj6072c362002-04-19 14:40:57 +0000342 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000343 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000344 return i;
345 }
346 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
347 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
348 VG_(panic)("VG_N_THREADS is too low");
349 /*NOTREACHED*/
350}
351
352
sewardj1e8cdc92002-04-18 11:37:52 +0000353ThreadState* VG_(get_current_thread_state) ( void )
354{
sewardj018f7622002-05-15 21:13:39 +0000355 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
356 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000357}
358
359
360ThreadId VG_(get_current_tid) ( void )
361{
sewardj018f7622002-05-15 21:13:39 +0000362 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
sewardj1e8cdc92002-04-18 11:37:52 +0000363 return vg_tid_currently_in_baseBlock;
364}
365
366
sewardje663cb92002-04-12 10:26:32 +0000367/* Copy the saved state of a thread into VG_(baseBlock), ready for it
368 to be run. */
369__inline__
370void VG_(load_thread_state) ( ThreadId tid )
371{
372 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000373 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
374
sewardj018f7622002-05-15 21:13:39 +0000375 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
376 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
377 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
378 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
379 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
380 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
381 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
382 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
383 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags;
384 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000385
386 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000387 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000388
sewardj018f7622002-05-15 21:13:39 +0000389 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
390 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
391 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
392 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
393 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
394 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
395 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
396 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
397 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
sewardj1e8cdc92002-04-18 11:37:52 +0000398
399 vg_tid_currently_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000400}
401
402
403/* Copy the state of a thread from VG_(baseBlock), presumably after it
404 has been descheduled. For sanity-check purposes, fill the vacated
405 VG_(baseBlock) with garbage so as to make the system more likely to
406 fail quickly if we erroneously continue to poke around inside
407 VG_(baseBlock) without first doing a load_thread_state().
408*/
409__inline__
410void VG_(save_thread_state) ( ThreadId tid )
411{
412 Int i;
413 const UInt junk = 0xDEADBEEF;
414
sewardj1e8cdc92002-04-18 11:37:52 +0000415 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
416
sewardj018f7622002-05-15 21:13:39 +0000417 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
418 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
419 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
420 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
421 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
422 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
423 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
424 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
425 VG_(threads)[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
426 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000427
428 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000429 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000430
sewardj018f7622002-05-15 21:13:39 +0000431 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
432 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
433 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
434 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
435 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
436 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
437 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
438 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
439 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
sewardje663cb92002-04-12 10:26:32 +0000440
441 /* Fill it up with junk. */
442 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
443 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
444 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
445 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
446 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
447 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
448 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
449 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
450 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
451 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
452
453 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
454 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000455
456 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000457}
458
459
460/* Run the thread tid for a while, and return a VG_TRC_* value to the
461 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000462static
sewardje663cb92002-04-12 10:26:32 +0000463UInt run_thread_for_a_while ( ThreadId tid )
464{
sewardj7ccc5c22002-04-24 21:39:11 +0000465 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000466 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000467 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000468 vg_assert(VG_(bbs_to_go) > 0);
469
sewardj671ff542002-05-07 09:25:30 +0000470 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000471 VG_(load_thread_state) ( tid );
472 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
473 /* try this ... */
474 trc = VG_(run_innerloop)();
475 /* We get here if the client didn't take a fault. */
476 } else {
477 /* We get here if the client took a fault, which caused our
478 signal handler to longjmp. */
479 vg_assert(trc == 0);
480 trc = VG_TRC_UNRESUMABLE_SIGNAL;
481 }
482 VG_(save_thread_state) ( tid );
sewardj671ff542002-05-07 09:25:30 +0000483 VGP_POPCC;
sewardje663cb92002-04-12 10:26:32 +0000484 return trc;
485}
486
487
488/* Increment the LRU epoch counter. */
489static
490void increment_epoch ( void )
491{
492 VG_(current_epoch)++;
493 if (VG_(clo_verbosity) > 2) {
494 UInt tt_used, tc_used;
495 VG_(get_tt_tc_used) ( &tt_used, &tc_used );
496 VG_(message)(Vg_UserMsg,
497 "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
498 VG_(bbs_done),
499 VG_(this_epoch_in_count),
500 VG_(this_epoch_in_osize),
501 VG_(this_epoch_in_tsize),
502 VG_(this_epoch_out_count),
503 VG_(this_epoch_out_osize),
504 VG_(this_epoch_out_tsize),
505 tt_used, tc_used
506 );
507 }
508 VG_(this_epoch_in_count) = 0;
509 VG_(this_epoch_in_osize) = 0;
510 VG_(this_epoch_in_tsize) = 0;
511 VG_(this_epoch_out_count) = 0;
512 VG_(this_epoch_out_osize) = 0;
513 VG_(this_epoch_out_tsize) = 0;
514}
515
516
sewardj20917d82002-05-28 01:36:45 +0000517static
518void mostly_clear_thread_record ( ThreadId tid )
519{
520 Int j;
521 vg_assert(tid >= 0 && tid < VG_N_THREADS);
522 VG_(threads)[tid].tid = tid;
523 VG_(threads)[tid].status = VgTs_Empty;
524 VG_(threads)[tid].associated_mx = NULL;
525 VG_(threads)[tid].associated_cv = NULL;
526 VG_(threads)[tid].awaken_at = 0;
527 VG_(threads)[tid].joinee_retval = NULL;
528 VG_(threads)[tid].joiner_thread_return = NULL;
529 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000530 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000531 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
532 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
533 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000534 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000535 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000536 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
537 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
538 for (j = 0; j < VG_N_THREAD_KEYS; j++)
539 VG_(threads)[tid].specifics[j] = NULL;
540}
541
542
sewardje663cb92002-04-12 10:26:32 +0000543/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000544 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000545 caller takes care to park the client's state is parked in
546 VG_(baseBlock).
547*/
548void VG_(scheduler_init) ( void )
549{
550 Int i;
551 Addr startup_esp;
552 ThreadId tid_main;
553
554 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000555
556 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
557 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)) {
558 /* Jolly good! */
559 } else {
560 VG_(printf)("%%esp at startup = %p is not near %p or %p; aborting\n",
561 (void*)startup_esp,
562 (void*)VG_STARTUP_STACK_BASE_1,
563 (void*)VG_STARTUP_STACK_BASE_2 );
sewardje663cb92002-04-12 10:26:32 +0000564 VG_(panic)("unexpected %esp at startup");
565 }
566
sewardj6072c362002-04-19 14:40:57 +0000567 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000568 mostly_clear_thread_record(i);
569 VG_(threads)[i].stack_size = 0;
570 VG_(threads)[i].stack_base = (Addr)NULL;
571 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000572 }
573
574 for (i = 0; i < VG_N_WAITING_FDS; i++)
575 vg_waiting_fds[i].fd = -1; /* not in use */
576
sewardj5f07b662002-04-23 16:52:51 +0000577 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
578 vg_thread_keys[i].inuse = False;
579 vg_thread_keys[i].destructor = NULL;
580 }
581
sewardj2cb00342002-06-28 01:46:26 +0000582 vg_fhstack_used = 0;
583
sewardje663cb92002-04-12 10:26:32 +0000584 /* Assert this is thread zero, which has certain magic
585 properties. */
586 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000587 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000588 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000589
590 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000591 vg_tid_currently_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000592 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000593
sewardj018f7622002-05-15 21:13:39 +0000594 VG_(threads)[tid_main].stack_highest_word
595 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000596
sewardj1e8cdc92002-04-18 11:37:52 +0000597 /* So now ... */
598 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardje663cb92002-04-12 10:26:32 +0000599}
600
601
602/* What if fd isn't a valid fd? */
603static
604void set_fd_nonblocking ( Int fd )
605{
606 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
607 vg_assert(!VG_(is_kerror)(res));
608 res |= VKI_O_NONBLOCK;
609 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
610 vg_assert(!VG_(is_kerror)(res));
611}
612
613static
614void set_fd_blocking ( Int fd )
615{
616 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
617 vg_assert(!VG_(is_kerror)(res));
618 res &= ~VKI_O_NONBLOCK;
619 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
620 vg_assert(!VG_(is_kerror)(res));
621}
622
623static
624Bool fd_is_blockful ( Int fd )
625{
626 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
627 vg_assert(!VG_(is_kerror)(res));
628 return (res & VKI_O_NONBLOCK) ? False : True;
629}
630
sewardj3947e622002-05-23 16:52:11 +0000631static
632Bool fd_is_valid ( Int fd )
633{
634 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
635 return VG_(is_kerror)(res) ? False : True;
636}
637
sewardje663cb92002-04-12 10:26:32 +0000638
639
sewardj6072c362002-04-19 14:40:57 +0000640/* vthread tid is returning from a signal handler; modify its
641 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000642
643/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
644 for read or write, has been interrupted by a signal. Find and
645 clear the relevant vg_waiting_fd[] entry. Most of the code in this
646 procedure is total paranoia, if you look closely. */
647static
648void cleanup_waiting_fd_table ( ThreadId tid )
649{
650 Int i, waiters;
651
sewardjb48e5002002-05-13 00:16:03 +0000652 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000653 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
654 vg_assert(VG_(threads)[tid].m_eax == __NR_read
655 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000656
657 /* Excessively paranoidly ... find the fd this op was waiting
658 for, and mark it as not being waited on. */
659 waiters = 0;
660 for (i = 0; i < VG_N_WAITING_FDS; i++) {
661 if (vg_waiting_fds[i].tid == tid) {
662 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000663 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000664 }
665 }
666 vg_assert(waiters == 1);
667 for (i = 0; i < VG_N_WAITING_FDS; i++)
668 if (vg_waiting_fds[i].tid == tid)
669 break;
670 vg_assert(i < VG_N_WAITING_FDS);
671 vg_assert(vg_waiting_fds[i].fd != -1);
672 vg_waiting_fds[i].fd = -1; /* not in use */
673}
674
675
sewardj6072c362002-04-19 14:40:57 +0000676static
677void handle_signal_return ( ThreadId tid )
678{
679 Char msg_buf[100];
680 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000681 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000682
sewardjb48e5002002-05-13 00:16:03 +0000683 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000684
sewardj9a2224b2002-06-19 10:17:40 +0000685 /* Increment signal-returned counter. Used only to implement
686 pause(). */
687 VG_(threads)[tid].n_signals_returned++;
688
sewardj6072c362002-04-19 14:40:57 +0000689 restart_blocked_syscalls = VG_(signal_returns)(tid);
690
691 if (restart_blocked_syscalls)
692 /* Easy; we don't have to do anything. */
693 return;
694
sewardj018f7622002-05-15 21:13:39 +0000695 if (VG_(threads)[tid].status == VgTs_WaitFD
696 && (VG_(threads)[tid].m_eax == __NR_read
697 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000698 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000699 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000700 VG_(threads)[tid].m_eax = -VKI_EINTR;
701 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000702
sewardj6072c362002-04-19 14:40:57 +0000703 if (VG_(clo_trace_sched)) {
704 VG_(sprintf)(msg_buf,
705 "read() / write() interrupted by signal; return EINTR" );
706 print_sched_event(tid, msg_buf);
707 }
708 return;
709 }
710
sewardj645030e2002-06-06 01:27:39 +0000711 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000712 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000713 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000714 write the unused time to nanosleep's second param, but that's
715 too much effort ... we just say that 1 nanosecond was not
716 used, and return EINTR. */
717 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
718 if (rem != NULL) {
719 rem->tv_sec = 0;
720 rem->tv_nsec = 1;
721 }
722 SET_EAX(tid, -VKI_EINTR);
723 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000724 return;
725 }
726
sewardj018f7622002-05-15 21:13:39 +0000727 if (VG_(threads)[tid].status == VgTs_WaitFD) {
sewardj1ffa8da2002-04-26 22:47:57 +0000728 VG_(panic)("handle_signal_return: unknown interrupted syscall");
729 }
730
sewardj6072c362002-04-19 14:40:57 +0000731 /* All other cases? Just return. */
732}
733
734
sewardje663cb92002-04-12 10:26:32 +0000735static
736void sched_do_syscall ( ThreadId tid )
737{
738 UInt saved_eax;
739 UInt res, syscall_no;
740 UInt fd;
sewardje663cb92002-04-12 10:26:32 +0000741 Bool orig_fd_blockness;
742 Char msg_buf[100];
743
sewardjb48e5002002-05-13 00:16:03 +0000744 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000745 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000746
sewardj018f7622002-05-15 21:13:39 +0000747 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000748
749 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000750 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000751 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000752 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000753 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000754 t_awaken
755 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000756 + (UInt)1000ULL * (UInt)(req->tv_sec)
757 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000758 VG_(threads)[tid].status = VgTs_Sleeping;
759 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000760 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000761 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000762 t_now, t_awaken-t_now);
763 print_sched_event(tid, msg_buf);
764 }
765 /* Force the scheduler to run something else for a while. */
766 return;
767 }
768
sewardjaec22c02002-04-29 01:58:08 +0000769 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000770 /* We think it's non-blocking. Just do it in the normal way. */
771 VG_(perform_assumed_nonblocking_syscall)(tid);
772 /* The thread is still runnable. */
773 return;
774 }
775
sewardje663cb92002-04-12 10:26:32 +0000776 /* Set the fd to nonblocking, and do the syscall, which will return
777 immediately, in order to lodge a request with the Linux kernel.
778 We later poll for I/O completion using select(). */
779
sewardj018f7622002-05-15 21:13:39 +0000780 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000781
782 /* Deal with error case immediately. */
783 if (!fd_is_valid(fd)) {
784 VG_(message)(Vg_UserMsg,
785 "Warning: invalid file descriptor %d in syscall %s",
786 fd, syscall_no == __NR_read ? "read()" : "write()" );
787 VG_(check_known_blocking_syscall)(tid, syscall_no, NULL /* PRE */);
788 KERNEL_DO_SYSCALL(tid, res);
789 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
790 /* We're still runnable. */
791 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
792 return;
793 }
794
795 /* From here onwards we know that fd is valid. */
796
sewardje663cb92002-04-12 10:26:32 +0000797 orig_fd_blockness = fd_is_blockful(fd);
798 set_fd_nonblocking(fd);
799 vg_assert(!fd_is_blockful(fd));
800 VG_(check_known_blocking_syscall)(tid, syscall_no, NULL /* PRE */);
801
802 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000803 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000804 KERNEL_DO_SYSCALL(tid,res);
805
806 /* Restore original blockfulness of the fd. */
807 if (orig_fd_blockness)
808 set_fd_blocking(fd);
809 else
810 set_fd_nonblocking(fd);
811
sewardjaec22c02002-04-29 01:58:08 +0000812 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
813 /* Finish off in the normal way. Don't restore %EAX, since that
814 now (correctly) holds the result of the call. We get here if either:
815 1. The call didn't block, or
816 2. The fd was already in nonblocking mode before we started to
817 mess with it. In this case, we're not expecting to handle
818 the I/O completion -- the client is. So don't file a
819 completion-wait entry.
820 */
sewardje663cb92002-04-12 10:26:32 +0000821 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
822 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000823 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000824
825 } else {
826
sewardjaec22c02002-04-29 01:58:08 +0000827 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
828
sewardje663cb92002-04-12 10:26:32 +0000829 /* It would have blocked. First, restore %EAX to what it was
830 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000831 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000832 /* Put this fd in a table of fds on which we are waiting for
833 completion. The arguments for select() later are constructed
834 from this table. */
835 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */);
836 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000837 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000838 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000839 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
840 print_sched_event(tid, msg_buf);
841 }
842
843 }
844}
845
846
847/* Find out which of the fds in vg_waiting_fds are now ready to go, by
848 making enquiries with select(), and mark them as ready. We have to
849 wait for the requesting threads to fall into the the WaitFD state
850 before we can actually finally deliver the results, so this
851 procedure doesn't do that; complete_blocked_syscalls() does it.
852
853 It might seem odd that a thread which has done a blocking syscall
854 is not in WaitFD state; the way this can happen is if it initially
855 becomes WaitFD, but then a signal is delivered to it, so it becomes
856 Runnable for a while. In this case we have to wait for the
857 sighandler to return, whereupon the WaitFD state is resumed, and
858 only at that point can the I/O result be delivered to it. However,
859 this point may be long after the fd is actually ready.
860
861 So, poll_for_ready_fds() merely detects fds which are ready.
862 complete_blocked_syscalls() does the second half of the trick,
863 possibly much later: it delivers the results from ready fds to
864 threads in WaitFD state.
865*/
sewardj9a199dc2002-04-14 13:01:38 +0000866static
sewardje663cb92002-04-12 10:26:32 +0000867void poll_for_ready_fds ( void )
868{
869 vki_ksigset_t saved_procmask;
870 vki_fd_set readfds;
871 vki_fd_set writefds;
872 vki_fd_set exceptfds;
873 struct vki_timeval timeout;
874 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
875 ThreadId tid;
876 Bool rd_ok, wr_ok, ex_ok;
877 Char msg_buf[100];
878
sewardje462e202002-04-13 04:09:07 +0000879 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000880 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000881
sewardje663cb92002-04-12 10:26:32 +0000882 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000883 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000884 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000885 break;
sewardj6072c362002-04-19 14:40:57 +0000886
sewardj5f07b662002-04-23 16:52:51 +0000887 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000888 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000889 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000890 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000891 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000892 continue;
sewardj018f7622002-05-15 21:13:39 +0000893 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +0000894 /* Resume this thread. Set to zero the remaining-time
895 (second) arg of nanosleep, since it's used up all its
896 time. */
sewardj018f7622002-05-15 21:13:39 +0000897 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
898 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +0000899 if (rem != NULL) {
900 rem->tv_sec = 0;
901 rem->tv_nsec = 0;
902 }
903 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +0000904 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +0000905 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +0000906 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000907 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000908 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +0000909 t_now);
910 print_sched_event(tid, msg_buf);
911 }
sewardje663cb92002-04-12 10:26:32 +0000912 }
913 }
914 }
sewardje663cb92002-04-12 10:26:32 +0000915
sewardje462e202002-04-13 04:09:07 +0000916 /* And look for threads waiting on file descriptors which are now
917 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +0000918 timeout.tv_sec = 0;
919 timeout.tv_usec = 0;
920
921 VKI_FD_ZERO(&readfds);
922 VKI_FD_ZERO(&writefds);
923 VKI_FD_ZERO(&exceptfds);
924 fd_max = -1;
925 for (i = 0; i < VG_N_WAITING_FDS; i++) {
926 if (vg_waiting_fds[i].fd == -1 /* not in use */)
927 continue;
928 if (vg_waiting_fds[i].ready /* already ready? */)
929 continue;
930 fd = vg_waiting_fds[i].fd;
931 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +0000932 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +0000933 if (fd > fd_max)
934 fd_max = fd;
935 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +0000936 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +0000937 syscall_no = vg_waiting_fds[i].syscall_no;
938 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +0000939 case __NR_read:
940 /* In order to catch timeout events on fds which are
941 readable and which have been ioctl(TCSETA)'d with a
942 VTIMEout, we appear to need to ask if the fd is
943 writable, for some reason. Ask me not why. Since this
944 is strange and potentially troublesome we only do it if
945 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +0000946 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +0000947 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +0000948 VKI_FD_SET(fd, &readfds); break;
949 case __NR_write:
950 VKI_FD_SET(fd, &writefds); break;
951 default:
952 VG_(panic)("poll_for_ready_fds: unexpected syscall");
953 /*NOTREACHED*/
954 break;
955 }
956 }
957
sewardje462e202002-04-13 04:09:07 +0000958 /* Short cut: if no fds are waiting, give up now. */
959 if (fd_max == -1)
960 return;
961
sewardje663cb92002-04-12 10:26:32 +0000962 /* BLOCK ALL SIGNALS. We don't want the complication of select()
963 getting interrupted. */
964 VG_(block_all_host_signals)( &saved_procmask );
965
966 n_ready = VG_(select)
967 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
968 if (VG_(is_kerror)(n_ready)) {
969 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
970 VG_(panic)("poll_for_ready_fds: select failed?!");
971 /*NOTREACHED*/
972 }
973
974 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +0000975 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +0000976
977 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
978
979 if (n_ready == 0)
980 return;
981
982 /* Inspect all the fds we know about, and handle any completions that
983 have happened. */
984 /*
985 VG_(printf)("\n\n");
986 for (fd = 0; fd < 100; fd++)
987 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
988 VG_(printf)("X"); } else { VG_(printf)("."); };
989 VG_(printf)("\n\nfd_max = %d\n", fd_max);
990 */
991
992 for (fd = 0; fd <= fd_max; fd++) {
993 rd_ok = VKI_FD_ISSET(fd, &readfds);
994 wr_ok = VKI_FD_ISSET(fd, &writefds);
995 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
996
997 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
998 if (n_ok == 0)
999 continue;
1000 if (n_ok > 1) {
1001 VG_(printf)("offending fd = %d\n", fd);
1002 VG_(panic)("poll_for_ready_fds: multiple events on fd");
1003 }
sewardjbc7d8782002-06-30 12:44:54 +00001004
sewardje663cb92002-04-12 10:26:32 +00001005 /* An I/O event completed for fd. Find the thread which
1006 requested this. */
1007 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1008 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1009 continue;
1010 if (vg_waiting_fds[i].fd == fd)
1011 break;
1012 }
1013
1014 /* And a bit more paranoia ... */
1015 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1016
1017 /* Mark the fd as ready. */
1018 vg_assert(! vg_waiting_fds[i].ready);
1019 vg_waiting_fds[i].ready = True;
1020 }
1021}
1022
1023
1024/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001025static
sewardje663cb92002-04-12 10:26:32 +00001026void complete_blocked_syscalls ( void )
1027{
1028 Int fd, i, res, syscall_no;
1029 ThreadId tid;
1030 Char msg_buf[100];
1031
1032 /* Inspect all the outstanding fds we know about. */
1033
1034 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1035 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1036 continue;
1037 if (! vg_waiting_fds[i].ready)
1038 continue;
1039
1040 fd = vg_waiting_fds[i].fd;
1041 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001042 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001043
1044 /* The thread actually has to be waiting for the I/O event it
1045 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001046 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001047 continue;
1048
1049 /* Ok, actually do it! We can safely use %EAX as the syscall
1050 number, because the speculative call made by
1051 sched_do_syscall() doesn't change %EAX in the case where the
1052 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001053 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001054 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001055
1056 /* In a rare case pertaining to writing into a pipe, write()
1057 will block when asked to write > 4096 bytes even though the
1058 kernel claims, when asked via select(), that blocking will
1059 not occur for a write on that fd. This can cause deadlocks.
1060 An easy answer is to limit the size of the write to 4096
1061 anyway and hope that the client program's logic can handle
1062 the short write. That shoulds dubious to me, so we don't do
1063 it by default. */
1064 if (syscall_no == __NR_write
1065 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1066 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1067 /* VG_(printf)("truncate write from %d to 4096\n",
1068 VG_(threads)[tid].m_edx ); */
1069 VG_(threads)[tid].m_edx = 4096;
1070 }
1071
sewardje663cb92002-04-12 10:26:32 +00001072 KERNEL_DO_SYSCALL(tid,res);
1073 VG_(check_known_blocking_syscall)(tid, syscall_no, &res /* POST */);
1074
1075 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001076 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001077 /* Mark slot as no longer in use. */
1078 vg_waiting_fds[i].fd = -1;
1079 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001080 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001081 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1082 print_sched_event(tid, msg_buf);
1083 }
1084 }
1085}
1086
1087
1088static
sewardj5f07b662002-04-23 16:52:51 +00001089void check_for_pthread_cond_timedwait ( void )
1090{
sewardj51c0aaf2002-04-25 01:32:10 +00001091 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001092 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001093 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001094 continue;
sewardj018f7622002-05-15 21:13:39 +00001095 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001096 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001097 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001098 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001099 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001100 }
sewardj5f07b662002-04-23 16:52:51 +00001101 }
1102}
1103
1104
1105static
sewardje663cb92002-04-12 10:26:32 +00001106void nanosleep_for_a_while ( void )
1107{
1108 Int res;
1109 struct vki_timespec req;
1110 struct vki_timespec rem;
1111 req.tv_sec = 0;
sewardj51c0aaf2002-04-25 01:32:10 +00001112 req.tv_nsec = 20 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001113 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001114 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001115}
1116
1117
1118/* ---------------------------------------------------------------------
1119 The scheduler proper.
1120 ------------------------------------------------------------------ */
1121
1122/* Run user-space threads until either
1123 * Deadlock occurs
1124 * One thread asks to shutdown Valgrind
1125 * The specified number of basic blocks has gone by.
1126*/
1127VgSchedReturnCode VG_(scheduler) ( void )
1128{
1129 ThreadId tid, tid_next;
1130 UInt trc;
1131 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001132 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001133 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001134 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001135
1136 /* For the LRU structures, records when the epoch began. */
1137 ULong lru_epoch_started_at = 0;
1138
1139 /* Start with the root thread. tid in general indicates the
1140 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001141 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001142
1143 /* This is the top level scheduler loop. It falls into three
1144 phases. */
1145 while (True) {
1146
sewardj6072c362002-04-19 14:40:57 +00001147 /* ======================= Phase 0 of 3 =======================
1148 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001149 stage1:
sewardj6072c362002-04-19 14:40:57 +00001150 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001151 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001152
sewardje663cb92002-04-12 10:26:32 +00001153 /* ======================= Phase 1 of 3 =======================
1154 Handle I/O completions and signals. This may change the
1155 status of various threads. Then select a new thread to run,
1156 or declare deadlock, or sleep if there are no runnable
1157 threads but some are blocked on I/O. */
1158
1159 /* Age the LRU structures if an epoch has been completed. */
1160 if (VG_(bbs_done) - lru_epoch_started_at >= VG_BBS_PER_EPOCH) {
1161 lru_epoch_started_at = VG_(bbs_done);
1162 increment_epoch();
1163 }
1164
1165 /* Was a debug-stop requested? */
1166 if (VG_(bbs_to_go) == 0)
1167 goto debug_stop;
1168
1169 /* Do the following loop until a runnable thread is found, or
1170 deadlock is detected. */
1171 while (True) {
1172
1173 /* For stats purposes only. */
1174 VG_(num_scheduling_events_MAJOR) ++;
1175
1176 /* See if any I/O operations which we were waiting for have
1177 completed, and, if so, make runnable the relevant waiting
1178 threads. */
1179 poll_for_ready_fds();
1180 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001181 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001182
1183 /* See if there are any signals which need to be delivered. If
1184 so, choose thread(s) to deliver them to, and build signal
1185 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001186
1187 /* Be careful about delivering signals to a thread waiting
1188 for a mutex. In particular, when the handler is running,
1189 that thread is temporarily apparently-not-waiting for the
1190 mutex, so if it is unlocked by another thread whilst the
1191 handler is running, this thread is not informed. When the
1192 handler returns, the thread resumes waiting on the mutex,
1193 even if, as a result, it has missed the unlocking of it.
1194 Potential deadlock. This sounds all very strange, but the
1195 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001196 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001197 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001198 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001199
1200 /* Try and find a thread (tid) to run. */
1201 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001202 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001203 while (True) {
1204 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001205 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001206 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1207 || VG_(threads)[tid_next].status == VgTs_Sleeping
1208 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1209 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1210 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001211 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001212 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001213 break; /* We can run this one. */
1214 if (tid_next == tid)
1215 break; /* been all the way round */
1216 }
1217 tid = tid_next;
1218
sewardj018f7622002-05-15 21:13:39 +00001219 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001220 /* Found a suitable candidate. Fall out of this loop, so
1221 we can advance to stage 2 of the scheduler: actually
1222 running the thread. */
1223 break;
1224 }
1225
1226 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001227 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001228 /* No runnable threads and no prospect of any appearing
1229 even if we wait for an arbitrary length of time. In
1230 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001231 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001232 return VgSrc_Deadlock;
1233 }
1234
1235 /* At least one thread is in a fd-wait state. Delay for a
1236 while, and go round again, in the hope that eventually a
1237 thread becomes runnable. */
1238 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001239 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001240 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001241 }
1242
1243
1244 /* ======================= Phase 2 of 3 =======================
1245 Wahey! We've finally decided that thread tid is runnable, so
1246 we now do that. Run it for as much of a quanta as possible.
1247 Trivial requests are handled and the thread continues. The
1248 aim is not to do too many of Phase 1 since it is expensive. */
1249
1250 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001251 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001252
1253 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1254 that it decrements the counter before testing it for zero, so
1255 that if VG_(dispatch_ctr) is set to N you get at most N-1
1256 iterations. Also this means that VG_(dispatch_ctr) must
1257 exceed zero before entering the innerloop. Also also, the
1258 decrement is done before the bb is actually run, so you
1259 always get at least one decrement even if nothing happens.
1260 */
1261 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1262 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1263 else
1264 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1265
1266 /* ... and remember what we asked for. */
1267 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1268
sewardj1e8cdc92002-04-18 11:37:52 +00001269 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001270 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001271
sewardje663cb92002-04-12 10:26:32 +00001272 /* Actually run thread tid. */
1273 while (True) {
1274
sewardj7e87e382002-05-03 19:09:05 +00001275 VG_(last_run_tid) = tid;
1276
sewardje663cb92002-04-12 10:26:32 +00001277 /* For stats purposes only. */
1278 VG_(num_scheduling_events_MINOR) ++;
1279
1280 if (0)
1281 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1282 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001283# if 0
1284 if (VG_(bbs_done) > 31700000 + 0) {
1285 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001286 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001287 NULL,NULL,NULL);
1288 }
sewardj018f7622002-05-15 21:13:39 +00001289 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001290# endif
sewardje663cb92002-04-12 10:26:32 +00001291
1292 trc = run_thread_for_a_while ( tid );
1293
sewardjb3eef6b2002-05-01 00:05:27 +00001294# if 0
sewardj018f7622002-05-15 21:13:39 +00001295 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001296 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001297 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001298 }
1299# endif
1300
sewardje663cb92002-04-12 10:26:32 +00001301 /* Deal quickly with trivial scheduling events, and resume the
1302 thread. */
1303
1304 if (trc == VG_TRC_INNER_FASTMISS) {
1305 vg_assert(VG_(dispatch_ctr) > 0);
1306
1307 /* Trivial event. Miss in the fast-cache. Do a full
1308 lookup for it. */
1309 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001310 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001311 if (trans_addr == (Addr)0) {
1312 /* Not found; we need to request a translation. */
sewardj018f7622002-05-15 21:13:39 +00001313 create_translation_for( tid, VG_(threads)[tid].m_eip );
1314 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001315 if (trans_addr == (Addr)0)
1316 VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
1317 }
1318 continue; /* with this thread */
1319 }
1320
1321 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj8ccc2be2002-05-10 20:26:37 +00001322 /* VG_(printf)("request 0x%x\n",
sewardj018f7622002-05-15 21:13:39 +00001323 *(UInt*)(VG_(threads)[tid].m_eax)); */
sewardj124ca2a2002-06-20 10:19:38 +00001324 do_client_request(tid);
1325 /* Following the request, we try and continue with the
1326 same thread if still runnable. If not, go back to
1327 Stage 1 to select a new thread to run. */
1328 if (VG_(threads)[tid].status == VgTs_Runnable)
1329 continue; /* with this thread */
1330 else
1331 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001332 }
1333
sewardj51c0aaf2002-04-25 01:32:10 +00001334 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1335 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001336 to become non-runnable. One special case: spot the
1337 client doing calls to exit() and take this as the cue
1338 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001339# if 0
1340 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001341 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001342 VG_(printf)("\nBEFORE\n");
1343 for (i = 10; i >= -10; i--)
1344 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1345 }
1346# endif
1347
sewardj83798bf2002-05-24 00:11:16 +00001348 /* Is the client exiting for good? */
sewardj018f7622002-05-15 21:13:39 +00001349 if (VG_(threads)[tid].m_eax == __NR_exit)
sewardj7e87e382002-05-03 19:09:05 +00001350 return VgSrc_ExitSyscall;
1351
sewardj83798bf2002-05-24 00:11:16 +00001352 /* Trap syscalls to __NR_sched_yield and just have this
1353 thread yield instead. Not essential, just an
1354 optimisation. */
1355 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1356 SET_EAX(tid, 0); /* syscall returns with success */
1357 goto stage1; /* find a new thread to run */
1358 }
1359
sewardj51c0aaf2002-04-25 01:32:10 +00001360 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001361
1362# if 0
1363 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001364 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001365 VG_(printf)("AFTER\n");
1366 for (i = 10; i >= -10; i--)
1367 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1368 }
1369# endif
1370
sewardj018f7622002-05-15 21:13:39 +00001371 if (VG_(threads)[tid].status == VgTs_Runnable)
sewardj51c0aaf2002-04-25 01:32:10 +00001372 continue; /* with this thread */
1373 else
1374 goto stage1;
1375 }
1376
sewardjd7fd4d22002-04-24 01:57:27 +00001377 /* It's an event we can't quickly deal with. Give up running
1378 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001379 break;
1380 }
1381
1382 /* ======================= Phase 3 of 3 =======================
1383 Handle non-trivial thread requests, mostly pthread stuff. */
1384
1385 /* Ok, we've fallen out of the dispatcher for a
1386 non-completely-trivial reason. First, update basic-block
1387 counters. */
1388
1389 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1390 vg_assert(done_this_time >= 0);
1391 VG_(bbs_to_go) -= (ULong)done_this_time;
1392 VG_(bbs_done) += (ULong)done_this_time;
1393
1394 if (0 && trc != VG_TRC_INNER_FASTMISS)
1395 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1396 tid, done_this_time, (Int)trc );
1397
1398 if (0 && trc != VG_TRC_INNER_FASTMISS)
1399 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1400 tid, VG_(bbs_done),
1401 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001402
sewardje663cb92002-04-12 10:26:32 +00001403 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001404 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001405
1406 switch (trc) {
1407
sewardje663cb92002-04-12 10:26:32 +00001408 case VG_TRC_INNER_COUNTERZERO:
1409 /* Timeslice is out. Let a new thread be scheduled,
1410 simply by doing nothing, causing us to arrive back at
1411 Phase 1. */
1412 if (VG_(bbs_to_go) == 0) {
1413 goto debug_stop;
1414 }
1415 vg_assert(VG_(dispatch_ctr) == 0);
1416 break;
1417
1418 case VG_TRC_UNRESUMABLE_SIGNAL:
1419 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1420 away. Again, do nothing, so we wind up back at Phase
1421 1, whereupon the signal will be "delivered". */
1422 break;
1423
sewardje663cb92002-04-12 10:26:32 +00001424 default:
1425 VG_(printf)("\ntrc = %d\n", trc);
1426 VG_(panic)("VG_(scheduler), phase 3: "
1427 "unexpected thread return code");
1428 /* NOTREACHED */
1429 break;
1430
1431 } /* switch (trc) */
1432
1433 /* That completes Phase 3 of 3. Return now to the top of the
1434 main scheduler loop, to Phase 1 of 3. */
1435
1436 } /* top-level scheduler loop */
1437
1438
1439 /* NOTREACHED */
1440 VG_(panic)("scheduler: post-main-loop ?!");
1441 /* NOTREACHED */
1442
1443 debug_stop:
1444 /* If we exited because of a debug stop, print the translation
1445 of the last block executed -- by translating it again, and
1446 throwing away the result. */
1447 VG_(printf)(
1448 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001449 VG_(translate)( &VG_(threads)[tid],
1450 VG_(threads)[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001451 VG_(printf)("\n");
1452 VG_(printf)(
1453 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1454
1455 return VgSrc_BbsDone;
1456}
1457
1458
1459/* ---------------------------------------------------------------------
1460 The pthread implementation.
1461 ------------------------------------------------------------------ */
1462
1463#include <pthread.h>
1464#include <errno.h>
1465
sewardjbf290b92002-05-01 02:28:01 +00001466#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001467 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001468
1469/* /usr/include/bits/pthreadtypes.h:
1470 typedef unsigned long int pthread_t;
1471*/
1472
sewardje663cb92002-04-12 10:26:32 +00001473
sewardj604ec3c2002-04-18 22:38:41 +00001474/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001475 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001476 -------------------------------------------------------- */
1477
sewardj20917d82002-05-28 01:36:45 +00001478/* We've decided to action a cancellation on tid. Make it jump to
1479 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1480 as the arg. */
1481static
1482void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1483{
1484 Char msg_buf[100];
1485 vg_assert(VG_(is_valid_tid)(tid));
1486 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1487 handler -- which is really thread_exit_wrapper() in
1488 vg_libpthread.c. */
1489 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1490 VG_(threads)[tid].m_esp -= 4;
1491 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1492 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1493 VG_(threads)[tid].status = VgTs_Runnable;
1494 /* Make sure we aren't cancelled again whilst handling this
1495 cancellation. */
1496 VG_(threads)[tid].cancel_st = False;
1497 if (VG_(clo_trace_sched)) {
1498 VG_(sprintf)(msg_buf,
1499 "jump to cancellation handler (hdlr = %p)",
1500 VG_(threads)[tid].cancel_pend);
1501 print_sched_event(tid, msg_buf);
1502 }
1503}
1504
1505
1506
sewardjb48e5002002-05-13 00:16:03 +00001507/* Release resources and generally clean up once a thread has finally
1508 disappeared. */
1509static
1510void cleanup_after_thread_exited ( ThreadId tid )
1511{
sewardj89f20fd2002-06-30 10:57:30 +00001512 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001513 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001514 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1515 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
sewardjb48e5002002-05-13 00:16:03 +00001516 /* Mark its stack no-access */
1517 if (VG_(clo_instrument) && tid != 1)
sewardj018f7622002-05-15 21:13:39 +00001518 VGM_(make_noaccess)( VG_(threads)[tid].stack_base,
1519 VG_(threads)[tid].stack_size );
sewardjb48e5002002-05-13 00:16:03 +00001520 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001521 thread, and get rid of signal handlers specifically arranged for
1522 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001523 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001524 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001525
1526 /* Clean up the waiting_fd table */
1527 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1528 if (vg_waiting_fds[i].tid == tid) {
1529 vg_waiting_fds[i].fd = -1; /* not in use */
1530 }
1531 }
sewardjb48e5002002-05-13 00:16:03 +00001532}
1533
1534
sewardj20917d82002-05-28 01:36:45 +00001535/* Look for matching pairs of threads waiting for joiners and threads
1536 waiting for joinees. For each such pair copy the return value of
1537 the joinee into the joiner, let the joiner resume and discard the
1538 joinee. */
1539static
1540void maybe_rendezvous_joiners_and_joinees ( void )
1541{
1542 Char msg_buf[100];
1543 void** thread_return;
1544 ThreadId jnr, jee;
1545
1546 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1547 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1548 continue;
1549 jee = VG_(threads)[jnr].joiner_jee_tid;
1550 if (jee == VG_INVALID_THREADID)
1551 continue;
1552 vg_assert(VG_(is_valid_tid)(jee));
1553 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1554 continue;
1555 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1556 joined by ... well, any thread. So let's do it! */
1557
1558 /* Copy return value to where joiner wants it. */
1559 thread_return = VG_(threads)[jnr].joiner_thread_return;
1560 if (thread_return != NULL) {
1561 /* CHECK thread_return writable */
sewardj5a3798b2002-06-04 23:24:22 +00001562 if (VG_(clo_instrument)
1563 && !VGM_(check_writable)( (Addr)thread_return,
1564 sizeof(void*), NULL))
1565 VG_(record_pthread_err)( jnr,
1566 "pthread_join: thread_return points to invalid location");
1567
sewardj20917d82002-05-28 01:36:45 +00001568 *thread_return = VG_(threads)[jee].joinee_retval;
1569 /* Not really right, since it makes the thread's return value
1570 appear to be defined even if it isn't. */
1571 if (VG_(clo_instrument))
1572 VGM_(make_readable)( (Addr)thread_return, sizeof(void*) );
1573 }
1574
1575 /* Joinee is discarded */
1576 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1577 cleanup_after_thread_exited ( jee );
1578 if (VG_(clo_trace_sched)) {
1579 VG_(sprintf)(msg_buf,
1580 "rendezvous with joinee %d. %d resumes, %d exits.",
1581 jee, jnr, jee );
1582 print_sched_event(jnr, msg_buf);
1583 }
1584
1585 /* joiner returns with success */
1586 VG_(threads)[jnr].status = VgTs_Runnable;
1587 SET_EDX(jnr, 0);
1588 }
1589}
1590
1591
sewardjccef2e62002-05-29 19:26:32 +00001592/* Nuke all threads other than tid. POSIX specifies that this should
1593 happen in __NR_exec, and after a __NR_fork() when I am the child,
1594 as POSIX requires. */
1595void VG_(nuke_all_threads_except) ( ThreadId me )
1596{
1597 ThreadId tid;
1598 for (tid = 1; tid < VG_N_THREADS; tid++) {
1599 if (tid == me
1600 || VG_(threads)[tid].status == VgTs_Empty)
1601 continue;
sewardjef037c72002-05-30 00:40:03 +00001602 if (0)
1603 VG_(printf)(
1604 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001605 VG_(threads)[tid].status = VgTs_Empty;
1606 cleanup_after_thread_exited( tid );
1607 }
1608}
1609
1610
sewardj20917d82002-05-28 01:36:45 +00001611/* -----------------------------------------------------------
1612 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1613 -------------------------------------------------------- */
1614
sewardje663cb92002-04-12 10:26:32 +00001615static
sewardj8ad94e12002-05-29 00:10:20 +00001616void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1617{
1618 Int sp;
1619 Char msg_buf[100];
1620 vg_assert(VG_(is_valid_tid)(tid));
1621 sp = VG_(threads)[tid].custack_used;
1622 if (VG_(clo_trace_sched)) {
1623 VG_(sprintf)(msg_buf,
1624 "cleanup_push (fn %p, arg %p) -> slot %d",
1625 cu->fn, cu->arg, sp);
1626 print_sched_event(tid, msg_buf);
1627 }
1628 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1629 if (sp == VG_N_CLEANUPSTACK)
1630 VG_(panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
1631 " Increase and recompile.");
1632 VG_(threads)[tid].custack[sp] = *cu;
1633 sp++;
1634 VG_(threads)[tid].custack_used = sp;
1635 SET_EDX(tid, 0);
1636}
1637
1638
1639static
1640void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1641{
1642 Int sp;
1643 Char msg_buf[100];
1644 vg_assert(VG_(is_valid_tid)(tid));
1645 sp = VG_(threads)[tid].custack_used;
1646 if (VG_(clo_trace_sched)) {
1647 VG_(sprintf)(msg_buf,
sewardj4dced352002-06-04 22:54:20 +00001648 "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001649 print_sched_event(tid, msg_buf);
1650 }
1651 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1652 if (sp == 0) {
1653 SET_EDX(tid, -1);
1654 return;
1655 }
1656 sp--;
1657 *cu = VG_(threads)[tid].custack[sp];
sewardj67a3bec2002-05-29 16:48:44 +00001658 if (VG_(clo_instrument))
1659 VGM_(make_readable)( (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001660 VG_(threads)[tid].custack_used = sp;
1661 SET_EDX(tid, 0);
1662}
1663
1664
1665static
sewardjff42d1d2002-05-22 13:17:31 +00001666void do_pthread_yield ( ThreadId tid )
1667{
1668 Char msg_buf[100];
1669 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001670 if (VG_(clo_trace_sched)) {
1671 VG_(sprintf)(msg_buf, "yield");
1672 print_sched_event(tid, msg_buf);
1673 }
1674 SET_EDX(tid, 0);
1675}
1676
1677
1678static
sewardj20917d82002-05-28 01:36:45 +00001679void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001680{
sewardj7989d0c2002-05-28 11:00:01 +00001681 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001682 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001683 if (VG_(clo_trace_sched)) {
1684 VG_(sprintf)(msg_buf, "testcancel");
1685 print_sched_event(tid, msg_buf);
1686 }
sewardj20917d82002-05-28 01:36:45 +00001687 if (/* is there a cancellation pending on this thread? */
1688 VG_(threads)[tid].cancel_pend != NULL
1689 && /* is this thread accepting cancellations? */
1690 VG_(threads)[tid].cancel_st) {
1691 /* Ok, let's do the cancellation. */
1692 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001693 } else {
sewardj20917d82002-05-28 01:36:45 +00001694 /* No, we keep going. */
1695 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001696 }
sewardje663cb92002-04-12 10:26:32 +00001697}
1698
1699
1700static
sewardj20917d82002-05-28 01:36:45 +00001701void do__set_cancelstate ( ThreadId tid, Int state )
1702{
1703 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001704 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001705 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001706 if (VG_(clo_trace_sched)) {
1707 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1708 state==PTHREAD_CANCEL_ENABLE
1709 ? "ENABLE"
1710 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1711 print_sched_event(tid, msg_buf);
1712 }
sewardj20917d82002-05-28 01:36:45 +00001713 old_st = VG_(threads)[tid].cancel_st;
1714 if (state == PTHREAD_CANCEL_ENABLE) {
1715 VG_(threads)[tid].cancel_st = True;
1716 } else
1717 if (state == PTHREAD_CANCEL_DISABLE) {
1718 VG_(threads)[tid].cancel_st = False;
1719 } else {
1720 VG_(panic)("do__set_cancelstate");
1721 }
1722 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1723 : PTHREAD_CANCEL_DISABLE);
1724}
1725
1726
1727static
1728void do__set_canceltype ( ThreadId tid, Int type )
1729{
1730 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001731 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001732 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001733 if (VG_(clo_trace_sched)) {
1734 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1735 type==PTHREAD_CANCEL_ASYNCHRONOUS
1736 ? "ASYNCHRONOUS"
1737 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1738 print_sched_event(tid, msg_buf);
1739 }
sewardj20917d82002-05-28 01:36:45 +00001740 old_ty = VG_(threads)[tid].cancel_ty;
1741 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1742 VG_(threads)[tid].cancel_ty = False;
1743 } else
1744 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001745 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001746 } else {
1747 VG_(panic)("do__set_canceltype");
1748 }
1749 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1750 : PTHREAD_CANCEL_ASYNCHRONOUS);
1751}
1752
1753
sewardj7989d0c2002-05-28 11:00:01 +00001754/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001755static
sewardj7989d0c2002-05-28 11:00:01 +00001756void do__set_or_get_detach ( ThreadId tid,
1757 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001758{
sewardj7989d0c2002-05-28 11:00:01 +00001759 ThreadId i;
1760 Char msg_buf[100];
1761 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1762 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001763 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001764 if (VG_(clo_trace_sched)) {
1765 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1766 what==0 ? "not-detached" : (
1767 what==1 ? "detached" : (
1768 what==2 ? "fetch old value" : "???")),
1769 det );
1770 print_sched_event(tid, msg_buf);
1771 }
1772
1773 if (!VG_(is_valid_tid)(det)) {
1774 SET_EDX(tid, -1);
1775 return;
1776 }
1777
sewardj20917d82002-05-28 01:36:45 +00001778 switch (what) {
1779 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001780 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001781 return;
sewardj7989d0c2002-05-28 11:00:01 +00001782 case 1: /* set detached. If someone is in a join-wait for det,
1783 do not detach. */
1784 for (i = 1; i < VG_N_THREADS; i++) {
1785 if (VG_(threads)[i].status == VgTs_WaitJoinee
1786 && VG_(threads)[i].joiner_jee_tid == det) {
1787 SET_EDX(tid, 0);
1788 if (VG_(clo_trace_sched)) {
1789 VG_(sprintf)(msg_buf,
1790 "tid %d not detached because %d in join-wait for it %d",
1791 det, i);
1792 print_sched_event(tid, msg_buf);
1793 }
1794 return;
1795 }
1796 }
1797 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001798 SET_EDX(tid, 0);
1799 return;
1800 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001801 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001802 SET_EDX(tid, 0);
1803 return;
1804 default:
1805 VG_(panic)("do__set_or_get_detach");
1806 }
1807}
1808
1809
1810static
1811void do__set_cancelpend ( ThreadId tid,
1812 ThreadId cee,
1813 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001814{
1815 Char msg_buf[100];
1816
sewardj20917d82002-05-28 01:36:45 +00001817 vg_assert(VG_(is_valid_tid)(tid));
1818 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1819
sewardj7989d0c2002-05-28 11:00:01 +00001820 if (!VG_(is_valid_tid)(cee)) {
1821 if (VG_(clo_trace_sched)) {
1822 VG_(sprintf)(msg_buf,
1823 "set_cancelpend for invalid tid %d", cee);
1824 print_sched_event(tid, msg_buf);
1825 }
sewardj4dced352002-06-04 22:54:20 +00001826 VG_(record_pthread_err)( tid,
1827 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00001828 SET_EDX(tid, -VKI_ESRCH);
1829 return;
1830 }
sewardj20917d82002-05-28 01:36:45 +00001831
1832 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
1833
1834 if (VG_(clo_trace_sched)) {
1835 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001836 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00001837 cancelpend_hdlr, tid);
1838 print_sched_event(cee, msg_buf);
1839 }
1840
1841 /* Thread doing the cancelling returns with success. */
1842 SET_EDX(tid, 0);
1843
1844 /* Perhaps we can nuke the cancellee right now? */
1845 do__testcancel(cee);
1846}
1847
1848
1849static
1850void do_pthread_join ( ThreadId tid,
1851 ThreadId jee, void** thread_return )
1852{
1853 Char msg_buf[100];
1854 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00001855 /* jee, the joinee, is the thread specified as an arg in thread
1856 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00001857 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001858 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001859
1860 if (jee == tid) {
sewardj4dced352002-06-04 22:54:20 +00001861 VG_(record_pthread_err)( tid,
1862 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00001863 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00001864 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001865 return;
1866 }
1867
sewardj20917d82002-05-28 01:36:45 +00001868 /* Flush any completed pairs, so as to make sure what we're looking
1869 at is up-to-date. */
1870 maybe_rendezvous_joiners_and_joinees();
1871
1872 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00001873 if (jee < 0
1874 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00001875 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00001876 /* Invalid thread to join to. */
sewardj4dced352002-06-04 22:54:20 +00001877 VG_(record_pthread_err)( tid,
1878 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00001879 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00001880 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001881 return;
1882 }
1883
sewardj20917d82002-05-28 01:36:45 +00001884 /* Is anyone else already in a join-wait for jee? */
1885 for (i = 1; i < VG_N_THREADS; i++) {
1886 if (i == tid) continue;
1887 if (VG_(threads)[i].status == VgTs_WaitJoinee
1888 && VG_(threads)[i].joiner_jee_tid == jee) {
1889 /* Someone already did join on this thread */
sewardj4dced352002-06-04 22:54:20 +00001890 VG_(record_pthread_err)( tid,
1891 "pthread_join: another thread already "
1892 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00001893 SET_EDX(tid, EINVAL);
1894 VG_(threads)[tid].status = VgTs_Runnable;
1895 return;
1896 }
sewardje663cb92002-04-12 10:26:32 +00001897 }
1898
sewardj20917d82002-05-28 01:36:45 +00001899 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00001900 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00001901 VG_(threads)[tid].joiner_thread_return = thread_return;
1902 VG_(threads)[tid].joiner_jee_tid = jee;
1903
1904 /* Look for matching joiners and joinees and do the right thing. */
1905 maybe_rendezvous_joiners_and_joinees();
1906
1907 /* Return value is irrelevant since this this thread becomes
1908 non-runnable. maybe_resume_joiner() will cause it to return the
1909 right value when it resumes. */
1910
sewardj8937c812002-04-12 20:12:20 +00001911 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00001912 VG_(sprintf)(msg_buf,
1913 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00001914 print_sched_event(tid, msg_buf);
1915 }
sewardje663cb92002-04-12 10:26:32 +00001916}
1917
1918
sewardj20917d82002-05-28 01:36:45 +00001919/* ( void* ): calling thread waits for joiner and returns the void* to
1920 it. This is one of two ways in which a thread can finally exit --
1921 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00001922static
sewardj20917d82002-05-28 01:36:45 +00001923void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00001924{
sewardj20917d82002-05-28 01:36:45 +00001925 Char msg_buf[100];
1926 vg_assert(VG_(is_valid_tid)(tid));
1927 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1928 if (VG_(clo_trace_sched)) {
1929 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001930 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00001931 print_sched_event(tid, msg_buf);
1932 }
1933 VG_(threads)[tid].status = VgTs_WaitJoiner;
1934 VG_(threads)[tid].joinee_retval = retval;
1935 maybe_rendezvous_joiners_and_joinees();
1936}
1937
1938
1939/* ( no-args ): calling thread disappears from the system forever.
1940 Reclaim resources. */
1941static
1942void do__quit ( ThreadId tid )
1943{
1944 Char msg_buf[100];
1945 vg_assert(VG_(is_valid_tid)(tid));
1946 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1947 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
1948 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00001949 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00001950 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00001951 print_sched_event(tid, msg_buf);
1952 }
1953 /* Return value is irrelevant; this thread will not get
1954 rescheduled. */
1955}
1956
1957
1958/* Should never be entered. If it is, will be on the simulated
1959 CPU. */
1960static
1961void do__apply_in_new_thread_bogusRA ( void )
1962{
1963 VG_(panic)("do__apply_in_new_thread_bogusRA");
1964}
1965
1966/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
1967 MUST NOT return -- ever. Eventually it will do either __QUIT or
1968 __WAIT_JOINER. Return the child tid to the parent. */
1969static
1970void do__apply_in_new_thread ( ThreadId parent_tid,
1971 void* (*fn)(void *),
1972 void* arg )
1973{
sewardje663cb92002-04-12 10:26:32 +00001974 Addr new_stack;
1975 UInt new_stk_szb;
1976 ThreadId tid;
1977 Char msg_buf[100];
1978
1979 /* Paranoia ... */
1980 vg_assert(sizeof(pthread_t) == sizeof(UInt));
1981
sewardj018f7622002-05-15 21:13:39 +00001982 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00001983
sewardj1e8cdc92002-04-18 11:37:52 +00001984 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00001985
1986 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00001987 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00001988 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001989
1990 /* Copy the parent's CPU state into the child's, in a roundabout
1991 way (via baseBlock). */
1992 VG_(load_thread_state)(parent_tid);
1993 VG_(save_thread_state)(tid);
1994
1995 /* Consider allocating the child a stack, if the one it already has
1996 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00001997 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00001998
sewardj018f7622002-05-15 21:13:39 +00001999 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002000 /* Again, for good measure :) We definitely don't want to be
2001 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002002 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002003 /* for now, we don't handle the case of anything other than
2004 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002005 vg_assert(VG_(threads)[tid].stack_size == 0);
2006 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002007 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2008 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002009 VG_(threads)[tid].stack_base = new_stack;
2010 VG_(threads)[tid].stack_size = new_stk_szb;
2011 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002012 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002013 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002014 }
sewardj1e8cdc92002-04-18 11:37:52 +00002015
sewardj018f7622002-05-15 21:13:39 +00002016 VG_(threads)[tid].m_esp
2017 = VG_(threads)[tid].stack_base
2018 + VG_(threads)[tid].stack_size
sewardj1e8cdc92002-04-18 11:37:52 +00002019 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
2020
sewardje663cb92002-04-12 10:26:32 +00002021 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00002022 VGM_(make_noaccess)( VG_(threads)[tid].m_esp,
sewardje663cb92002-04-12 10:26:32 +00002023 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
2024
2025 /* push arg */
sewardj018f7622002-05-15 21:13:39 +00002026 VG_(threads)[tid].m_esp -= 4;
2027 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)arg;
sewardje663cb92002-04-12 10:26:32 +00002028
sewardj20917d82002-05-28 01:36:45 +00002029 /* push (bogus) return address */
sewardj018f7622002-05-15 21:13:39 +00002030 VG_(threads)[tid].m_esp -= 4;
sewardj20917d82002-05-28 01:36:45 +00002031 * (UInt*)(VG_(threads)[tid].m_esp)
2032 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002033
2034 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00002035 VGM_(make_readable)( VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002036
2037 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002038 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002039
sewardj8937c812002-04-12 20:12:20 +00002040 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00002041 VG_(sprintf)(msg_buf,
2042 "new thread, created by %d", parent_tid );
2043 print_sched_event(tid, msg_buf);
2044 }
2045
sewardj20917d82002-05-28 01:36:45 +00002046 /* Create new thread with default attrs:
2047 deferred cancellation, not detached
2048 */
2049 mostly_clear_thread_record(tid);
2050 VG_(threads)[tid].status = VgTs_Runnable;
sewardj5f07b662002-04-23 16:52:51 +00002051
sewardj018f7622002-05-15 21:13:39 +00002052 /* We inherit our parent's signal mask. */
2053 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002054 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002055
sewardj20917d82002-05-28 01:36:45 +00002056 /* return child's tid to parent */
2057 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002058}
2059
2060
sewardj604ec3c2002-04-18 22:38:41 +00002061/* -----------------------------------------------------------
2062 MUTEXes
2063 -------------------------------------------------------- */
2064
sewardj604ec3c2002-04-18 22:38:41 +00002065/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002066 typedef struct
2067 {
2068 int __m_reserved; -- Reserved for future use
2069 int __m_count; -- Depth of recursive locking
2070 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2071 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2072 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2073 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002074
sewardj6072c362002-04-19 14:40:57 +00002075 #define PTHREAD_MUTEX_INITIALIZER \
2076 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2077 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2078 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2079 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2080 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2081 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2082 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002083
sewardj6072c362002-04-19 14:40:57 +00002084 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002085
sewardj6072c362002-04-19 14:40:57 +00002086 __m_kind never changes and indicates whether or not it is recursive.
2087
2088 __m_count indicates the lock count; if 0, the mutex is not owned by
2089 anybody.
2090
2091 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2092 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2093 statically initialised mutexes correctly appear
2094 to belong to nobody.
2095
2096 In summary, a not-in-use mutex is distinguised by having __m_owner
2097 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2098 conditions holds, the other should too.
2099
2100 There is no linked list of threads waiting for this mutex. Instead
2101 a thread in WaitMX state points at the mutex with its waited_on_mx
2102 field. This makes _unlock() inefficient, but simple to implement the
2103 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002104
sewardj604ec3c2002-04-18 22:38:41 +00002105 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002106 deals with that for us.
2107*/
sewardje663cb92002-04-12 10:26:32 +00002108
sewardj3b5d8862002-04-20 13:53:23 +00002109/* Helper fns ... */
2110static
2111void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2112 Char* caller )
2113{
2114 Int i;
2115 Char msg_buf[100];
2116
2117 /* Find some arbitrary thread waiting on this mutex, and make it
2118 runnable. If none are waiting, mark the mutex as not held. */
2119 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002120 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002121 continue;
sewardj018f7622002-05-15 21:13:39 +00002122 if (VG_(threads)[i].status == VgTs_WaitMX
2123 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002124 break;
2125 }
2126
2127 vg_assert(i <= VG_N_THREADS);
2128 if (i == VG_N_THREADS) {
2129 /* Nobody else is waiting on it. */
2130 mutex->__m_count = 0;
2131 mutex->__m_owner = VG_INVALID_THREADID;
2132 } else {
2133 /* Notionally transfer the hold to thread i, whose
2134 pthread_mutex_lock() call now returns with 0 (success). */
2135 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002136 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002137 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002138 VG_(threads)[i].status = VgTs_Runnable;
2139 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002140 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002141
2142 if (VG_(clo_trace_pthread_level) >= 1) {
2143 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2144 caller, mutex );
2145 print_pthread_event(i, msg_buf);
2146 }
2147 }
2148}
2149
sewardje663cb92002-04-12 10:26:32 +00002150
2151static
sewardj30671ff2002-04-21 00:13:57 +00002152void do_pthread_mutex_lock( ThreadId tid,
2153 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002154 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002155{
sewardj30671ff2002-04-21 00:13:57 +00002156 Char msg_buf[100];
2157 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002158 = is_trylock ? "pthread_mutex_trylock"
2159 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002160
sewardj604ec3c2002-04-18 22:38:41 +00002161 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002162 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002163 print_pthread_event(tid, msg_buf);
2164 }
2165
2166 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002167 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002168 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002169
2170 /* POSIX doesn't mandate this, but for sanity ... */
2171 if (mutex == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002172 VG_(record_pthread_err)( tid,
2173 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002174 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002175 return;
2176 }
2177
sewardj604ec3c2002-04-18 22:38:41 +00002178 /* More paranoia ... */
2179 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002180# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002181 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002182 case PTHREAD_MUTEX_ADAPTIVE_NP:
2183# endif
sewardja1679dd2002-05-10 22:31:40 +00002184# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002185 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002186# endif
sewardj604ec3c2002-04-18 22:38:41 +00002187 case PTHREAD_MUTEX_RECURSIVE_NP:
2188 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002189 if (mutex->__m_count >= 0) break;
2190 /* else fall thru */
2191 default:
sewardj4dced352002-06-04 22:54:20 +00002192 VG_(record_pthread_err)( tid,
2193 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002194 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002195 return;
sewardje663cb92002-04-12 10:26:32 +00002196 }
2197
sewardj604ec3c2002-04-18 22:38:41 +00002198 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002199
sewardjb48e5002002-05-13 00:16:03 +00002200 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002201
2202 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002203 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002204 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002205 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002206 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002207 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002208 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002209 if (0)
2210 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2211 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002212 return;
2213 } else {
sewardj30671ff2002-04-21 00:13:57 +00002214 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002215 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002216 else
sewardjc3bd5f52002-05-01 03:24:23 +00002217 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002218 return;
2219 }
2220 } else {
sewardj6072c362002-04-19 14:40:57 +00002221 /* Someone else has it; we have to wait. Mark ourselves
2222 thusly. */
sewardj05553872002-04-20 20:53:17 +00002223 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002224 if (is_trylock) {
2225 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002226 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002227 } else {
sewardj018f7622002-05-15 21:13:39 +00002228 VG_(threads)[tid].status = VgTs_WaitMX;
2229 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002230 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002231 if (VG_(clo_trace_pthread_level) >= 1) {
2232 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2233 caller, mutex );
2234 print_pthread_event(tid, msg_buf);
2235 }
2236 }
sewardje663cb92002-04-12 10:26:32 +00002237 return;
2238 }
sewardjf8f819e2002-04-17 23:21:37 +00002239
sewardje663cb92002-04-12 10:26:32 +00002240 } else {
sewardj6072c362002-04-19 14:40:57 +00002241 /* Nobody owns it. Sanity check ... */
2242 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002243 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002244 mutex->__m_count = 1;
2245 mutex->__m_owner = (_pthread_descr)tid;
sewardje663cb92002-04-12 10:26:32 +00002246 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002247 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002248 }
sewardjf8f819e2002-04-17 23:21:37 +00002249
sewardje663cb92002-04-12 10:26:32 +00002250}
2251
2252
2253static
2254void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002255 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002256{
sewardj3b5d8862002-04-20 13:53:23 +00002257 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002258
sewardj45b4b372002-04-16 22:50:32 +00002259 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002260 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002261 print_pthread_event(tid, msg_buf);
2262 }
2263
sewardj604ec3c2002-04-18 22:38:41 +00002264 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002265 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002266 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002267
2268 if (mutex == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002269 VG_(record_pthread_err)( tid,
2270 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002271 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002272 return;
2273 }
2274
2275 /* More paranoia ... */
2276 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002277# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002278 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002279 case PTHREAD_MUTEX_ADAPTIVE_NP:
2280# endif
sewardja1679dd2002-05-10 22:31:40 +00002281# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002282 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002283# endif
sewardj604ec3c2002-04-18 22:38:41 +00002284 case PTHREAD_MUTEX_RECURSIVE_NP:
2285 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002286 if (mutex->__m_count >= 0) break;
2287 /* else fall thru */
2288 default:
sewardj4dced352002-06-04 22:54:20 +00002289 VG_(record_pthread_err)( tid,
2290 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002291 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002292 return;
2293 }
sewardje663cb92002-04-12 10:26:32 +00002294
2295 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002296 if (mutex->__m_count == 0) {
2297 /* nobody holds it */
2298 VG_(record_pthread_err)( tid,
2299 "pthread_mutex_unlock: mutex is not locked");
2300 SET_EDX(tid, EPERM);
2301 return;
2302 }
2303
2304 if ((ThreadId)mutex->__m_owner != tid) {
2305 /* we don't hold it */
2306 VG_(record_pthread_err)( tid,
2307 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002308 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002309 return;
2310 }
2311
sewardjf8f819e2002-04-17 23:21:37 +00002312 /* If it's a multiply-locked recursive mutex, just decrement the
2313 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002314 if (mutex->__m_count > 1) {
2315 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2316 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002317 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002318 return;
2319 }
2320
sewardj604ec3c2002-04-18 22:38:41 +00002321 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002322 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002323 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002324 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002325
sewardj3b5d8862002-04-20 13:53:23 +00002326 /* Release at max one thread waiting on this mutex. */
2327 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002328
sewardj3b5d8862002-04-20 13:53:23 +00002329 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002330 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002331}
2332
2333
sewardj6072c362002-04-19 14:40:57 +00002334/* -----------------------------------------------------------
2335 CONDITION VARIABLES
2336 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002337
sewardj6072c362002-04-19 14:40:57 +00002338/* The relevant native types are as follows:
2339 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002340
sewardj6072c362002-04-19 14:40:57 +00002341 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2342 typedef struct
2343 {
2344 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2345 _pthread_descr __c_waiting; -- Threads waiting on this condition
2346 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002347
sewardj6072c362002-04-19 14:40:57 +00002348 -- Attribute for conditionally variables.
2349 typedef struct
2350 {
2351 int __dummy;
2352 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002353
sewardj6072c362002-04-19 14:40:57 +00002354 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002355
sewardj3b5d8862002-04-20 13:53:23 +00002356 We don't use any fields of pthread_cond_t for anything at all.
2357 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002358
2359 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002360 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002361
sewardj77e466c2002-04-14 02:29:29 +00002362
sewardj5f07b662002-04-23 16:52:51 +00002363static
2364void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2365{
2366 Char msg_buf[100];
2367 pthread_mutex_t* mx;
2368 pthread_cond_t* cv;
2369
sewardjb48e5002002-05-13 00:16:03 +00002370 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002371 && VG_(threads)[tid].status == VgTs_WaitCV
2372 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2373 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002374 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002375 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002376 vg_assert(cv != NULL);
2377
2378 if (mx->__m_owner == VG_INVALID_THREADID) {
2379 /* Currently unheld; hand it out to thread tid. */
2380 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002381 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002382 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002383 VG_(threads)[tid].associated_cv = NULL;
2384 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002385 mx->__m_owner = (_pthread_descr)tid;
2386 mx->__m_count = 1;
2387
2388 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002389 VG_(sprintf)(msg_buf,
2390 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2391 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002392 print_pthread_event(tid, msg_buf);
2393 }
2394 } else {
2395 /* Currently held. Make thread tid be blocked on it. */
2396 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002397 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002398 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002399 VG_(threads)[tid].associated_cv = NULL;
2400 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002401 if (VG_(clo_trace_pthread_level) >= 1) {
2402 VG_(sprintf)(msg_buf,
2403 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2404 cv, mx );
2405 print_pthread_event(tid, msg_buf);
2406 }
2407
2408 }
2409}
2410
2411
sewardj3b5d8862002-04-20 13:53:23 +00002412static
2413void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2414 Int n_to_release,
2415 Char* caller )
2416{
2417 Int i;
2418 Char msg_buf[100];
2419 pthread_mutex_t* mx;
2420
2421 while (True) {
2422 if (n_to_release == 0)
2423 return;
2424
2425 /* Find a thread waiting on this CV. */
2426 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002427 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002428 continue;
sewardj018f7622002-05-15 21:13:39 +00002429 if (VG_(threads)[i].status == VgTs_WaitCV
2430 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002431 break;
2432 }
2433 vg_assert(i <= VG_N_THREADS);
2434
2435 if (i == VG_N_THREADS) {
2436 /* Nobody else is waiting on it. */
2437 return;
2438 }
2439
sewardj018f7622002-05-15 21:13:39 +00002440 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002441 vg_assert(mx != NULL);
2442
2443 if (mx->__m_owner == VG_INVALID_THREADID) {
2444 /* Currently unheld; hand it out to thread i. */
2445 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002446 VG_(threads)[i].status = VgTs_Runnable;
2447 VG_(threads)[i].associated_cv = NULL;
2448 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002449 mx->__m_owner = (_pthread_descr)i;
2450 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002451 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002452
2453 if (VG_(clo_trace_pthread_level) >= 1) {
2454 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2455 caller, cond, mx );
2456 print_pthread_event(i, msg_buf);
2457 }
2458
2459 } else {
2460 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002461 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002462 VG_(threads)[i].status = VgTs_WaitMX;
2463 VG_(threads)[i].associated_cv = NULL;
2464 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002465 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002466
2467 if (VG_(clo_trace_pthread_level) >= 1) {
2468 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2469 caller, cond, mx );
2470 print_pthread_event(i, msg_buf);
2471 }
2472
2473 }
2474
2475 n_to_release--;
2476 }
2477}
2478
2479
2480static
2481void do_pthread_cond_wait ( ThreadId tid,
2482 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002483 pthread_mutex_t *mutex,
2484 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002485{
2486 Char msg_buf[100];
2487
sewardj5f07b662002-04-23 16:52:51 +00002488 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2489 ms_end is the ending millisecond. */
2490
sewardj3b5d8862002-04-20 13:53:23 +00002491 /* pre: mutex should be a valid mutex and owned by tid. */
2492 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002493 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2494 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002495 print_pthread_event(tid, msg_buf);
2496 }
2497
2498 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002499 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002500 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002501
2502 if (mutex == NULL || cond == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002503 VG_(record_pthread_err)( tid,
2504 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002505 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002506 return;
2507 }
2508
2509 /* More paranoia ... */
2510 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002511# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002512 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002513 case PTHREAD_MUTEX_ADAPTIVE_NP:
2514# endif
sewardja1679dd2002-05-10 22:31:40 +00002515# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002516 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002517# endif
sewardj3b5d8862002-04-20 13:53:23 +00002518 case PTHREAD_MUTEX_RECURSIVE_NP:
2519 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002520 if (mutex->__m_count >= 0) break;
2521 /* else fall thru */
2522 default:
sewardj4dced352002-06-04 22:54:20 +00002523 VG_(record_pthread_err)( tid,
2524 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002525 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002526 return;
2527 }
2528
2529 /* Barf if we don't currently hold the mutex. */
2530 if (mutex->__m_count == 0 /* nobody holds it */
2531 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardj4dced352002-06-04 22:54:20 +00002532 VG_(record_pthread_err)( tid,
2533 "pthread_cond_wait/timedwait: mutex is unlocked "
2534 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002535 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002536 return;
2537 }
2538
2539 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002540 VG_(threads)[tid].status = VgTs_WaitCV;
2541 VG_(threads)[tid].associated_cv = cond;
2542 VG_(threads)[tid].associated_mx = mutex;
2543 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002544
2545 if (VG_(clo_trace_pthread_level) >= 1) {
2546 VG_(sprintf)(msg_buf,
2547 "pthread_cond_wait cv %p, mx %p: BLOCK",
2548 cond, mutex );
2549 print_pthread_event(tid, msg_buf);
2550 }
2551
2552 /* Release the mutex. */
2553 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2554}
2555
2556
2557static
2558void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2559 Bool broadcast,
2560 pthread_cond_t *cond )
2561{
2562 Char msg_buf[100];
2563 Char* caller
2564 = broadcast ? "pthread_cond_broadcast"
2565 : "pthread_cond_signal ";
2566
2567 if (VG_(clo_trace_pthread_level) >= 2) {
2568 VG_(sprintf)(msg_buf, "%s cv %p ...",
2569 caller, cond );
2570 print_pthread_event(tid, msg_buf);
2571 }
2572
2573 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002574 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002575 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002576
2577 if (cond == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002578 VG_(record_pthread_err)( tid,
2579 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002580 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002581 return;
2582 }
2583
2584 release_N_threads_waiting_on_cond (
2585 cond,
2586 broadcast ? VG_N_THREADS : 1,
2587 caller
2588 );
2589
sewardjc3bd5f52002-05-01 03:24:23 +00002590 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002591}
2592
sewardj77e466c2002-04-14 02:29:29 +00002593
sewardj5f07b662002-04-23 16:52:51 +00002594/* -----------------------------------------------------------
2595 THREAD SPECIFIC DATA
2596 -------------------------------------------------------- */
2597
2598static __inline__
2599Bool is_valid_key ( ThreadKey k )
2600{
2601 /* k unsigned; hence no < 0 check */
2602 if (k >= VG_N_THREAD_KEYS) return False;
2603 if (!vg_thread_keys[k].inuse) return False;
2604 return True;
2605}
2606
2607static
2608void do_pthread_key_create ( ThreadId tid,
2609 pthread_key_t* key,
2610 void (*destructor)(void*) )
2611{
2612 Int i;
2613 Char msg_buf[100];
2614
2615 if (VG_(clo_trace_pthread_level) >= 1) {
2616 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2617 key, destructor );
2618 print_pthread_event(tid, msg_buf);
2619 }
2620
2621 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002622 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002623 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002624
2625 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2626 if (!vg_thread_keys[i].inuse)
2627 break;
2628
2629 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002630 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002631 return;
2632 */
2633 VG_(panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2634 " increase and recompile");
2635 }
2636
sewardj870497a2002-05-29 01:06:47 +00002637 vg_thread_keys[i].inuse = True;
2638 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002639
sewardj5a3798b2002-06-04 23:24:22 +00002640 /* check key for addressibility */
2641 if (VG_(clo_instrument)
2642 && !VGM_(check_writable)( (Addr)key,
2643 sizeof(pthread_key_t), NULL))
2644 VG_(record_pthread_err)( tid,
2645 "pthread_key_create: key points to invalid location");
sewardj5f07b662002-04-23 16:52:51 +00002646 *key = i;
sewardjc3bd5f52002-05-01 03:24:23 +00002647 if (VG_(clo_instrument))
2648 VGM_(make_readable)( (Addr)key, sizeof(pthread_key_t) );
2649
2650 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002651}
2652
2653
2654static
2655void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2656{
2657 Char msg_buf[100];
2658 if (VG_(clo_trace_pthread_level) >= 1) {
2659 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2660 key );
2661 print_pthread_event(tid, msg_buf);
2662 }
2663
sewardjb48e5002002-05-13 00:16:03 +00002664 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002665 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002666
2667 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002668 VG_(record_pthread_err)( tid,
2669 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002670 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002671 return;
2672 }
2673
2674 vg_thread_keys[key].inuse = False;
2675
2676 /* Optional. We're not required to do this, although it shouldn't
2677 make any difference to programs which use the key/specifics
2678 functions correctly. */
sewardj3b13f0e2002-04-25 20:17:29 +00002679# if 1
sewardj5f07b662002-04-23 16:52:51 +00002680 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00002681 if (VG_(threads)[tid].status != VgTs_Empty)
2682 VG_(threads)[tid].specifics[key] = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002683 }
sewardj3b13f0e2002-04-25 20:17:29 +00002684# endif
sewardj5f07b662002-04-23 16:52:51 +00002685}
2686
2687
2688static
2689void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
2690{
2691 Char msg_buf[100];
2692 if (VG_(clo_trace_pthread_level) >= 1) {
2693 VG_(sprintf)(msg_buf, "pthread_getspecific key %d",
2694 key );
2695 print_pthread_event(tid, msg_buf);
2696 }
2697
sewardjb48e5002002-05-13 00:16:03 +00002698 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002699 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002700
2701 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002702 VG_(record_pthread_err)( tid,
2703 "pthread_getspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002704 SET_EDX(tid, (UInt)NULL);
sewardj5f07b662002-04-23 16:52:51 +00002705 return;
2706 }
2707
sewardj018f7622002-05-15 21:13:39 +00002708 SET_EDX(tid, (UInt)VG_(threads)[tid].specifics[key]);
sewardj5f07b662002-04-23 16:52:51 +00002709}
2710
2711
2712static
2713void do_pthread_setspecific ( ThreadId tid,
2714 pthread_key_t key,
2715 void *pointer )
2716{
2717 Char msg_buf[100];
2718 if (VG_(clo_trace_pthread_level) >= 1) {
2719 VG_(sprintf)(msg_buf, "pthread_setspecific key %d, ptr %p",
2720 key, pointer );
2721 print_pthread_event(tid, msg_buf);
2722 }
2723
sewardjb48e5002002-05-13 00:16:03 +00002724 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002725 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002726
2727 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002728 VG_(record_pthread_err)( tid,
2729 "pthread_setspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002730 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002731 return;
2732 }
2733
sewardj018f7622002-05-15 21:13:39 +00002734 VG_(threads)[tid].specifics[key] = pointer;
sewardjc3bd5f52002-05-01 03:24:23 +00002735 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002736}
2737
2738
sewardj870497a2002-05-29 01:06:47 +00002739/* Helper for calling destructors at thread exit. If key is valid,
2740 copy the thread's specific value into cu->arg and put the *key*'s
2741 destructor fn address in cu->fn. Then return 0 to the caller.
2742 Otherwise return non-zero to the caller. */
2743static
2744void do__get_key_destr_and_spec ( ThreadId tid,
2745 pthread_key_t key,
2746 CleanupEntry* cu )
2747{
2748 Char msg_buf[100];
2749 if (VG_(clo_trace_pthread_level) >= 1) {
2750 VG_(sprintf)(msg_buf,
2751 "get_key_destr_and_arg (key = %d)", key );
2752 print_pthread_event(tid, msg_buf);
2753 }
2754 vg_assert(VG_(is_valid_tid)(tid));
2755 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
2756 if (!vg_thread_keys[key].inuse) {
2757 SET_EDX(tid, -1);
2758 return;
2759 }
2760 cu->fn = vg_thread_keys[key].destructor;
2761 cu->arg = VG_(threads)[tid].specifics[key];
sewardjd140e442002-05-29 01:21:19 +00002762 if (VG_(clo_instrument))
2763 VGM_(make_readable)( (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00002764 SET_EDX(tid, 0);
2765}
2766
2767
sewardjb48e5002002-05-13 00:16:03 +00002768/* ---------------------------------------------------
2769 SIGNALS
2770 ------------------------------------------------ */
2771
2772/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002773 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2774 for OK and 1 for some kind of addressing error, which the
2775 vg_libpthread.c routine turns into return values 0 and EFAULT
2776 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002777static
2778void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002779 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002780 vki_ksigset_t* newmask,
2781 vki_ksigset_t* oldmask )
2782{
2783 Char msg_buf[100];
2784 if (VG_(clo_trace_pthread_level) >= 1) {
2785 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00002786 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
2787 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002788 print_pthread_event(tid, msg_buf);
2789 }
2790
2791 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002792 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002793
2794 if (VG_(clo_instrument)) {
sewardj5a3798b2002-06-04 23:24:22 +00002795 /* check newmask/oldmask are addressible/defined */
sewardj0076f542002-06-16 11:37:06 +00002796 if (newmask
sewardj5a3798b2002-06-04 23:24:22 +00002797 && !VGM_(check_readable)( (Addr)newmask,
2798 sizeof(vki_ksigset_t), NULL))
2799 VG_(record_pthread_err)( tid,
2800 "pthread_sigmask: newmask contains "
2801 "unaddressible or undefined bytes");
sewardj0076f542002-06-16 11:37:06 +00002802 if (oldmask
2803 && !VGM_(check_writable)( (Addr)oldmask,
sewardj5a3798b2002-06-04 23:24:22 +00002804 sizeof(vki_ksigset_t), NULL))
2805 VG_(record_pthread_err)( tid,
2806 "pthread_sigmask: oldmask contains "
2807 "unaddressible bytes");
sewardjb48e5002002-05-13 00:16:03 +00002808 }
2809
sewardj018f7622002-05-15 21:13:39 +00002810 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002811
sewardj5a3798b2002-06-04 23:24:22 +00002812 if (oldmask && VG_(clo_instrument)) {
2813 VGM_(make_readable)( (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00002814 }
2815
sewardj018f7622002-05-15 21:13:39 +00002816 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00002817 SET_EDX(tid, 0);
2818}
2819
2820
2821static
2822void do_sigwait ( ThreadId tid,
2823 vki_ksigset_t* set,
2824 Int* sig )
2825{
sewardj018f7622002-05-15 21:13:39 +00002826 vki_ksigset_t irrelevant_sigmask;
2827 Char msg_buf[100];
2828
sewardjb48e5002002-05-13 00:16:03 +00002829 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
2830 VG_(sprintf)(msg_buf,
2831 "suspend due to sigwait(): set %p, sig %p",
2832 set, sig );
2833 print_pthread_event(tid, msg_buf);
2834 }
2835
2836 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002837 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002838
sewardj018f7622002-05-15 21:13:39 +00002839 /* Change SCSS */
2840 VG_(threads)[tid].sigs_waited_for = *set;
2841 VG_(threads)[tid].status = VgTs_WaitSIG;
2842
2843 VG_(block_all_host_signals)( &irrelevant_sigmask );
2844 VG_(handle_SCSS_change)( False /* lazy update */ );
2845}
2846
2847
2848static
2849void do_pthread_kill ( ThreadId tid, /* me */
2850 ThreadId thread, /* thread to signal */
2851 Int sig )
2852{
2853 Char msg_buf[100];
2854
2855 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
2856 VG_(sprintf)(msg_buf,
2857 "pthread_kill thread %d, signo %d",
2858 thread, sig );
2859 print_pthread_event(tid, msg_buf);
2860 }
2861
2862 vg_assert(VG_(is_valid_tid)(tid)
2863 && VG_(threads)[tid].status == VgTs_Runnable);
2864
sewardj4dced352002-06-04 22:54:20 +00002865 if (!VG_(is_valid_tid)(thread)) {
2866 VG_(record_pthread_err)( tid,
2867 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00002868 SET_EDX(tid, -VKI_ESRCH);
2869 return;
2870 }
2871
2872 if (sig < 1 || sig > VKI_KNSIG) {
2873 SET_EDX(tid, -VKI_EINVAL);
2874 return;
2875 }
2876
2877 VG_(send_signal_to_thread)( thread, sig );
2878 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00002879}
2880
2881
sewardj2cb00342002-06-28 01:46:26 +00002882/* -----------------------------------------------------------
2883 FORK HANDLERS.
2884 -------------------------------------------------------- */
2885
2886static
2887void do__set_fhstack_used ( ThreadId tid, Int n )
2888{
2889 Char msg_buf[100];
2890 if (VG_(clo_trace_sched)) {
2891 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
2892 print_pthread_event(tid, msg_buf);
2893 }
2894
2895 vg_assert(VG_(is_valid_tid)(tid)
2896 && VG_(threads)[tid].status == VgTs_Runnable);
2897
2898 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
2899 vg_fhstack_used = n;
2900 SET_EDX(tid, 0);
2901 } else {
2902 SET_EDX(tid, -1);
2903 }
2904}
2905
2906
2907static
2908void do__get_fhstack_used ( ThreadId tid )
2909{
2910 Int n;
2911 Char msg_buf[100];
2912 if (VG_(clo_trace_sched)) {
2913 VG_(sprintf)(msg_buf, "get_fhstack_used" );
2914 print_pthread_event(tid, msg_buf);
2915 }
2916
2917 vg_assert(VG_(is_valid_tid)(tid)
2918 && VG_(threads)[tid].status == VgTs_Runnable);
2919
2920 n = vg_fhstack_used;
2921 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
2922 SET_EDX(tid, n);
2923}
2924
2925static
2926void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
2927{
2928 Char msg_buf[100];
2929 if (VG_(clo_trace_sched)) {
2930 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
2931 print_pthread_event(tid, msg_buf);
2932 }
2933
2934 vg_assert(VG_(is_valid_tid)(tid)
2935 && VG_(threads)[tid].status == VgTs_Runnable);
2936
2937 if (VG_(clo_instrument)) {
2938 /* check fh is addressible/defined */
2939 if (!VGM_(check_readable)( (Addr)fh,
2940 sizeof(ForkHandlerEntry), NULL)) {
2941 VG_(record_pthread_err)( tid,
2942 "pthread_atfork: prepare/parent/child contains "
2943 "unaddressible or undefined bytes");
2944 }
2945 }
2946
2947 if (n < 0 && n >= VG_N_FORKHANDLERSTACK) {
2948 SET_EDX(tid, -1);
2949 return;
2950 }
2951
2952 vg_fhstack[n] = *fh;
2953 SET_EDX(tid, 0);
2954}
2955
2956
2957static
2958void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
2959 ForkHandlerEntry* fh )
2960{
2961 Char msg_buf[100];
2962 if (VG_(clo_trace_sched)) {
2963 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
2964 print_pthread_event(tid, msg_buf);
2965 }
2966
2967 vg_assert(VG_(is_valid_tid)(tid)
2968 && VG_(threads)[tid].status == VgTs_Runnable);
2969
2970 if (VG_(clo_instrument)) {
2971 /* check fh is addressible/defined */
2972 if (!VGM_(check_writable)( (Addr)fh,
2973 sizeof(ForkHandlerEntry), NULL)) {
2974 VG_(record_pthread_err)( tid,
2975 "fork: prepare/parent/child contains "
2976 "unaddressible bytes");
2977 }
2978 }
2979
2980 if (n < 0 && n >= VG_N_FORKHANDLERSTACK) {
2981 SET_EDX(tid, -1);
2982 return;
2983 }
2984
2985 *fh = vg_fhstack[n];
2986 SET_EDX(tid, 0);
2987
2988 if (VG_(clo_instrument)) {
2989 VGM_(make_readable)( (Addr)fh, sizeof(ForkHandlerEntry) );
2990 }
2991}
2992
2993
sewardje663cb92002-04-12 10:26:32 +00002994/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00002995 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00002996 ------------------------------------------------------------------ */
2997
sewardj124ca2a2002-06-20 10:19:38 +00002998/* Do a client request for the thread tid. After the request, tid may
2999 or may not still be runnable; if not, the scheduler will have to
3000 choose a new thread to run.
3001*/
sewardje663cb92002-04-12 10:26:32 +00003002static
sewardj124ca2a2002-06-20 10:19:38 +00003003void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003004{
sewardj124ca2a2002-06-20 10:19:38 +00003005# define RETURN_WITH(vvv) \
3006 { tst->m_edx = (vvv); \
3007 tst->sh_edx = VGM_WORD_VALID; \
3008 }
3009
3010 ThreadState* tst = &VG_(threads)[tid];
3011 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3012 UInt req_no = arg[0];
3013
3014 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003015 switch (req_no) {
3016
sewardj124ca2a2002-06-20 10:19:38 +00003017 case VG_USERREQ__MALLOC:
3018 RETURN_WITH(
3019 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3020 );
3021 break;
3022
3023 case VG_USERREQ__BUILTIN_NEW:
3024 RETURN_WITH(
3025 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3026 );
3027 break;
3028
3029 case VG_USERREQ__BUILTIN_VEC_NEW:
3030 RETURN_WITH(
3031 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3032 );
3033 break;
3034
3035 case VG_USERREQ__FREE:
3036 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3037 RETURN_WITH(0); /* irrelevant */
3038 break;
3039
3040 case VG_USERREQ__BUILTIN_DELETE:
3041 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3042 RETURN_WITH(0); /* irrelevant */
3043 break;
3044
3045 case VG_USERREQ__BUILTIN_VEC_DELETE:
3046 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3047 RETURN_WITH(0); /* irrelevant */
3048 break;
3049
3050 case VG_USERREQ__CALLOC:
3051 RETURN_WITH(
3052 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3053 );
3054 break;
3055
3056 case VG_USERREQ__REALLOC:
3057 RETURN_WITH(
3058 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3059 );
3060 break;
3061
3062 case VG_USERREQ__MEMALIGN:
3063 RETURN_WITH(
3064 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3065 );
3066 break;
3067
3068 case VG_USERREQ__PTHREAD_GET_THREADID:
3069 RETURN_WITH(tid);
3070 break;
3071
3072 case VG_USERREQ__RUNNING_ON_VALGRIND:
3073 RETURN_WITH(1);
3074 break;
3075
3076 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3077 RETURN_WITH(VG_(clo_trace_pthread_level));
3078 break;
3079
3080 case VG_USERREQ__READ_MILLISECOND_TIMER:
3081 RETURN_WITH(VG_(read_millisecond_timer)());
3082 break;
3083
3084 /* Some of these may make thread tid non-runnable, but the
3085 scheduler checks for that on return from this function. */
3086 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3087 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3088 break;
3089
3090 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3091 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3092 break;
3093
3094 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3095 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3096 break;
3097
3098 case VG_USERREQ__PTHREAD_GETSPECIFIC:
3099 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
3100 break;
3101
3102 case VG_USERREQ__SET_CANCELTYPE:
3103 do__set_canceltype ( tid, arg[1] );
3104 break;
3105
3106 case VG_USERREQ__CLEANUP_PUSH:
3107 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3108 break;
3109
3110 case VG_USERREQ__CLEANUP_POP:
3111 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3112 break;
3113
3114 case VG_USERREQ__TESTCANCEL:
3115 do__testcancel ( tid );
3116 break;
3117
3118 case VG_USERREQ__GET_N_SIGS_RETURNED:
3119 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3120 break;
3121
sewardje663cb92002-04-12 10:26:32 +00003122 case VG_USERREQ__PTHREAD_JOIN:
3123 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3124 break;
3125
sewardj3b5d8862002-04-20 13:53:23 +00003126 case VG_USERREQ__PTHREAD_COND_WAIT:
3127 do_pthread_cond_wait( tid,
3128 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003129 (pthread_mutex_t *)(arg[2]),
3130 0xFFFFFFFF /* no timeout */ );
3131 break;
3132
3133 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3134 do_pthread_cond_wait( tid,
3135 (pthread_cond_t *)(arg[1]),
3136 (pthread_mutex_t *)(arg[2]),
3137 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003138 break;
3139
3140 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3141 do_pthread_cond_signal_or_broadcast(
3142 tid,
3143 False, /* signal, not broadcast */
3144 (pthread_cond_t *)(arg[1]) );
3145 break;
3146
3147 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3148 do_pthread_cond_signal_or_broadcast(
3149 tid,
3150 True, /* broadcast, not signal */
3151 (pthread_cond_t *)(arg[1]) );
3152 break;
3153
sewardj5f07b662002-04-23 16:52:51 +00003154 case VG_USERREQ__PTHREAD_KEY_CREATE:
3155 do_pthread_key_create ( tid,
3156 (pthread_key_t*)(arg[1]),
3157 (void(*)(void*))(arg[2]) );
3158 break;
3159
3160 case VG_USERREQ__PTHREAD_KEY_DELETE:
3161 do_pthread_key_delete ( tid,
3162 (pthread_key_t)(arg[1]) );
3163 break;
3164
sewardj5f07b662002-04-23 16:52:51 +00003165 case VG_USERREQ__PTHREAD_SETSPECIFIC:
3166 do_pthread_setspecific ( tid,
3167 (pthread_key_t)(arg[1]),
3168 (void*)(arg[2]) );
3169 break;
3170
sewardjb48e5002002-05-13 00:16:03 +00003171 case VG_USERREQ__PTHREAD_SIGMASK:
3172 do_pthread_sigmask ( tid,
3173 arg[1],
3174 (vki_ksigset_t*)(arg[2]),
3175 (vki_ksigset_t*)(arg[3]) );
3176 break;
3177
3178 case VG_USERREQ__SIGWAIT:
3179 do_sigwait ( tid,
3180 (vki_ksigset_t*)(arg[1]),
3181 (Int*)(arg[2]) );
3182 break;
3183
sewardj018f7622002-05-15 21:13:39 +00003184 case VG_USERREQ__PTHREAD_KILL:
3185 do_pthread_kill ( tid, arg[1], arg[2] );
3186 break;
3187
sewardjff42d1d2002-05-22 13:17:31 +00003188 case VG_USERREQ__PTHREAD_YIELD:
3189 do_pthread_yield ( tid );
3190 /* because this is classified as a non-trivial client
3191 request, the scheduler should now select a new thread to
3192 run. */
3193 break;
sewardj018f7622002-05-15 21:13:39 +00003194
sewardj7989d0c2002-05-28 11:00:01 +00003195 case VG_USERREQ__SET_CANCELSTATE:
3196 do__set_cancelstate ( tid, arg[1] );
3197 break;
3198
sewardj7989d0c2002-05-28 11:00:01 +00003199 case VG_USERREQ__SET_OR_GET_DETACH:
3200 do__set_or_get_detach ( tid, arg[1], arg[2] );
3201 break;
3202
3203 case VG_USERREQ__SET_CANCELPEND:
3204 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3205 break;
3206
3207 case VG_USERREQ__WAIT_JOINER:
3208 do__wait_joiner ( tid, (void*)arg[1] );
3209 break;
3210
3211 case VG_USERREQ__QUIT:
3212 do__quit ( tid );
3213 break;
3214
3215 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3216 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3217 (void*)arg[2] );
3218 break;
3219
sewardj870497a2002-05-29 01:06:47 +00003220 case VG_USERREQ__GET_KEY_D_AND_S:
3221 do__get_key_destr_and_spec ( tid,
3222 (pthread_key_t)arg[1],
3223 (CleanupEntry*)arg[2] );
3224 break;
3225
sewardjef037c72002-05-30 00:40:03 +00003226 case VG_USERREQ__NUKE_OTHER_THREADS:
3227 VG_(nuke_all_threads_except) ( tid );
3228 SET_EDX(tid, 0);
3229 break;
3230
sewardj4dced352002-06-04 22:54:20 +00003231 case VG_USERREQ__PTHREAD_ERROR:
3232 VG_(record_pthread_err)( tid, (Char*)(arg[1]) );
3233 SET_EDX(tid, 0);
3234 break;
3235
sewardj2cb00342002-06-28 01:46:26 +00003236 case VG_USERREQ__SET_FHSTACK_USED:
3237 do__set_fhstack_used( tid, (Int)(arg[1]) );
3238 break;
3239
3240 case VG_USERREQ__GET_FHSTACK_USED:
3241 do__get_fhstack_used( tid );
3242 break;
3243
3244 case VG_USERREQ__SET_FHSTACK_ENTRY:
3245 do__set_fhstack_entry( tid, (Int)(arg[1]),
3246 (ForkHandlerEntry*)(arg[2]) );
3247 break;
3248
3249 case VG_USERREQ__GET_FHSTACK_ENTRY:
3250 do__get_fhstack_entry( tid, (Int)(arg[1]),
3251 (ForkHandlerEntry*)(arg[2]) );
3252 break;
3253
sewardje663cb92002-04-12 10:26:32 +00003254 case VG_USERREQ__MAKE_NOACCESS:
3255 case VG_USERREQ__MAKE_WRITABLE:
3256 case VG_USERREQ__MAKE_READABLE:
3257 case VG_USERREQ__DISCARD:
3258 case VG_USERREQ__CHECK_WRITABLE:
3259 case VG_USERREQ__CHECK_READABLE:
3260 case VG_USERREQ__MAKE_NOACCESS_STACK:
sewardje663cb92002-04-12 10:26:32 +00003261 case VG_USERREQ__DO_LEAK_CHECK:
sewardj18d75132002-05-16 11:06:21 +00003262 case VG_USERREQ__DISCARD_TRANSLATIONS:
sewardjc3bd5f52002-05-01 03:24:23 +00003263 SET_EDX(
3264 tid,
sewardj018f7622002-05-15 21:13:39 +00003265 VG_(handle_client_request) ( &VG_(threads)[tid], arg )
sewardjc3bd5f52002-05-01 03:24:23 +00003266 );
sewardje663cb92002-04-12 10:26:32 +00003267 break;
3268
sewardj77e466c2002-04-14 02:29:29 +00003269 case VG_USERREQ__SIGNAL_RETURNS:
3270 handle_signal_return(tid);
3271 break;
sewardj54cacf02002-04-12 23:24:59 +00003272
sewardje663cb92002-04-12 10:26:32 +00003273 default:
sewardj124ca2a2002-06-20 10:19:38 +00003274 VG_(printf)("panic'd on client request = 0x%x\n", arg[0] );
3275 VG_(panic)("do_client_request: "
sewardje663cb92002-04-12 10:26:32 +00003276 "unknown request");
3277 /*NOTREACHED*/
3278 break;
3279 }
sewardj124ca2a2002-06-20 10:19:38 +00003280
3281# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003282}
3283
3284
sewardj6072c362002-04-19 14:40:57 +00003285/* ---------------------------------------------------------------------
3286 Sanity checking.
3287 ------------------------------------------------------------------ */
3288
3289/* Internal consistency checks on the sched/pthread structures. */
3290static
3291void scheduler_sanity ( void )
3292{
sewardj3b5d8862002-04-20 13:53:23 +00003293 pthread_mutex_t* mx;
3294 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003295 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003296
sewardj6072c362002-04-19 14:40:57 +00003297 /* VG_(printf)("scheduler_sanity\n"); */
3298 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003299 mx = VG_(threads)[i].associated_mx;
3300 cv = VG_(threads)[i].associated_cv;
3301 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003302 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3303 it's actually held by someone, since otherwise this thread
3304 is deadlocked, (4) the mutex's owner is not us, since
3305 otherwise this thread is also deadlocked. The logic in
3306 do_pthread_mutex_lock rejects attempts by a thread to lock
3307 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003308
sewardjbf290b92002-05-01 02:28:01 +00003309 (2) has been seen to fail sometimes. I don't know why.
3310 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003311 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003312 /* 1 */ vg_assert(mx != NULL);
3313 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003314 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003315 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003316 } else
sewardj018f7622002-05-15 21:13:39 +00003317 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003318 vg_assert(cv != NULL);
3319 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003320 } else {
sewardj05553872002-04-20 20:53:17 +00003321 /* Unfortunately these don't hold true when a sighandler is
3322 running. To be fixed. */
3323 /* vg_assert(cv == NULL); */
3324 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003325 }
sewardjbf290b92002-05-01 02:28:01 +00003326
sewardj018f7622002-05-15 21:13:39 +00003327 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003328 Int
sewardj018f7622002-05-15 21:13:39 +00003329 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3330 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003331 if (i > 1 /* not the root thread */
3332 && stack_used
3333 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3334 VG_(message)(Vg_UserMsg,
3335 "Warning: STACK OVERFLOW: "
3336 "thread %d: stack used %d, available %d",
3337 i, stack_used, VG_PTHREAD_STACK_MIN );
3338 VG_(message)(Vg_UserMsg,
3339 "Terminating Valgrind. If thread(s) "
3340 "really need more stack, increase");
3341 VG_(message)(Vg_UserMsg,
3342 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3343 VG_(exit)(1);
3344 }
sewardjb48e5002002-05-13 00:16:03 +00003345
sewardj018f7622002-05-15 21:13:39 +00003346 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003347 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003348 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003349 } else {
3350 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003351 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003352 }
3353
sewardjbf290b92002-05-01 02:28:01 +00003354 }
sewardj6072c362002-04-19 14:40:57 +00003355 }
sewardj5f07b662002-04-23 16:52:51 +00003356
3357 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3358 if (!vg_thread_keys[i].inuse)
3359 vg_assert(vg_thread_keys[i].destructor == NULL);
3360 }
sewardj6072c362002-04-19 14:40:57 +00003361}
3362
3363
sewardje663cb92002-04-12 10:26:32 +00003364/*--------------------------------------------------------------------*/
3365/*--- end vg_scheduler.c ---*/
3366/*--------------------------------------------------------------------*/