blob: 74af761290a7d6e37006158d803d30f0caec817f [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
sewardj77f0fc12002-07-12 01:23:03 +00001371 if (VG_(threads)[tid].status == VgTs_Runnable) {
1372 /* Better do a signal check, since if in a tight loop
1373 with a slow syscall it may be a very long time
1374 before we get back to the main signal check in Stage 1. */
1375 sigs_delivered = VG_(deliver_signals)();
1376 if (sigs_delivered)
1377 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001378 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001379 } else {
1380 goto stage1;
1381 }
sewardj51c0aaf2002-04-25 01:32:10 +00001382 }
1383
sewardjd7fd4d22002-04-24 01:57:27 +00001384 /* It's an event we can't quickly deal with. Give up running
1385 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001386 break;
1387 }
1388
1389 /* ======================= Phase 3 of 3 =======================
1390 Handle non-trivial thread requests, mostly pthread stuff. */
1391
1392 /* Ok, we've fallen out of the dispatcher for a
1393 non-completely-trivial reason. First, update basic-block
1394 counters. */
1395
1396 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1397 vg_assert(done_this_time >= 0);
1398 VG_(bbs_to_go) -= (ULong)done_this_time;
1399 VG_(bbs_done) += (ULong)done_this_time;
1400
1401 if (0 && trc != VG_TRC_INNER_FASTMISS)
1402 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1403 tid, done_this_time, (Int)trc );
1404
1405 if (0 && trc != VG_TRC_INNER_FASTMISS)
1406 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1407 tid, VG_(bbs_done),
1408 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001409
sewardje663cb92002-04-12 10:26:32 +00001410 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001411 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001412
1413 switch (trc) {
1414
sewardje663cb92002-04-12 10:26:32 +00001415 case VG_TRC_INNER_COUNTERZERO:
1416 /* Timeslice is out. Let a new thread be scheduled,
1417 simply by doing nothing, causing us to arrive back at
1418 Phase 1. */
1419 if (VG_(bbs_to_go) == 0) {
1420 goto debug_stop;
1421 }
1422 vg_assert(VG_(dispatch_ctr) == 0);
1423 break;
1424
1425 case VG_TRC_UNRESUMABLE_SIGNAL:
1426 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1427 away. Again, do nothing, so we wind up back at Phase
1428 1, whereupon the signal will be "delivered". */
1429 break;
1430
sewardje663cb92002-04-12 10:26:32 +00001431 default:
1432 VG_(printf)("\ntrc = %d\n", trc);
1433 VG_(panic)("VG_(scheduler), phase 3: "
1434 "unexpected thread return code");
1435 /* NOTREACHED */
1436 break;
1437
1438 } /* switch (trc) */
1439
1440 /* That completes Phase 3 of 3. Return now to the top of the
1441 main scheduler loop, to Phase 1 of 3. */
1442
1443 } /* top-level scheduler loop */
1444
1445
1446 /* NOTREACHED */
1447 VG_(panic)("scheduler: post-main-loop ?!");
1448 /* NOTREACHED */
1449
1450 debug_stop:
1451 /* If we exited because of a debug stop, print the translation
1452 of the last block executed -- by translating it again, and
1453 throwing away the result. */
1454 VG_(printf)(
1455 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001456 VG_(translate)( &VG_(threads)[tid],
1457 VG_(threads)[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001458 VG_(printf)("\n");
1459 VG_(printf)(
1460 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1461
1462 return VgSrc_BbsDone;
1463}
1464
1465
1466/* ---------------------------------------------------------------------
1467 The pthread implementation.
1468 ------------------------------------------------------------------ */
1469
1470#include <pthread.h>
1471#include <errno.h>
1472
sewardjbf290b92002-05-01 02:28:01 +00001473#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001474 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001475
1476/* /usr/include/bits/pthreadtypes.h:
1477 typedef unsigned long int pthread_t;
1478*/
1479
sewardje663cb92002-04-12 10:26:32 +00001480
sewardj604ec3c2002-04-18 22:38:41 +00001481/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001482 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001483 -------------------------------------------------------- */
1484
sewardj20917d82002-05-28 01:36:45 +00001485/* We've decided to action a cancellation on tid. Make it jump to
1486 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1487 as the arg. */
1488static
1489void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1490{
1491 Char msg_buf[100];
1492 vg_assert(VG_(is_valid_tid)(tid));
1493 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1494 handler -- which is really thread_exit_wrapper() in
1495 vg_libpthread.c. */
1496 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1497 VG_(threads)[tid].m_esp -= 4;
1498 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1499 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1500 VG_(threads)[tid].status = VgTs_Runnable;
1501 /* Make sure we aren't cancelled again whilst handling this
1502 cancellation. */
1503 VG_(threads)[tid].cancel_st = False;
1504 if (VG_(clo_trace_sched)) {
1505 VG_(sprintf)(msg_buf,
1506 "jump to cancellation handler (hdlr = %p)",
1507 VG_(threads)[tid].cancel_pend);
1508 print_sched_event(tid, msg_buf);
1509 }
1510}
1511
1512
1513
sewardjb48e5002002-05-13 00:16:03 +00001514/* Release resources and generally clean up once a thread has finally
1515 disappeared. */
1516static
1517void cleanup_after_thread_exited ( ThreadId tid )
1518{
sewardj89f20fd2002-06-30 10:57:30 +00001519 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001520 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001521 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1522 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
sewardjb48e5002002-05-13 00:16:03 +00001523 /* Mark its stack no-access */
1524 if (VG_(clo_instrument) && tid != 1)
sewardj018f7622002-05-15 21:13:39 +00001525 VGM_(make_noaccess)( VG_(threads)[tid].stack_base,
1526 VG_(threads)[tid].stack_size );
sewardjb48e5002002-05-13 00:16:03 +00001527 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001528 thread, and get rid of signal handlers specifically arranged for
1529 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001530 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001531 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001532
1533 /* Clean up the waiting_fd table */
1534 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1535 if (vg_waiting_fds[i].tid == tid) {
1536 vg_waiting_fds[i].fd = -1; /* not in use */
1537 }
1538 }
sewardjb48e5002002-05-13 00:16:03 +00001539}
1540
1541
sewardj20917d82002-05-28 01:36:45 +00001542/* Look for matching pairs of threads waiting for joiners and threads
1543 waiting for joinees. For each such pair copy the return value of
1544 the joinee into the joiner, let the joiner resume and discard the
1545 joinee. */
1546static
1547void maybe_rendezvous_joiners_and_joinees ( void )
1548{
1549 Char msg_buf[100];
1550 void** thread_return;
1551 ThreadId jnr, jee;
1552
1553 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1554 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1555 continue;
1556 jee = VG_(threads)[jnr].joiner_jee_tid;
1557 if (jee == VG_INVALID_THREADID)
1558 continue;
1559 vg_assert(VG_(is_valid_tid)(jee));
1560 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1561 continue;
1562 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1563 joined by ... well, any thread. So let's do it! */
1564
1565 /* Copy return value to where joiner wants it. */
1566 thread_return = VG_(threads)[jnr].joiner_thread_return;
1567 if (thread_return != NULL) {
1568 /* CHECK thread_return writable */
sewardj5a3798b2002-06-04 23:24:22 +00001569 if (VG_(clo_instrument)
1570 && !VGM_(check_writable)( (Addr)thread_return,
1571 sizeof(void*), NULL))
1572 VG_(record_pthread_err)( jnr,
1573 "pthread_join: thread_return points to invalid location");
1574
sewardj20917d82002-05-28 01:36:45 +00001575 *thread_return = VG_(threads)[jee].joinee_retval;
1576 /* Not really right, since it makes the thread's return value
1577 appear to be defined even if it isn't. */
1578 if (VG_(clo_instrument))
1579 VGM_(make_readable)( (Addr)thread_return, sizeof(void*) );
1580 }
1581
1582 /* Joinee is discarded */
1583 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1584 cleanup_after_thread_exited ( jee );
1585 if (VG_(clo_trace_sched)) {
1586 VG_(sprintf)(msg_buf,
1587 "rendezvous with joinee %d. %d resumes, %d exits.",
1588 jee, jnr, jee );
1589 print_sched_event(jnr, msg_buf);
1590 }
1591
1592 /* joiner returns with success */
1593 VG_(threads)[jnr].status = VgTs_Runnable;
1594 SET_EDX(jnr, 0);
1595 }
1596}
1597
1598
sewardjccef2e62002-05-29 19:26:32 +00001599/* Nuke all threads other than tid. POSIX specifies that this should
1600 happen in __NR_exec, and after a __NR_fork() when I am the child,
1601 as POSIX requires. */
1602void VG_(nuke_all_threads_except) ( ThreadId me )
1603{
1604 ThreadId tid;
1605 for (tid = 1; tid < VG_N_THREADS; tid++) {
1606 if (tid == me
1607 || VG_(threads)[tid].status == VgTs_Empty)
1608 continue;
sewardjef037c72002-05-30 00:40:03 +00001609 if (0)
1610 VG_(printf)(
1611 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001612 VG_(threads)[tid].status = VgTs_Empty;
1613 cleanup_after_thread_exited( tid );
1614 }
1615}
1616
1617
sewardj20917d82002-05-28 01:36:45 +00001618/* -----------------------------------------------------------
1619 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1620 -------------------------------------------------------- */
1621
sewardje663cb92002-04-12 10:26:32 +00001622static
sewardj8ad94e12002-05-29 00:10:20 +00001623void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1624{
1625 Int sp;
1626 Char msg_buf[100];
1627 vg_assert(VG_(is_valid_tid)(tid));
1628 sp = VG_(threads)[tid].custack_used;
1629 if (VG_(clo_trace_sched)) {
1630 VG_(sprintf)(msg_buf,
1631 "cleanup_push (fn %p, arg %p) -> slot %d",
1632 cu->fn, cu->arg, sp);
1633 print_sched_event(tid, msg_buf);
1634 }
1635 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1636 if (sp == VG_N_CLEANUPSTACK)
1637 VG_(panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
1638 " Increase and recompile.");
1639 VG_(threads)[tid].custack[sp] = *cu;
1640 sp++;
1641 VG_(threads)[tid].custack_used = sp;
1642 SET_EDX(tid, 0);
1643}
1644
1645
1646static
1647void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1648{
1649 Int sp;
1650 Char msg_buf[100];
1651 vg_assert(VG_(is_valid_tid)(tid));
1652 sp = VG_(threads)[tid].custack_used;
1653 if (VG_(clo_trace_sched)) {
1654 VG_(sprintf)(msg_buf,
sewardj4dced352002-06-04 22:54:20 +00001655 "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001656 print_sched_event(tid, msg_buf);
1657 }
1658 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1659 if (sp == 0) {
1660 SET_EDX(tid, -1);
1661 return;
1662 }
1663 sp--;
1664 *cu = VG_(threads)[tid].custack[sp];
sewardj67a3bec2002-05-29 16:48:44 +00001665 if (VG_(clo_instrument))
1666 VGM_(make_readable)( (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001667 VG_(threads)[tid].custack_used = sp;
1668 SET_EDX(tid, 0);
1669}
1670
1671
1672static
sewardjff42d1d2002-05-22 13:17:31 +00001673void do_pthread_yield ( ThreadId tid )
1674{
1675 Char msg_buf[100];
1676 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001677 if (VG_(clo_trace_sched)) {
1678 VG_(sprintf)(msg_buf, "yield");
1679 print_sched_event(tid, msg_buf);
1680 }
1681 SET_EDX(tid, 0);
1682}
1683
1684
1685static
sewardj20917d82002-05-28 01:36:45 +00001686void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001687{
sewardj7989d0c2002-05-28 11:00:01 +00001688 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001689 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001690 if (VG_(clo_trace_sched)) {
1691 VG_(sprintf)(msg_buf, "testcancel");
1692 print_sched_event(tid, msg_buf);
1693 }
sewardj20917d82002-05-28 01:36:45 +00001694 if (/* is there a cancellation pending on this thread? */
1695 VG_(threads)[tid].cancel_pend != NULL
1696 && /* is this thread accepting cancellations? */
1697 VG_(threads)[tid].cancel_st) {
1698 /* Ok, let's do the cancellation. */
1699 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001700 } else {
sewardj20917d82002-05-28 01:36:45 +00001701 /* No, we keep going. */
1702 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001703 }
sewardje663cb92002-04-12 10:26:32 +00001704}
1705
1706
1707static
sewardj20917d82002-05-28 01:36:45 +00001708void do__set_cancelstate ( ThreadId tid, Int state )
1709{
1710 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001711 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001712 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001713 if (VG_(clo_trace_sched)) {
1714 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1715 state==PTHREAD_CANCEL_ENABLE
1716 ? "ENABLE"
1717 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1718 print_sched_event(tid, msg_buf);
1719 }
sewardj20917d82002-05-28 01:36:45 +00001720 old_st = VG_(threads)[tid].cancel_st;
1721 if (state == PTHREAD_CANCEL_ENABLE) {
1722 VG_(threads)[tid].cancel_st = True;
1723 } else
1724 if (state == PTHREAD_CANCEL_DISABLE) {
1725 VG_(threads)[tid].cancel_st = False;
1726 } else {
1727 VG_(panic)("do__set_cancelstate");
1728 }
1729 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1730 : PTHREAD_CANCEL_DISABLE);
1731}
1732
1733
1734static
1735void do__set_canceltype ( ThreadId tid, Int type )
1736{
1737 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001738 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001739 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001740 if (VG_(clo_trace_sched)) {
1741 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1742 type==PTHREAD_CANCEL_ASYNCHRONOUS
1743 ? "ASYNCHRONOUS"
1744 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1745 print_sched_event(tid, msg_buf);
1746 }
sewardj20917d82002-05-28 01:36:45 +00001747 old_ty = VG_(threads)[tid].cancel_ty;
1748 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1749 VG_(threads)[tid].cancel_ty = False;
1750 } else
1751 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001752 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001753 } else {
1754 VG_(panic)("do__set_canceltype");
1755 }
1756 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1757 : PTHREAD_CANCEL_ASYNCHRONOUS);
1758}
1759
1760
sewardj7989d0c2002-05-28 11:00:01 +00001761/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001762static
sewardj7989d0c2002-05-28 11:00:01 +00001763void do__set_or_get_detach ( ThreadId tid,
1764 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001765{
sewardj7989d0c2002-05-28 11:00:01 +00001766 ThreadId i;
1767 Char msg_buf[100];
1768 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1769 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001770 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001771 if (VG_(clo_trace_sched)) {
1772 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1773 what==0 ? "not-detached" : (
1774 what==1 ? "detached" : (
1775 what==2 ? "fetch old value" : "???")),
1776 det );
1777 print_sched_event(tid, msg_buf);
1778 }
1779
1780 if (!VG_(is_valid_tid)(det)) {
1781 SET_EDX(tid, -1);
1782 return;
1783 }
1784
sewardj20917d82002-05-28 01:36:45 +00001785 switch (what) {
1786 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001787 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001788 return;
sewardj7989d0c2002-05-28 11:00:01 +00001789 case 1: /* set detached. If someone is in a join-wait for det,
1790 do not detach. */
1791 for (i = 1; i < VG_N_THREADS; i++) {
1792 if (VG_(threads)[i].status == VgTs_WaitJoinee
1793 && VG_(threads)[i].joiner_jee_tid == det) {
1794 SET_EDX(tid, 0);
1795 if (VG_(clo_trace_sched)) {
1796 VG_(sprintf)(msg_buf,
1797 "tid %d not detached because %d in join-wait for it %d",
1798 det, i);
1799 print_sched_event(tid, msg_buf);
1800 }
1801 return;
1802 }
1803 }
1804 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001805 SET_EDX(tid, 0);
1806 return;
1807 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001808 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001809 SET_EDX(tid, 0);
1810 return;
1811 default:
1812 VG_(panic)("do__set_or_get_detach");
1813 }
1814}
1815
1816
1817static
1818void do__set_cancelpend ( ThreadId tid,
1819 ThreadId cee,
1820 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001821{
1822 Char msg_buf[100];
1823
sewardj20917d82002-05-28 01:36:45 +00001824 vg_assert(VG_(is_valid_tid)(tid));
1825 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1826
sewardj7989d0c2002-05-28 11:00:01 +00001827 if (!VG_(is_valid_tid)(cee)) {
1828 if (VG_(clo_trace_sched)) {
1829 VG_(sprintf)(msg_buf,
1830 "set_cancelpend for invalid tid %d", cee);
1831 print_sched_event(tid, msg_buf);
1832 }
sewardj4dced352002-06-04 22:54:20 +00001833 VG_(record_pthread_err)( tid,
1834 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00001835 SET_EDX(tid, -VKI_ESRCH);
1836 return;
1837 }
sewardj20917d82002-05-28 01:36:45 +00001838
1839 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
1840
1841 if (VG_(clo_trace_sched)) {
1842 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001843 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00001844 cancelpend_hdlr, tid);
1845 print_sched_event(cee, msg_buf);
1846 }
1847
1848 /* Thread doing the cancelling returns with success. */
1849 SET_EDX(tid, 0);
1850
1851 /* Perhaps we can nuke the cancellee right now? */
1852 do__testcancel(cee);
1853}
1854
1855
1856static
1857void do_pthread_join ( ThreadId tid,
1858 ThreadId jee, void** thread_return )
1859{
1860 Char msg_buf[100];
1861 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00001862 /* jee, the joinee, is the thread specified as an arg in thread
1863 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00001864 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001865 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001866
1867 if (jee == tid) {
sewardj4dced352002-06-04 22:54:20 +00001868 VG_(record_pthread_err)( tid,
1869 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00001870 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00001871 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001872 return;
1873 }
1874
sewardj20917d82002-05-28 01:36:45 +00001875 /* Flush any completed pairs, so as to make sure what we're looking
1876 at is up-to-date. */
1877 maybe_rendezvous_joiners_and_joinees();
1878
1879 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00001880 if (jee < 0
1881 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00001882 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00001883 /* Invalid thread to join to. */
sewardj4dced352002-06-04 22:54:20 +00001884 VG_(record_pthread_err)( tid,
1885 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00001886 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00001887 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001888 return;
1889 }
1890
sewardj20917d82002-05-28 01:36:45 +00001891 /* Is anyone else already in a join-wait for jee? */
1892 for (i = 1; i < VG_N_THREADS; i++) {
1893 if (i == tid) continue;
1894 if (VG_(threads)[i].status == VgTs_WaitJoinee
1895 && VG_(threads)[i].joiner_jee_tid == jee) {
1896 /* Someone already did join on this thread */
sewardj4dced352002-06-04 22:54:20 +00001897 VG_(record_pthread_err)( tid,
1898 "pthread_join: another thread already "
1899 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00001900 SET_EDX(tid, EINVAL);
1901 VG_(threads)[tid].status = VgTs_Runnable;
1902 return;
1903 }
sewardje663cb92002-04-12 10:26:32 +00001904 }
1905
sewardj20917d82002-05-28 01:36:45 +00001906 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00001907 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00001908 VG_(threads)[tid].joiner_thread_return = thread_return;
1909 VG_(threads)[tid].joiner_jee_tid = jee;
1910
1911 /* Look for matching joiners and joinees and do the right thing. */
1912 maybe_rendezvous_joiners_and_joinees();
1913
1914 /* Return value is irrelevant since this this thread becomes
1915 non-runnable. maybe_resume_joiner() will cause it to return the
1916 right value when it resumes. */
1917
sewardj8937c812002-04-12 20:12:20 +00001918 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00001919 VG_(sprintf)(msg_buf,
1920 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00001921 print_sched_event(tid, msg_buf);
1922 }
sewardje663cb92002-04-12 10:26:32 +00001923}
1924
1925
sewardj20917d82002-05-28 01:36:45 +00001926/* ( void* ): calling thread waits for joiner and returns the void* to
1927 it. This is one of two ways in which a thread can finally exit --
1928 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00001929static
sewardj20917d82002-05-28 01:36:45 +00001930void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00001931{
sewardj20917d82002-05-28 01:36:45 +00001932 Char msg_buf[100];
1933 vg_assert(VG_(is_valid_tid)(tid));
1934 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1935 if (VG_(clo_trace_sched)) {
1936 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001937 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00001938 print_sched_event(tid, msg_buf);
1939 }
1940 VG_(threads)[tid].status = VgTs_WaitJoiner;
1941 VG_(threads)[tid].joinee_retval = retval;
1942 maybe_rendezvous_joiners_and_joinees();
1943}
1944
1945
1946/* ( no-args ): calling thread disappears from the system forever.
1947 Reclaim resources. */
1948static
1949void do__quit ( ThreadId tid )
1950{
1951 Char msg_buf[100];
1952 vg_assert(VG_(is_valid_tid)(tid));
1953 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1954 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
1955 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00001956 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00001957 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00001958 print_sched_event(tid, msg_buf);
1959 }
1960 /* Return value is irrelevant; this thread will not get
1961 rescheduled. */
1962}
1963
1964
1965/* Should never be entered. If it is, will be on the simulated
1966 CPU. */
1967static
1968void do__apply_in_new_thread_bogusRA ( void )
1969{
1970 VG_(panic)("do__apply_in_new_thread_bogusRA");
1971}
1972
1973/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
1974 MUST NOT return -- ever. Eventually it will do either __QUIT or
1975 __WAIT_JOINER. Return the child tid to the parent. */
1976static
1977void do__apply_in_new_thread ( ThreadId parent_tid,
1978 void* (*fn)(void *),
1979 void* arg )
1980{
sewardje663cb92002-04-12 10:26:32 +00001981 Addr new_stack;
1982 UInt new_stk_szb;
1983 ThreadId tid;
1984 Char msg_buf[100];
1985
1986 /* Paranoia ... */
1987 vg_assert(sizeof(pthread_t) == sizeof(UInt));
1988
sewardj018f7622002-05-15 21:13:39 +00001989 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00001990
sewardj1e8cdc92002-04-18 11:37:52 +00001991 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00001992
1993 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00001994 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00001995 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001996
1997 /* Copy the parent's CPU state into the child's, in a roundabout
1998 way (via baseBlock). */
1999 VG_(load_thread_state)(parent_tid);
2000 VG_(save_thread_state)(tid);
2001
2002 /* Consider allocating the child a stack, if the one it already has
2003 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002004 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002005
sewardj018f7622002-05-15 21:13:39 +00002006 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002007 /* Again, for good measure :) We definitely don't want to be
2008 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002009 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002010 /* for now, we don't handle the case of anything other than
2011 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002012 vg_assert(VG_(threads)[tid].stack_size == 0);
2013 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002014 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2015 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002016 VG_(threads)[tid].stack_base = new_stack;
2017 VG_(threads)[tid].stack_size = new_stk_szb;
2018 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002019 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002020 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002021 }
sewardj1e8cdc92002-04-18 11:37:52 +00002022
sewardj018f7622002-05-15 21:13:39 +00002023 VG_(threads)[tid].m_esp
2024 = VG_(threads)[tid].stack_base
2025 + VG_(threads)[tid].stack_size
sewardj1e8cdc92002-04-18 11:37:52 +00002026 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
2027
sewardje663cb92002-04-12 10:26:32 +00002028 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00002029 VGM_(make_noaccess)( VG_(threads)[tid].m_esp,
sewardje663cb92002-04-12 10:26:32 +00002030 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
2031
2032 /* push arg */
sewardj018f7622002-05-15 21:13:39 +00002033 VG_(threads)[tid].m_esp -= 4;
2034 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)arg;
sewardje663cb92002-04-12 10:26:32 +00002035
sewardj20917d82002-05-28 01:36:45 +00002036 /* push (bogus) return address */
sewardj018f7622002-05-15 21:13:39 +00002037 VG_(threads)[tid].m_esp -= 4;
sewardj20917d82002-05-28 01:36:45 +00002038 * (UInt*)(VG_(threads)[tid].m_esp)
2039 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002040
2041 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00002042 VGM_(make_readable)( VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002043
2044 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002045 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002046
sewardj8937c812002-04-12 20:12:20 +00002047 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00002048 VG_(sprintf)(msg_buf,
2049 "new thread, created by %d", parent_tid );
2050 print_sched_event(tid, msg_buf);
2051 }
2052
sewardj20917d82002-05-28 01:36:45 +00002053 /* Create new thread with default attrs:
2054 deferred cancellation, not detached
2055 */
2056 mostly_clear_thread_record(tid);
2057 VG_(threads)[tid].status = VgTs_Runnable;
sewardj5f07b662002-04-23 16:52:51 +00002058
sewardj018f7622002-05-15 21:13:39 +00002059 /* We inherit our parent's signal mask. */
2060 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002061 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002062
sewardj20917d82002-05-28 01:36:45 +00002063 /* return child's tid to parent */
2064 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002065}
2066
2067
sewardj604ec3c2002-04-18 22:38:41 +00002068/* -----------------------------------------------------------
2069 MUTEXes
2070 -------------------------------------------------------- */
2071
sewardj604ec3c2002-04-18 22:38:41 +00002072/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002073 typedef struct
2074 {
2075 int __m_reserved; -- Reserved for future use
2076 int __m_count; -- Depth of recursive locking
2077 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2078 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2079 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2080 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002081
sewardj6072c362002-04-19 14:40:57 +00002082 #define PTHREAD_MUTEX_INITIALIZER \
2083 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2084 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2085 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2086 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2087 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2088 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2089 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002090
sewardj6072c362002-04-19 14:40:57 +00002091 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002092
sewardj6072c362002-04-19 14:40:57 +00002093 __m_kind never changes and indicates whether or not it is recursive.
2094
2095 __m_count indicates the lock count; if 0, the mutex is not owned by
2096 anybody.
2097
2098 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2099 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2100 statically initialised mutexes correctly appear
2101 to belong to nobody.
2102
2103 In summary, a not-in-use mutex is distinguised by having __m_owner
2104 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2105 conditions holds, the other should too.
2106
2107 There is no linked list of threads waiting for this mutex. Instead
2108 a thread in WaitMX state points at the mutex with its waited_on_mx
2109 field. This makes _unlock() inefficient, but simple to implement the
2110 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002111
sewardj604ec3c2002-04-18 22:38:41 +00002112 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002113 deals with that for us.
2114*/
sewardje663cb92002-04-12 10:26:32 +00002115
sewardj3b5d8862002-04-20 13:53:23 +00002116/* Helper fns ... */
2117static
2118void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2119 Char* caller )
2120{
2121 Int i;
2122 Char msg_buf[100];
2123
2124 /* Find some arbitrary thread waiting on this mutex, and make it
2125 runnable. If none are waiting, mark the mutex as not held. */
2126 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002127 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002128 continue;
sewardj018f7622002-05-15 21:13:39 +00002129 if (VG_(threads)[i].status == VgTs_WaitMX
2130 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002131 break;
2132 }
2133
2134 vg_assert(i <= VG_N_THREADS);
2135 if (i == VG_N_THREADS) {
2136 /* Nobody else is waiting on it. */
2137 mutex->__m_count = 0;
2138 mutex->__m_owner = VG_INVALID_THREADID;
2139 } else {
2140 /* Notionally transfer the hold to thread i, whose
2141 pthread_mutex_lock() call now returns with 0 (success). */
2142 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002143 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002144 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002145 VG_(threads)[i].status = VgTs_Runnable;
2146 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002147 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002148
2149 if (VG_(clo_trace_pthread_level) >= 1) {
2150 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2151 caller, mutex );
2152 print_pthread_event(i, msg_buf);
2153 }
2154 }
2155}
2156
sewardje663cb92002-04-12 10:26:32 +00002157
2158static
sewardj30671ff2002-04-21 00:13:57 +00002159void do_pthread_mutex_lock( ThreadId tid,
2160 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002161 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002162{
sewardj30671ff2002-04-21 00:13:57 +00002163 Char msg_buf[100];
2164 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002165 = is_trylock ? "pthread_mutex_trylock"
2166 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002167
sewardj604ec3c2002-04-18 22:38:41 +00002168 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002169 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002170 print_pthread_event(tid, msg_buf);
2171 }
2172
2173 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002174 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002175 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002176
2177 /* POSIX doesn't mandate this, but for sanity ... */
2178 if (mutex == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002179 VG_(record_pthread_err)( tid,
2180 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002181 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002182 return;
2183 }
2184
sewardj604ec3c2002-04-18 22:38:41 +00002185 /* More paranoia ... */
2186 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002187# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002188 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002189 case PTHREAD_MUTEX_ADAPTIVE_NP:
2190# endif
sewardja1679dd2002-05-10 22:31:40 +00002191# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002192 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002193# endif
sewardj604ec3c2002-04-18 22:38:41 +00002194 case PTHREAD_MUTEX_RECURSIVE_NP:
2195 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002196 if (mutex->__m_count >= 0) break;
2197 /* else fall thru */
2198 default:
sewardj4dced352002-06-04 22:54:20 +00002199 VG_(record_pthread_err)( tid,
2200 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002201 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002202 return;
sewardje663cb92002-04-12 10:26:32 +00002203 }
2204
sewardj604ec3c2002-04-18 22:38:41 +00002205 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002206
sewardjb48e5002002-05-13 00:16:03 +00002207 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002208
2209 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002210 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002211 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002212 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002213 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002214 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002215 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002216 if (0)
2217 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2218 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002219 return;
2220 } else {
sewardj30671ff2002-04-21 00:13:57 +00002221 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002222 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002223 else
sewardjc3bd5f52002-05-01 03:24:23 +00002224 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002225 return;
2226 }
2227 } else {
sewardj6072c362002-04-19 14:40:57 +00002228 /* Someone else has it; we have to wait. Mark ourselves
2229 thusly. */
sewardj05553872002-04-20 20:53:17 +00002230 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002231 if (is_trylock) {
2232 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002233 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002234 } else {
sewardj018f7622002-05-15 21:13:39 +00002235 VG_(threads)[tid].status = VgTs_WaitMX;
2236 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002237 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002238 if (VG_(clo_trace_pthread_level) >= 1) {
2239 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2240 caller, mutex );
2241 print_pthread_event(tid, msg_buf);
2242 }
2243 }
sewardje663cb92002-04-12 10:26:32 +00002244 return;
2245 }
sewardjf8f819e2002-04-17 23:21:37 +00002246
sewardje663cb92002-04-12 10:26:32 +00002247 } else {
sewardj6072c362002-04-19 14:40:57 +00002248 /* Nobody owns it. Sanity check ... */
2249 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002250 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002251 mutex->__m_count = 1;
2252 mutex->__m_owner = (_pthread_descr)tid;
sewardje663cb92002-04-12 10:26:32 +00002253 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002254 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002255 }
sewardjf8f819e2002-04-17 23:21:37 +00002256
sewardje663cb92002-04-12 10:26:32 +00002257}
2258
2259
2260static
2261void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002262 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002263{
sewardj3b5d8862002-04-20 13:53:23 +00002264 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002265
sewardj45b4b372002-04-16 22:50:32 +00002266 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002267 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002268 print_pthread_event(tid, msg_buf);
2269 }
2270
sewardj604ec3c2002-04-18 22:38:41 +00002271 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002272 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002273 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002274
2275 if (mutex == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002276 VG_(record_pthread_err)( tid,
2277 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002278 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002279 return;
2280 }
2281
2282 /* More paranoia ... */
2283 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002284# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002285 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002286 case PTHREAD_MUTEX_ADAPTIVE_NP:
2287# endif
sewardja1679dd2002-05-10 22:31:40 +00002288# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002289 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002290# endif
sewardj604ec3c2002-04-18 22:38:41 +00002291 case PTHREAD_MUTEX_RECURSIVE_NP:
2292 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002293 if (mutex->__m_count >= 0) break;
2294 /* else fall thru */
2295 default:
sewardj4dced352002-06-04 22:54:20 +00002296 VG_(record_pthread_err)( tid,
2297 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002298 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002299 return;
2300 }
sewardje663cb92002-04-12 10:26:32 +00002301
2302 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002303 if (mutex->__m_count == 0) {
2304 /* nobody holds it */
2305 VG_(record_pthread_err)( tid,
2306 "pthread_mutex_unlock: mutex is not locked");
2307 SET_EDX(tid, EPERM);
2308 return;
2309 }
2310
2311 if ((ThreadId)mutex->__m_owner != tid) {
2312 /* we don't hold it */
2313 VG_(record_pthread_err)( tid,
2314 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002315 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002316 return;
2317 }
2318
sewardjf8f819e2002-04-17 23:21:37 +00002319 /* If it's a multiply-locked recursive mutex, just decrement the
2320 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002321 if (mutex->__m_count > 1) {
2322 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2323 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002324 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002325 return;
2326 }
2327
sewardj604ec3c2002-04-18 22:38:41 +00002328 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002329 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002330 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002331 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002332
sewardj3b5d8862002-04-20 13:53:23 +00002333 /* Release at max one thread waiting on this mutex. */
2334 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002335
sewardj3b5d8862002-04-20 13:53:23 +00002336 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002337 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002338}
2339
2340
sewardj6072c362002-04-19 14:40:57 +00002341/* -----------------------------------------------------------
2342 CONDITION VARIABLES
2343 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002344
sewardj6072c362002-04-19 14:40:57 +00002345/* The relevant native types are as follows:
2346 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002347
sewardj6072c362002-04-19 14:40:57 +00002348 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2349 typedef struct
2350 {
2351 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2352 _pthread_descr __c_waiting; -- Threads waiting on this condition
2353 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002354
sewardj6072c362002-04-19 14:40:57 +00002355 -- Attribute for conditionally variables.
2356 typedef struct
2357 {
2358 int __dummy;
2359 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002360
sewardj6072c362002-04-19 14:40:57 +00002361 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002362
sewardj3b5d8862002-04-20 13:53:23 +00002363 We don't use any fields of pthread_cond_t for anything at all.
2364 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002365
2366 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002367 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002368
sewardj77e466c2002-04-14 02:29:29 +00002369
sewardj5f07b662002-04-23 16:52:51 +00002370static
2371void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2372{
2373 Char msg_buf[100];
2374 pthread_mutex_t* mx;
2375 pthread_cond_t* cv;
2376
sewardjb48e5002002-05-13 00:16:03 +00002377 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002378 && VG_(threads)[tid].status == VgTs_WaitCV
2379 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2380 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002381 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002382 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002383 vg_assert(cv != NULL);
2384
2385 if (mx->__m_owner == VG_INVALID_THREADID) {
2386 /* Currently unheld; hand it out to thread tid. */
2387 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002388 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002389 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002390 VG_(threads)[tid].associated_cv = NULL;
2391 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002392 mx->__m_owner = (_pthread_descr)tid;
2393 mx->__m_count = 1;
2394
2395 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002396 VG_(sprintf)(msg_buf,
2397 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2398 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002399 print_pthread_event(tid, msg_buf);
2400 }
2401 } else {
2402 /* Currently held. Make thread tid be blocked on it. */
2403 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002404 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002405 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002406 VG_(threads)[tid].associated_cv = NULL;
2407 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002408 if (VG_(clo_trace_pthread_level) >= 1) {
2409 VG_(sprintf)(msg_buf,
2410 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2411 cv, mx );
2412 print_pthread_event(tid, msg_buf);
2413 }
2414
2415 }
2416}
2417
2418
sewardj3b5d8862002-04-20 13:53:23 +00002419static
2420void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2421 Int n_to_release,
2422 Char* caller )
2423{
2424 Int i;
2425 Char msg_buf[100];
2426 pthread_mutex_t* mx;
2427
2428 while (True) {
2429 if (n_to_release == 0)
2430 return;
2431
2432 /* Find a thread waiting on this CV. */
2433 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002434 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002435 continue;
sewardj018f7622002-05-15 21:13:39 +00002436 if (VG_(threads)[i].status == VgTs_WaitCV
2437 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002438 break;
2439 }
2440 vg_assert(i <= VG_N_THREADS);
2441
2442 if (i == VG_N_THREADS) {
2443 /* Nobody else is waiting on it. */
2444 return;
2445 }
2446
sewardj018f7622002-05-15 21:13:39 +00002447 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002448 vg_assert(mx != NULL);
2449
2450 if (mx->__m_owner == VG_INVALID_THREADID) {
2451 /* Currently unheld; hand it out to thread i. */
2452 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002453 VG_(threads)[i].status = VgTs_Runnable;
2454 VG_(threads)[i].associated_cv = NULL;
2455 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002456 mx->__m_owner = (_pthread_descr)i;
2457 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002458 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002459
2460 if (VG_(clo_trace_pthread_level) >= 1) {
2461 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2462 caller, cond, mx );
2463 print_pthread_event(i, msg_buf);
2464 }
2465
2466 } else {
2467 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002468 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002469 VG_(threads)[i].status = VgTs_WaitMX;
2470 VG_(threads)[i].associated_cv = NULL;
2471 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002472 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002473
2474 if (VG_(clo_trace_pthread_level) >= 1) {
2475 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2476 caller, cond, mx );
2477 print_pthread_event(i, msg_buf);
2478 }
2479
2480 }
2481
2482 n_to_release--;
2483 }
2484}
2485
2486
2487static
2488void do_pthread_cond_wait ( ThreadId tid,
2489 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002490 pthread_mutex_t *mutex,
2491 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002492{
2493 Char msg_buf[100];
2494
sewardj5f07b662002-04-23 16:52:51 +00002495 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2496 ms_end is the ending millisecond. */
2497
sewardj3b5d8862002-04-20 13:53:23 +00002498 /* pre: mutex should be a valid mutex and owned by tid. */
2499 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002500 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2501 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002502 print_pthread_event(tid, msg_buf);
2503 }
2504
2505 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002506 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002507 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002508
2509 if (mutex == NULL || cond == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002510 VG_(record_pthread_err)( tid,
2511 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002512 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002513 return;
2514 }
2515
2516 /* More paranoia ... */
2517 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002518# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002519 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002520 case PTHREAD_MUTEX_ADAPTIVE_NP:
2521# endif
sewardja1679dd2002-05-10 22:31:40 +00002522# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002523 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002524# endif
sewardj3b5d8862002-04-20 13:53:23 +00002525 case PTHREAD_MUTEX_RECURSIVE_NP:
2526 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002527 if (mutex->__m_count >= 0) break;
2528 /* else fall thru */
2529 default:
sewardj4dced352002-06-04 22:54:20 +00002530 VG_(record_pthread_err)( tid,
2531 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002532 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002533 return;
2534 }
2535
2536 /* Barf if we don't currently hold the mutex. */
2537 if (mutex->__m_count == 0 /* nobody holds it */
2538 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
sewardj4dced352002-06-04 22:54:20 +00002539 VG_(record_pthread_err)( tid,
2540 "pthread_cond_wait/timedwait: mutex is unlocked "
2541 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002542 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002543 return;
2544 }
2545
2546 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002547 VG_(threads)[tid].status = VgTs_WaitCV;
2548 VG_(threads)[tid].associated_cv = cond;
2549 VG_(threads)[tid].associated_mx = mutex;
2550 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002551
2552 if (VG_(clo_trace_pthread_level) >= 1) {
2553 VG_(sprintf)(msg_buf,
2554 "pthread_cond_wait cv %p, mx %p: BLOCK",
2555 cond, mutex );
2556 print_pthread_event(tid, msg_buf);
2557 }
2558
2559 /* Release the mutex. */
2560 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2561}
2562
2563
2564static
2565void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2566 Bool broadcast,
2567 pthread_cond_t *cond )
2568{
2569 Char msg_buf[100];
2570 Char* caller
2571 = broadcast ? "pthread_cond_broadcast"
2572 : "pthread_cond_signal ";
2573
2574 if (VG_(clo_trace_pthread_level) >= 2) {
2575 VG_(sprintf)(msg_buf, "%s cv %p ...",
2576 caller, cond );
2577 print_pthread_event(tid, msg_buf);
2578 }
2579
2580 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002581 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002582 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002583
2584 if (cond == NULL) {
sewardj4dced352002-06-04 22:54:20 +00002585 VG_(record_pthread_err)( tid,
2586 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002587 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002588 return;
2589 }
2590
2591 release_N_threads_waiting_on_cond (
2592 cond,
2593 broadcast ? VG_N_THREADS : 1,
2594 caller
2595 );
2596
sewardjc3bd5f52002-05-01 03:24:23 +00002597 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002598}
2599
sewardj77e466c2002-04-14 02:29:29 +00002600
sewardj5f07b662002-04-23 16:52:51 +00002601/* -----------------------------------------------------------
2602 THREAD SPECIFIC DATA
2603 -------------------------------------------------------- */
2604
2605static __inline__
2606Bool is_valid_key ( ThreadKey k )
2607{
2608 /* k unsigned; hence no < 0 check */
2609 if (k >= VG_N_THREAD_KEYS) return False;
2610 if (!vg_thread_keys[k].inuse) return False;
2611 return True;
2612}
2613
2614static
2615void do_pthread_key_create ( ThreadId tid,
2616 pthread_key_t* key,
2617 void (*destructor)(void*) )
2618{
2619 Int i;
2620 Char msg_buf[100];
2621
2622 if (VG_(clo_trace_pthread_level) >= 1) {
2623 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2624 key, destructor );
2625 print_pthread_event(tid, msg_buf);
2626 }
2627
2628 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002629 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002630 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002631
2632 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2633 if (!vg_thread_keys[i].inuse)
2634 break;
2635
2636 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002637 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002638 return;
2639 */
2640 VG_(panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2641 " increase and recompile");
2642 }
2643
sewardj870497a2002-05-29 01:06:47 +00002644 vg_thread_keys[i].inuse = True;
2645 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002646
sewardj5a3798b2002-06-04 23:24:22 +00002647 /* check key for addressibility */
2648 if (VG_(clo_instrument)
2649 && !VGM_(check_writable)( (Addr)key,
2650 sizeof(pthread_key_t), NULL))
2651 VG_(record_pthread_err)( tid,
2652 "pthread_key_create: key points to invalid location");
sewardj5f07b662002-04-23 16:52:51 +00002653 *key = i;
sewardjc3bd5f52002-05-01 03:24:23 +00002654 if (VG_(clo_instrument))
2655 VGM_(make_readable)( (Addr)key, sizeof(pthread_key_t) );
2656
2657 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002658}
2659
2660
2661static
2662void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2663{
2664 Char msg_buf[100];
2665 if (VG_(clo_trace_pthread_level) >= 1) {
2666 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2667 key );
2668 print_pthread_event(tid, msg_buf);
2669 }
2670
sewardjb48e5002002-05-13 00:16:03 +00002671 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002672 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002673
2674 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002675 VG_(record_pthread_err)( tid,
2676 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002677 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002678 return;
2679 }
2680
2681 vg_thread_keys[key].inuse = False;
2682
2683 /* Optional. We're not required to do this, although it shouldn't
2684 make any difference to programs which use the key/specifics
2685 functions correctly. */
sewardj3b13f0e2002-04-25 20:17:29 +00002686# if 1
sewardj5f07b662002-04-23 16:52:51 +00002687 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00002688 if (VG_(threads)[tid].status != VgTs_Empty)
2689 VG_(threads)[tid].specifics[key] = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002690 }
sewardj3b13f0e2002-04-25 20:17:29 +00002691# endif
sewardj5f07b662002-04-23 16:52:51 +00002692}
2693
2694
2695static
2696void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
2697{
2698 Char msg_buf[100];
2699 if (VG_(clo_trace_pthread_level) >= 1) {
2700 VG_(sprintf)(msg_buf, "pthread_getspecific key %d",
2701 key );
2702 print_pthread_event(tid, msg_buf);
2703 }
2704
sewardjb48e5002002-05-13 00:16:03 +00002705 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002706 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002707
2708 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002709 VG_(record_pthread_err)( tid,
2710 "pthread_getspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002711 SET_EDX(tid, (UInt)NULL);
sewardj5f07b662002-04-23 16:52:51 +00002712 return;
2713 }
2714
sewardj018f7622002-05-15 21:13:39 +00002715 SET_EDX(tid, (UInt)VG_(threads)[tid].specifics[key]);
sewardj5f07b662002-04-23 16:52:51 +00002716}
2717
2718
2719static
2720void do_pthread_setspecific ( ThreadId tid,
2721 pthread_key_t key,
2722 void *pointer )
2723{
2724 Char msg_buf[100];
2725 if (VG_(clo_trace_pthread_level) >= 1) {
2726 VG_(sprintf)(msg_buf, "pthread_setspecific key %d, ptr %p",
2727 key, pointer );
2728 print_pthread_event(tid, msg_buf);
2729 }
2730
sewardjb48e5002002-05-13 00:16:03 +00002731 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002732 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002733
2734 if (!is_valid_key(key)) {
sewardj4dced352002-06-04 22:54:20 +00002735 VG_(record_pthread_err)( tid,
2736 "pthread_setspecific: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002737 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002738 return;
2739 }
2740
sewardj018f7622002-05-15 21:13:39 +00002741 VG_(threads)[tid].specifics[key] = pointer;
sewardjc3bd5f52002-05-01 03:24:23 +00002742 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002743}
2744
2745
sewardj870497a2002-05-29 01:06:47 +00002746/* Helper for calling destructors at thread exit. If key is valid,
2747 copy the thread's specific value into cu->arg and put the *key*'s
2748 destructor fn address in cu->fn. Then return 0 to the caller.
2749 Otherwise return non-zero to the caller. */
2750static
2751void do__get_key_destr_and_spec ( ThreadId tid,
2752 pthread_key_t key,
2753 CleanupEntry* cu )
2754{
2755 Char msg_buf[100];
2756 if (VG_(clo_trace_pthread_level) >= 1) {
2757 VG_(sprintf)(msg_buf,
2758 "get_key_destr_and_arg (key = %d)", key );
2759 print_pthread_event(tid, msg_buf);
2760 }
2761 vg_assert(VG_(is_valid_tid)(tid));
2762 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
2763 if (!vg_thread_keys[key].inuse) {
2764 SET_EDX(tid, -1);
2765 return;
2766 }
2767 cu->fn = vg_thread_keys[key].destructor;
2768 cu->arg = VG_(threads)[tid].specifics[key];
sewardjd140e442002-05-29 01:21:19 +00002769 if (VG_(clo_instrument))
2770 VGM_(make_readable)( (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00002771 SET_EDX(tid, 0);
2772}
2773
2774
sewardjb48e5002002-05-13 00:16:03 +00002775/* ---------------------------------------------------
2776 SIGNALS
2777 ------------------------------------------------ */
2778
2779/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002780 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2781 for OK and 1 for some kind of addressing error, which the
2782 vg_libpthread.c routine turns into return values 0 and EFAULT
2783 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002784static
2785void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002786 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002787 vki_ksigset_t* newmask,
2788 vki_ksigset_t* oldmask )
2789{
2790 Char msg_buf[100];
2791 if (VG_(clo_trace_pthread_level) >= 1) {
2792 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00002793 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
2794 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002795 print_pthread_event(tid, msg_buf);
2796 }
2797
2798 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002799 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002800
2801 if (VG_(clo_instrument)) {
sewardj5a3798b2002-06-04 23:24:22 +00002802 /* check newmask/oldmask are addressible/defined */
sewardj0076f542002-06-16 11:37:06 +00002803 if (newmask
sewardj5a3798b2002-06-04 23:24:22 +00002804 && !VGM_(check_readable)( (Addr)newmask,
2805 sizeof(vki_ksigset_t), NULL))
2806 VG_(record_pthread_err)( tid,
2807 "pthread_sigmask: newmask contains "
2808 "unaddressible or undefined bytes");
sewardj0076f542002-06-16 11:37:06 +00002809 if (oldmask
2810 && !VGM_(check_writable)( (Addr)oldmask,
sewardj5a3798b2002-06-04 23:24:22 +00002811 sizeof(vki_ksigset_t), NULL))
2812 VG_(record_pthread_err)( tid,
2813 "pthread_sigmask: oldmask contains "
2814 "unaddressible bytes");
sewardjb48e5002002-05-13 00:16:03 +00002815 }
2816
sewardj018f7622002-05-15 21:13:39 +00002817 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00002818
sewardj5a3798b2002-06-04 23:24:22 +00002819 if (oldmask && VG_(clo_instrument)) {
2820 VGM_(make_readable)( (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00002821 }
2822
sewardj018f7622002-05-15 21:13:39 +00002823 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00002824 SET_EDX(tid, 0);
2825}
2826
2827
2828static
2829void do_sigwait ( ThreadId tid,
2830 vki_ksigset_t* set,
2831 Int* sig )
2832{
sewardj018f7622002-05-15 21:13:39 +00002833 vki_ksigset_t irrelevant_sigmask;
2834 Char msg_buf[100];
2835
sewardjb48e5002002-05-13 00:16:03 +00002836 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
2837 VG_(sprintf)(msg_buf,
2838 "suspend due to sigwait(): set %p, sig %p",
2839 set, sig );
2840 print_pthread_event(tid, msg_buf);
2841 }
2842
2843 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002844 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00002845
sewardj018f7622002-05-15 21:13:39 +00002846 /* Change SCSS */
2847 VG_(threads)[tid].sigs_waited_for = *set;
2848 VG_(threads)[tid].status = VgTs_WaitSIG;
2849
2850 VG_(block_all_host_signals)( &irrelevant_sigmask );
2851 VG_(handle_SCSS_change)( False /* lazy update */ );
2852}
2853
2854
2855static
2856void do_pthread_kill ( ThreadId tid, /* me */
2857 ThreadId thread, /* thread to signal */
2858 Int sig )
2859{
2860 Char msg_buf[100];
2861
2862 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
2863 VG_(sprintf)(msg_buf,
2864 "pthread_kill thread %d, signo %d",
2865 thread, sig );
2866 print_pthread_event(tid, msg_buf);
2867 }
2868
2869 vg_assert(VG_(is_valid_tid)(tid)
2870 && VG_(threads)[tid].status == VgTs_Runnable);
2871
sewardj4dced352002-06-04 22:54:20 +00002872 if (!VG_(is_valid_tid)(thread)) {
2873 VG_(record_pthread_err)( tid,
2874 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00002875 SET_EDX(tid, -VKI_ESRCH);
2876 return;
2877 }
2878
2879 if (sig < 1 || sig > VKI_KNSIG) {
2880 SET_EDX(tid, -VKI_EINVAL);
2881 return;
2882 }
2883
2884 VG_(send_signal_to_thread)( thread, sig );
2885 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00002886}
2887
2888
sewardj2cb00342002-06-28 01:46:26 +00002889/* -----------------------------------------------------------
2890 FORK HANDLERS.
2891 -------------------------------------------------------- */
2892
2893static
2894void do__set_fhstack_used ( ThreadId tid, Int n )
2895{
2896 Char msg_buf[100];
2897 if (VG_(clo_trace_sched)) {
2898 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
2899 print_pthread_event(tid, msg_buf);
2900 }
2901
2902 vg_assert(VG_(is_valid_tid)(tid)
2903 && VG_(threads)[tid].status == VgTs_Runnable);
2904
2905 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
2906 vg_fhstack_used = n;
2907 SET_EDX(tid, 0);
2908 } else {
2909 SET_EDX(tid, -1);
2910 }
2911}
2912
2913
2914static
2915void do__get_fhstack_used ( ThreadId tid )
2916{
2917 Int n;
2918 Char msg_buf[100];
2919 if (VG_(clo_trace_sched)) {
2920 VG_(sprintf)(msg_buf, "get_fhstack_used" );
2921 print_pthread_event(tid, msg_buf);
2922 }
2923
2924 vg_assert(VG_(is_valid_tid)(tid)
2925 && VG_(threads)[tid].status == VgTs_Runnable);
2926
2927 n = vg_fhstack_used;
2928 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
2929 SET_EDX(tid, n);
2930}
2931
2932static
2933void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
2934{
2935 Char msg_buf[100];
2936 if (VG_(clo_trace_sched)) {
2937 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
2938 print_pthread_event(tid, msg_buf);
2939 }
2940
2941 vg_assert(VG_(is_valid_tid)(tid)
2942 && VG_(threads)[tid].status == VgTs_Runnable);
2943
2944 if (VG_(clo_instrument)) {
2945 /* check fh is addressible/defined */
2946 if (!VGM_(check_readable)( (Addr)fh,
2947 sizeof(ForkHandlerEntry), NULL)) {
2948 VG_(record_pthread_err)( tid,
2949 "pthread_atfork: prepare/parent/child contains "
2950 "unaddressible or undefined bytes");
2951 }
2952 }
2953
2954 if (n < 0 && n >= VG_N_FORKHANDLERSTACK) {
2955 SET_EDX(tid, -1);
2956 return;
2957 }
2958
2959 vg_fhstack[n] = *fh;
2960 SET_EDX(tid, 0);
2961}
2962
2963
2964static
2965void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
2966 ForkHandlerEntry* fh )
2967{
2968 Char msg_buf[100];
2969 if (VG_(clo_trace_sched)) {
2970 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
2971 print_pthread_event(tid, msg_buf);
2972 }
2973
2974 vg_assert(VG_(is_valid_tid)(tid)
2975 && VG_(threads)[tid].status == VgTs_Runnable);
2976
2977 if (VG_(clo_instrument)) {
2978 /* check fh is addressible/defined */
2979 if (!VGM_(check_writable)( (Addr)fh,
2980 sizeof(ForkHandlerEntry), NULL)) {
2981 VG_(record_pthread_err)( tid,
2982 "fork: prepare/parent/child contains "
2983 "unaddressible bytes");
2984 }
2985 }
2986
2987 if (n < 0 && n >= VG_N_FORKHANDLERSTACK) {
2988 SET_EDX(tid, -1);
2989 return;
2990 }
2991
2992 *fh = vg_fhstack[n];
2993 SET_EDX(tid, 0);
2994
2995 if (VG_(clo_instrument)) {
2996 VGM_(make_readable)( (Addr)fh, sizeof(ForkHandlerEntry) );
2997 }
2998}
2999
3000
sewardje663cb92002-04-12 10:26:32 +00003001/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003002 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003003 ------------------------------------------------------------------ */
3004
sewardj124ca2a2002-06-20 10:19:38 +00003005/* Do a client request for the thread tid. After the request, tid may
3006 or may not still be runnable; if not, the scheduler will have to
3007 choose a new thread to run.
3008*/
sewardje663cb92002-04-12 10:26:32 +00003009static
sewardj124ca2a2002-06-20 10:19:38 +00003010void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003011{
sewardj124ca2a2002-06-20 10:19:38 +00003012# define RETURN_WITH(vvv) \
3013 { tst->m_edx = (vvv); \
3014 tst->sh_edx = VGM_WORD_VALID; \
3015 }
3016
3017 ThreadState* tst = &VG_(threads)[tid];
3018 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3019 UInt req_no = arg[0];
3020
3021 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003022 switch (req_no) {
3023
sewardj124ca2a2002-06-20 10:19:38 +00003024 case VG_USERREQ__MALLOC:
3025 RETURN_WITH(
3026 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3027 );
3028 break;
3029
3030 case VG_USERREQ__BUILTIN_NEW:
3031 RETURN_WITH(
3032 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3033 );
3034 break;
3035
3036 case VG_USERREQ__BUILTIN_VEC_NEW:
3037 RETURN_WITH(
3038 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3039 );
3040 break;
3041
3042 case VG_USERREQ__FREE:
3043 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3044 RETURN_WITH(0); /* irrelevant */
3045 break;
3046
3047 case VG_USERREQ__BUILTIN_DELETE:
3048 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3049 RETURN_WITH(0); /* irrelevant */
3050 break;
3051
3052 case VG_USERREQ__BUILTIN_VEC_DELETE:
3053 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3054 RETURN_WITH(0); /* irrelevant */
3055 break;
3056
3057 case VG_USERREQ__CALLOC:
3058 RETURN_WITH(
3059 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3060 );
3061 break;
3062
3063 case VG_USERREQ__REALLOC:
3064 RETURN_WITH(
3065 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3066 );
3067 break;
3068
3069 case VG_USERREQ__MEMALIGN:
3070 RETURN_WITH(
3071 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3072 );
3073 break;
3074
3075 case VG_USERREQ__PTHREAD_GET_THREADID:
3076 RETURN_WITH(tid);
3077 break;
3078
3079 case VG_USERREQ__RUNNING_ON_VALGRIND:
3080 RETURN_WITH(1);
3081 break;
3082
3083 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3084 RETURN_WITH(VG_(clo_trace_pthread_level));
3085 break;
3086
3087 case VG_USERREQ__READ_MILLISECOND_TIMER:
3088 RETURN_WITH(VG_(read_millisecond_timer)());
3089 break;
3090
3091 /* Some of these may make thread tid non-runnable, but the
3092 scheduler checks for that on return from this function. */
3093 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3094 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3095 break;
3096
3097 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3098 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3099 break;
3100
3101 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3102 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3103 break;
3104
3105 case VG_USERREQ__PTHREAD_GETSPECIFIC:
3106 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
3107 break;
3108
3109 case VG_USERREQ__SET_CANCELTYPE:
3110 do__set_canceltype ( tid, arg[1] );
3111 break;
3112
3113 case VG_USERREQ__CLEANUP_PUSH:
3114 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3115 break;
3116
3117 case VG_USERREQ__CLEANUP_POP:
3118 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3119 break;
3120
3121 case VG_USERREQ__TESTCANCEL:
3122 do__testcancel ( tid );
3123 break;
3124
3125 case VG_USERREQ__GET_N_SIGS_RETURNED:
3126 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3127 break;
3128
sewardje663cb92002-04-12 10:26:32 +00003129 case VG_USERREQ__PTHREAD_JOIN:
3130 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3131 break;
3132
sewardj3b5d8862002-04-20 13:53:23 +00003133 case VG_USERREQ__PTHREAD_COND_WAIT:
3134 do_pthread_cond_wait( tid,
3135 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003136 (pthread_mutex_t *)(arg[2]),
3137 0xFFFFFFFF /* no timeout */ );
3138 break;
3139
3140 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3141 do_pthread_cond_wait( tid,
3142 (pthread_cond_t *)(arg[1]),
3143 (pthread_mutex_t *)(arg[2]),
3144 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003145 break;
3146
3147 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3148 do_pthread_cond_signal_or_broadcast(
3149 tid,
3150 False, /* signal, not broadcast */
3151 (pthread_cond_t *)(arg[1]) );
3152 break;
3153
3154 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3155 do_pthread_cond_signal_or_broadcast(
3156 tid,
3157 True, /* broadcast, not signal */
3158 (pthread_cond_t *)(arg[1]) );
3159 break;
3160
sewardj5f07b662002-04-23 16:52:51 +00003161 case VG_USERREQ__PTHREAD_KEY_CREATE:
3162 do_pthread_key_create ( tid,
3163 (pthread_key_t*)(arg[1]),
3164 (void(*)(void*))(arg[2]) );
3165 break;
3166
3167 case VG_USERREQ__PTHREAD_KEY_DELETE:
3168 do_pthread_key_delete ( tid,
3169 (pthread_key_t)(arg[1]) );
3170 break;
3171
sewardj5f07b662002-04-23 16:52:51 +00003172 case VG_USERREQ__PTHREAD_SETSPECIFIC:
3173 do_pthread_setspecific ( tid,
3174 (pthread_key_t)(arg[1]),
3175 (void*)(arg[2]) );
3176 break;
3177
sewardjb48e5002002-05-13 00:16:03 +00003178 case VG_USERREQ__PTHREAD_SIGMASK:
3179 do_pthread_sigmask ( tid,
3180 arg[1],
3181 (vki_ksigset_t*)(arg[2]),
3182 (vki_ksigset_t*)(arg[3]) );
3183 break;
3184
3185 case VG_USERREQ__SIGWAIT:
3186 do_sigwait ( tid,
3187 (vki_ksigset_t*)(arg[1]),
3188 (Int*)(arg[2]) );
3189 break;
3190
sewardj018f7622002-05-15 21:13:39 +00003191 case VG_USERREQ__PTHREAD_KILL:
3192 do_pthread_kill ( tid, arg[1], arg[2] );
3193 break;
3194
sewardjff42d1d2002-05-22 13:17:31 +00003195 case VG_USERREQ__PTHREAD_YIELD:
3196 do_pthread_yield ( tid );
3197 /* because this is classified as a non-trivial client
3198 request, the scheduler should now select a new thread to
3199 run. */
3200 break;
sewardj018f7622002-05-15 21:13:39 +00003201
sewardj7989d0c2002-05-28 11:00:01 +00003202 case VG_USERREQ__SET_CANCELSTATE:
3203 do__set_cancelstate ( tid, arg[1] );
3204 break;
3205
sewardj7989d0c2002-05-28 11:00:01 +00003206 case VG_USERREQ__SET_OR_GET_DETACH:
3207 do__set_or_get_detach ( tid, arg[1], arg[2] );
3208 break;
3209
3210 case VG_USERREQ__SET_CANCELPEND:
3211 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3212 break;
3213
3214 case VG_USERREQ__WAIT_JOINER:
3215 do__wait_joiner ( tid, (void*)arg[1] );
3216 break;
3217
3218 case VG_USERREQ__QUIT:
3219 do__quit ( tid );
3220 break;
3221
3222 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3223 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3224 (void*)arg[2] );
3225 break;
3226
sewardj870497a2002-05-29 01:06:47 +00003227 case VG_USERREQ__GET_KEY_D_AND_S:
3228 do__get_key_destr_and_spec ( tid,
3229 (pthread_key_t)arg[1],
3230 (CleanupEntry*)arg[2] );
3231 break;
3232
sewardjef037c72002-05-30 00:40:03 +00003233 case VG_USERREQ__NUKE_OTHER_THREADS:
3234 VG_(nuke_all_threads_except) ( tid );
3235 SET_EDX(tid, 0);
3236 break;
3237
sewardj4dced352002-06-04 22:54:20 +00003238 case VG_USERREQ__PTHREAD_ERROR:
3239 VG_(record_pthread_err)( tid, (Char*)(arg[1]) );
3240 SET_EDX(tid, 0);
3241 break;
3242
sewardj2cb00342002-06-28 01:46:26 +00003243 case VG_USERREQ__SET_FHSTACK_USED:
3244 do__set_fhstack_used( tid, (Int)(arg[1]) );
3245 break;
3246
3247 case VG_USERREQ__GET_FHSTACK_USED:
3248 do__get_fhstack_used( tid );
3249 break;
3250
3251 case VG_USERREQ__SET_FHSTACK_ENTRY:
3252 do__set_fhstack_entry( tid, (Int)(arg[1]),
3253 (ForkHandlerEntry*)(arg[2]) );
3254 break;
3255
3256 case VG_USERREQ__GET_FHSTACK_ENTRY:
3257 do__get_fhstack_entry( tid, (Int)(arg[1]),
3258 (ForkHandlerEntry*)(arg[2]) );
3259 break;
3260
sewardje663cb92002-04-12 10:26:32 +00003261 case VG_USERREQ__MAKE_NOACCESS:
3262 case VG_USERREQ__MAKE_WRITABLE:
3263 case VG_USERREQ__MAKE_READABLE:
3264 case VG_USERREQ__DISCARD:
3265 case VG_USERREQ__CHECK_WRITABLE:
3266 case VG_USERREQ__CHECK_READABLE:
3267 case VG_USERREQ__MAKE_NOACCESS_STACK:
sewardje663cb92002-04-12 10:26:32 +00003268 case VG_USERREQ__DO_LEAK_CHECK:
sewardj18d75132002-05-16 11:06:21 +00003269 case VG_USERREQ__DISCARD_TRANSLATIONS:
sewardjc3bd5f52002-05-01 03:24:23 +00003270 SET_EDX(
3271 tid,
sewardj018f7622002-05-15 21:13:39 +00003272 VG_(handle_client_request) ( &VG_(threads)[tid], arg )
sewardjc3bd5f52002-05-01 03:24:23 +00003273 );
sewardje663cb92002-04-12 10:26:32 +00003274 break;
3275
sewardj77e466c2002-04-14 02:29:29 +00003276 case VG_USERREQ__SIGNAL_RETURNS:
3277 handle_signal_return(tid);
3278 break;
sewardj54cacf02002-04-12 23:24:59 +00003279
sewardje663cb92002-04-12 10:26:32 +00003280 default:
sewardj124ca2a2002-06-20 10:19:38 +00003281 VG_(printf)("panic'd on client request = 0x%x\n", arg[0] );
3282 VG_(panic)("do_client_request: "
sewardje663cb92002-04-12 10:26:32 +00003283 "unknown request");
3284 /*NOTREACHED*/
3285 break;
3286 }
sewardj124ca2a2002-06-20 10:19:38 +00003287
3288# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003289}
3290
3291
sewardj6072c362002-04-19 14:40:57 +00003292/* ---------------------------------------------------------------------
3293 Sanity checking.
3294 ------------------------------------------------------------------ */
3295
3296/* Internal consistency checks on the sched/pthread structures. */
3297static
3298void scheduler_sanity ( void )
3299{
sewardj3b5d8862002-04-20 13:53:23 +00003300 pthread_mutex_t* mx;
3301 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003302 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003303
sewardj6072c362002-04-19 14:40:57 +00003304 /* VG_(printf)("scheduler_sanity\n"); */
3305 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003306 mx = VG_(threads)[i].associated_mx;
3307 cv = VG_(threads)[i].associated_cv;
3308 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003309 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3310 it's actually held by someone, since otherwise this thread
3311 is deadlocked, (4) the mutex's owner is not us, since
3312 otherwise this thread is also deadlocked. The logic in
3313 do_pthread_mutex_lock rejects attempts by a thread to lock
3314 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003315
sewardjbf290b92002-05-01 02:28:01 +00003316 (2) has been seen to fail sometimes. I don't know why.
3317 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003318 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003319 /* 1 */ vg_assert(mx != NULL);
3320 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003321 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003322 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003323 } else
sewardj018f7622002-05-15 21:13:39 +00003324 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003325 vg_assert(cv != NULL);
3326 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003327 } else {
sewardj05553872002-04-20 20:53:17 +00003328 /* Unfortunately these don't hold true when a sighandler is
3329 running. To be fixed. */
3330 /* vg_assert(cv == NULL); */
3331 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003332 }
sewardjbf290b92002-05-01 02:28:01 +00003333
sewardj018f7622002-05-15 21:13:39 +00003334 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003335 Int
sewardj018f7622002-05-15 21:13:39 +00003336 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3337 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003338 if (i > 1 /* not the root thread */
3339 && stack_used
3340 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3341 VG_(message)(Vg_UserMsg,
3342 "Warning: STACK OVERFLOW: "
3343 "thread %d: stack used %d, available %d",
3344 i, stack_used, VG_PTHREAD_STACK_MIN );
3345 VG_(message)(Vg_UserMsg,
3346 "Terminating Valgrind. If thread(s) "
3347 "really need more stack, increase");
3348 VG_(message)(Vg_UserMsg,
3349 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3350 VG_(exit)(1);
3351 }
sewardjb48e5002002-05-13 00:16:03 +00003352
sewardj018f7622002-05-15 21:13:39 +00003353 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003354 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003355 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003356 } else {
3357 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003358 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003359 }
3360
sewardjbf290b92002-05-01 02:28:01 +00003361 }
sewardj6072c362002-04-19 14:40:57 +00003362 }
sewardj5f07b662002-04-23 16:52:51 +00003363
3364 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3365 if (!vg_thread_keys[i].inuse)
3366 vg_assert(vg_thread_keys[i].destructor == NULL);
3367 }
sewardj6072c362002-04-19 14:40:57 +00003368}
3369
3370
sewardje663cb92002-04-12 10:26:32 +00003371/*--------------------------------------------------------------------*/
3372/*--- end vg_scheduler.c ---*/
3373/*--------------------------------------------------------------------*/