blob: 98d0359b7a07eaa0e5dbcdbf8f5d505fae1b565a [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/*--------------------------------------------------------------------*/
3/*--- A user-space pthreads implementation. vg_scheduler.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
njnc9539842002-10-02 13:26:35 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardje663cb92002-04-12 10:26:32 +00009
10 Copyright (C) 2000-2002 Julian Seward
11 jseward@acm.org
sewardje663cb92002-04-12 10:26:32 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardje663cb92002-04-12 10:26:32 +000029*/
30
31#include "vg_include.h"
njn25e49d8e72002-09-23 09:36:25 +000032#include "valgrind.h" /* for VG_USERREQ__RUNNING_ON_VALGRIND and
33 VG_USERREQ__DISCARD_TRANSLATIONS */
sewardje663cb92002-04-12 10:26:32 +000034
sewardjb60c1ad2002-05-29 20:23:26 +000035/* BORKAGE/ISSUES as of 29 May 02
sewardje663cb92002-04-12 10:26:32 +000036
sewardj77e466c2002-04-14 02:29:29 +000037- Currently, when a signal is run, just the ThreadStatus.status fields
38 are saved in the signal frame, along with the CPU state. Question:
39 should I also save and restore:
40 ThreadStatus.joiner
41 ThreadStatus.waited_on_mid
42 ThreadStatus.awaken_at
43 ThreadStatus.retval
44 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000045
sewardj77e466c2002-04-14 02:29:29 +000046- Signals interrupting read/write and nanosleep: SA_RESTART settings.
47 Read/write correctly return with EINTR when SA_RESTART isn't
48 specified and they are interrupted by a signal. nanosleep just
49 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000050
sewardj705d3cb2002-05-23 13:13:12 +000051- So, what's the deal with signals and mutexes? If a thread is
sewardj6072c362002-04-19 14:40:57 +000052 blocked on a mutex, or for a condition variable for that matter, can
53 signals still be delivered to it? This has serious consequences --
54 deadlocks, etc.
55
sewardj705d3cb2002-05-23 13:13:12 +000056- Signals still not really right. Each thread should have its
57 own pending-set, but there is just one process-wide pending set.
58
sewardjb60c1ad2002-05-29 20:23:26 +000059 TODO for valgrind-1.0:
60
sewardj055fbb82002-05-30 00:40:55 +000061- Update assertion checking in scheduler_sanity().
62
sewardjb60c1ad2002-05-29 20:23:26 +000063 TODO sometime:
64
sewardj645030e2002-06-06 01:27:39 +000065- poll() in the vg_libpthread.c -- should it handle the nanosleep
66 being interrupted by a signal? Ditto accept?
67
sewardjb60c1ad2002-05-29 20:23:26 +000068- Mutex scrubbing - clearup_after_thread_exit: look for threads
69 blocked on mutexes held by the exiting thread, and release them
70 appropriately. (??)
71
72- pthread_atfork
73
sewardje462e202002-04-13 04:09:07 +000074*/
sewardje663cb92002-04-12 10:26:32 +000075
76
77/* ---------------------------------------------------------------------
78 Types and globals for the scheduler.
79 ------------------------------------------------------------------ */
80
81/* type ThreadId is defined in vg_include.h. */
82
83/* struct ThreadState is defined in vg_include.h. */
84
sewardj018f7622002-05-15 21:13:39 +000085/* Globals. A statically allocated array of threads. NOTE: [0] is
86 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000087 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000088ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000089
sewardj2cb00342002-06-28 01:46:26 +000090/* The process' fork-handler stack. */
91static Int vg_fhstack_used = 0;
92static ForkHandlerEntry vg_fhstack[VG_N_FORKHANDLERSTACK];
93
94
sewardj1e8cdc92002-04-18 11:37:52 +000095/* The tid of the thread currently in VG_(baseBlock). */
96static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
97
sewardjb52a1b02002-10-23 21:38:22 +000098/* The tid either currently in baseBlock, or was in baseBlock before
99 was saved it out; this is only updated when a new thread is loaded
100 into the baseBlock */
101static Int vg_tid_last_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000102
103/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
104jmp_buf VG_(scheduler_jmpbuf);
sewardj872051c2002-07-13 12:12:56 +0000105/* This says whether scheduler_jmpbuf is actually valid. Needed so
106 that our signal handler doesn't longjmp when the buffer isn't
107 actually valid. */
108Bool VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000109/* ... and if so, here's the signal which caused it to do so. */
110Int VG_(longjmpd_on_signal);
111
112
113/* Machinery to keep track of which threads are waiting on which
114 fds. */
115typedef
116 struct {
117 /* The thread which made the request. */
118 ThreadId tid;
119
120 /* The next two fields describe the request. */
121 /* File descriptor waited for. -1 means this slot is not in use */
122 Int fd;
123 /* The syscall number the fd is used in. */
124 Int syscall_no;
125
126 /* False => still waiting for select to tell us the fd is ready
127 to go. True => the fd is ready, but the results have not yet
128 been delivered back to the calling thread. Once the latter
129 happens, this entire record is marked as no longer in use, by
130 making the fd field be -1. */
131 Bool ready;
njn25e49d8e72002-09-23 09:36:25 +0000132
133 /* The result from SK_(pre_blocking_syscall)(); is passed to
134 * SK_(post_blocking_syscall)(). */
135 void* pre_result;
sewardje663cb92002-04-12 10:26:32 +0000136 }
137 VgWaitedOnFd;
138
139static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
140
141
sewardj5f07b662002-04-23 16:52:51 +0000142/* Keeping track of keys. */
143typedef
144 struct {
145 /* Has this key been allocated ? */
146 Bool inuse;
147 /* If .inuse==True, records the address of the associated
148 destructor, or NULL if none. */
149 void (*destructor)(void*);
150 }
151 ThreadKeyState;
152
153/* And our array of thread keys. */
154static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
155
156typedef UInt ThreadKey;
157
158
njn25e49d8e72002-09-23 09:36:25 +0000159UInt VG_(written_shadow_reg);
160
sewardje663cb92002-04-12 10:26:32 +0000161/* Forwards */
sewardj124ca2a2002-06-20 10:19:38 +0000162static void do_client_request ( ThreadId tid );
sewardj6072c362002-04-19 14:40:57 +0000163static void scheduler_sanity ( void );
sewardj124ca2a2002-06-20 10:19:38 +0000164static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
sewardjd140e442002-05-29 01:21:19 +0000165
sewardje663cb92002-04-12 10:26:32 +0000166/* ---------------------------------------------------------------------
167 Helper functions for the scheduler.
168 ------------------------------------------------------------------ */
169
sewardjb48e5002002-05-13 00:16:03 +0000170__inline__
171Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000172{
173 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000174 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000175 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000176 if (VG_(threads)[tid].status == VgTs_Empty) return False;
177 return True;
178}
179
180
181__inline__
182Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
183{
184 /* tid is unsigned, hence no < 0 test. */
185 if (tid == 0) return False;
186 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000187 return True;
188}
189
190
sewardj1e8cdc92002-04-18 11:37:52 +0000191/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000192 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
193 if none do. A small complication is dealing with any currently
194 VG_(baseBlock)-resident thread.
sewardj1e8cdc92002-04-18 11:37:52 +0000195*/
njn25e49d8e72002-09-23 09:36:25 +0000196ThreadId VG_(any_matching_thread_stack)
197 ( Bool (*p) ( Addr stack_min, Addr stack_max ))
sewardj1e8cdc92002-04-18 11:37:52 +0000198{
199 ThreadId tid, tid_to_skip;
200
201 tid_to_skip = VG_INVALID_THREADID;
202
203 /* First check to see if there's a currently-loaded thread in
204 VG_(baseBlock). */
205 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
206 tid = vg_tid_currently_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000207 if ( p ( VG_(baseBlock)[VGOFF_(m_esp)],
208 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000209 return tid;
210 else
211 tid_to_skip = tid;
212 }
213
sewardj6072c362002-04-19 14:40:57 +0000214 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000215 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardj1e8cdc92002-04-18 11:37:52 +0000216 if (tid == tid_to_skip) continue;
njn25e49d8e72002-09-23 09:36:25 +0000217 if ( p ( VG_(threads)[tid].m_esp,
218 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000219 return tid;
220 }
221 return VG_INVALID_THREADID;
222}
223
224
sewardj15a43e12002-04-17 19:35:12 +0000225/* Print the scheduler status. */
226void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000227{
228 Int i;
229 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000230 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000231 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000232 VG_(printf)("\nThread %d: status = ", i);
sewardj018f7622002-05-15 21:13:39 +0000233 switch (VG_(threads)[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000234 case VgTs_Runnable: VG_(printf)("Runnable"); break;
235 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
sewardj20917d82002-05-28 01:36:45 +0000236 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee(%d)",
237 VG_(threads)[i].joiner_jee_tid);
238 break;
239 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner"); break;
sewardj6072c362002-04-19 14:40:57 +0000240 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
241 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000242 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000243 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000244 default: VG_(printf)("???"); break;
245 }
sewardj3b5d8862002-04-20 13:53:23 +0000246 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000247 VG_(threads)[i].associated_mx,
248 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000249 VG_(pp_ExeContext)(
njn25e49d8e72002-09-23 09:36:25 +0000250 VG_(get_ExeContext2)( VG_(threads)[i].m_eip, VG_(threads)[i].m_ebp,
251 VG_(threads)[i].m_esp,
252 VG_(threads)[i].stack_highest_word)
253 );
sewardje663cb92002-04-12 10:26:32 +0000254 }
255 VG_(printf)("\n");
256}
257
258static
njn25e49d8e72002-09-23 09:36:25 +0000259void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no, void* pre_res )
sewardje663cb92002-04-12 10:26:32 +0000260{
261 Int i;
262
263 vg_assert(fd != -1); /* avoid total chaos */
264
265 for (i = 0; i < VG_N_WAITING_FDS; i++)
266 if (vg_waiting_fds[i].fd == -1)
267 break;
268
269 if (i == VG_N_WAITING_FDS)
njne427a662002-10-02 11:08:25 +0000270 VG_(core_panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
sewardje663cb92002-04-12 10:26:32 +0000271 /*
272 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
273 tid, fd, i);
274 */
275 vg_waiting_fds[i].fd = fd;
276 vg_waiting_fds[i].tid = tid;
277 vg_waiting_fds[i].ready = False;
278 vg_waiting_fds[i].syscall_no = syscall_no;
njn25e49d8e72002-09-23 09:36:25 +0000279 vg_waiting_fds[i].pre_result = pre_res;
sewardje663cb92002-04-12 10:26:32 +0000280}
281
282
283
284static
285void print_sched_event ( ThreadId tid, Char* what )
286{
sewardj45b4b372002-04-16 22:50:32 +0000287 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000288}
289
290
291static
292void print_pthread_event ( ThreadId tid, Char* what )
293{
294 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000295}
296
297
298static
299Char* name_of_sched_event ( UInt event )
300{
301 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000302 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
303 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
304 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
305 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
306 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
307 default: return "??UNKNOWN??";
308 }
309}
310
311
312/* Create a translation of the client basic block beginning at
313 orig_addr, and add it to the translation cache & translation table.
314 This probably doesn't really belong here, but, hey ...
315*/
sewardj1e8cdc92002-04-18 11:37:52 +0000316static
317void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000318{
sewardj22854b92002-11-30 14:00:47 +0000319 Addr trans_addr;
320 Int orig_size, trans_size;
321 UShort jumps[VG_MAX_JUMPS];
322 Int i;
323
324 for(i = 0; i < VG_MAX_JUMPS; i++)
325 jumps[i] = (UShort)-1;
sewardj6c3769f2002-11-29 01:02:45 +0000326
327 /* Make a translation, into temporary storage. */
sewardj018f7622002-05-15 21:13:39 +0000328 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +0000329 orig_addr, &orig_size, &trans_addr, &trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000330
331 /* Copy data at trans_addr into the translation cache. */
sewardje663cb92002-04-12 10:26:32 +0000332 /* Since the .orig_size and .trans_size fields are
333 UShort, be paranoid. */
334 vg_assert(orig_size > 0 && orig_size < 65536);
335 vg_assert(trans_size > 0 && trans_size < 65536);
sewardj6c3769f2002-11-29 01:02:45 +0000336
sewardj22854b92002-11-30 14:00:47 +0000337 VG_(add_to_trans_tab)( orig_addr, orig_size, trans_addr, trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000338
sewardje663cb92002-04-12 10:26:32 +0000339 /* Free the intermediary -- was allocated by VG_(emit_code). */
njn25e49d8e72002-09-23 09:36:25 +0000340 VG_(arena_free)( VG_AR_JITTER, (void*)trans_addr );
sewardje663cb92002-04-12 10:26:32 +0000341}
342
343
344/* Allocate a completely empty ThreadState record. */
345static
346ThreadId vg_alloc_ThreadState ( void )
347{
348 Int i;
sewardj6072c362002-04-19 14:40:57 +0000349 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000350 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000351 return i;
352 }
353 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
354 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000355 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000356 /*NOTREACHED*/
357}
358
njn25e49d8e72002-09-23 09:36:25 +0000359ThreadState* VG_(get_ThreadState)( ThreadId tid )
360{
361 vg_assert(tid >= 0 && tid < VG_N_THREADS);
362 return & VG_(threads)[tid];
363}
sewardje663cb92002-04-12 10:26:32 +0000364
sewardj1e8cdc92002-04-18 11:37:52 +0000365ThreadState* VG_(get_current_thread_state) ( void )
366{
sewardj018f7622002-05-15 21:13:39 +0000367 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
368 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000369}
370
371
372ThreadId VG_(get_current_tid) ( void )
373{
sewardjb52a1b02002-10-23 21:38:22 +0000374 if (!VG_(is_valid_tid)(vg_tid_currently_in_baseBlock))
375 return VG_INVALID_THREADID;
sewardj1e8cdc92002-04-18 11:37:52 +0000376 return vg_tid_currently_in_baseBlock;
377}
378
sewardjb52a1b02002-10-23 21:38:22 +0000379ThreadId VG_(get_current_or_recent_tid) ( void )
njn25e49d8e72002-09-23 09:36:25 +0000380{
sewardjb52a1b02002-10-23 21:38:22 +0000381 vg_assert(vg_tid_currently_in_baseBlock == vg_tid_last_in_baseBlock ||
382 vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
383 vg_assert(VG_(is_valid_tid)(vg_tid_last_in_baseBlock));
384
385 return vg_tid_last_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000386}
387
sewardj7ab2aca2002-10-20 19:40:32 +0000388ThreadId VG_(get_tid_from_ThreadState) (ThreadState* tst)
389{
390 vg_assert(tst >= &VG_(threads)[1] && tst < &VG_(threads)[VG_N_THREADS]);
391 return tst->tid;
392}
393
sewardje663cb92002-04-12 10:26:32 +0000394/* Copy the saved state of a thread into VG_(baseBlock), ready for it
395 to be run. */
396__inline__
397void VG_(load_thread_state) ( ThreadId tid )
398{
399 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000400 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
401
sewardj92a59562002-09-30 00:53:10 +0000402 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
403 VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs;
404 VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss;
405 VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds;
406 VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es;
407 VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs;
408 VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs;
409
sewardj018f7622002-05-15 21:13:39 +0000410 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
411 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
412 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
413 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
414 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
415 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
416 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
417 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
sewardjfa492d42002-12-08 18:20:01 +0000418 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags & ~EFlagD;
419 VG_(baseBlock)[VGOFF_(m_dflag)] = VG_(extractDflag)(VG_(threads)[tid].m_eflags);
sewardj018f7622002-05-15 21:13:39 +0000420 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000421
422 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000423 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000424
njn25e49d8e72002-09-23 09:36:25 +0000425 if (VG_(needs).shadow_regs) {
426 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
427 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
428 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
429 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
430 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
431 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
432 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
433 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
434 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
435 } else {
436 /* Fields shouldn't be used -- check their values haven't changed. */
437 /* Nb: they are written to by some macros like SET_EDX, but they
438 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
439 vg_assert(
440 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
441 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
442 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
443 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
444 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
445 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
446 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
447 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
448 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
449 }
sewardj1e8cdc92002-04-18 11:37:52 +0000450
451 vg_tid_currently_in_baseBlock = tid;
sewardjb52a1b02002-10-23 21:38:22 +0000452 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000453}
454
455
456/* Copy the state of a thread from VG_(baseBlock), presumably after it
457 has been descheduled. For sanity-check purposes, fill the vacated
458 VG_(baseBlock) with garbage so as to make the system more likely to
459 fail quickly if we erroneously continue to poke around inside
460 VG_(baseBlock) without first doing a load_thread_state().
461*/
462__inline__
463void VG_(save_thread_state) ( ThreadId tid )
464{
465 Int i;
466 const UInt junk = 0xDEADBEEF;
467
sewardj1e8cdc92002-04-18 11:37:52 +0000468 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
469
sewardj92a59562002-09-30 00:53:10 +0000470
471 /* We don't copy out the LDT entry, because it can never be changed
472 by the normal actions of the thread, only by the modify_ldt
473 syscall, in which case we will correctly be updating
474 VG_(threads)[tid].ldt. */
sewardjca340b32002-12-08 22:14:11 +0000475 if ((void*)VG_(threads)[tid].ldt != (void*)VG_(baseBlock)[VGOFF_(ldt)])
476 VG_(printf)("VG_(threads)[%d].ldt=%p VG_(baseBlock)[VGOFF_(ldt)]=%p\n",
477 tid, (void*)VG_(threads)[tid].ldt, (void*)VG_(baseBlock)[VGOFF_(ldt)]);
478
sewardj92a59562002-09-30 00:53:10 +0000479 vg_assert((void*)VG_(threads)[tid].ldt
480 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
481
482 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
483 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
484 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
485 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
486 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
487 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
488
sewardj018f7622002-05-15 21:13:39 +0000489 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
490 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
491 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
492 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
493 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
494 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
495 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
496 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardjfa492d42002-12-08 18:20:01 +0000497 VG_(threads)[tid].m_eflags = VG_(insertDflag)(VG_(baseBlock)[VGOFF_(m_eflags)],
498 VG_(baseBlock)[VGOFF_(m_dflag)]);
sewardj018f7622002-05-15 21:13:39 +0000499 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000500
501 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000502 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000503
njn25e49d8e72002-09-23 09:36:25 +0000504 if (VG_(needs).shadow_regs) {
505 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
506 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
507 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
508 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
509 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
510 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
511 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
512 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
513 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
514 } else {
515 /* Fill with recognisable junk */
516 VG_(threads)[tid].sh_eax =
517 VG_(threads)[tid].sh_ebx =
518 VG_(threads)[tid].sh_ecx =
519 VG_(threads)[tid].sh_edx =
520 VG_(threads)[tid].sh_esi =
521 VG_(threads)[tid].sh_edi =
522 VG_(threads)[tid].sh_ebp =
523 VG_(threads)[tid].sh_esp =
524 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
525 }
sewardje663cb92002-04-12 10:26:32 +0000526
527 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000528 VG_(baseBlock)[VGOFF_(ldt)] = junk;
529 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
530 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
531 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
532 VG_(baseBlock)[VGOFF_(m_es)] = junk;
533 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
534 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
535
sewardje663cb92002-04-12 10:26:32 +0000536 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
537 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
538 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
539 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
540 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
541 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
542 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
543 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
544 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
545 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
546
547 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
548 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000549
550 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000551}
552
553
554/* Run the thread tid for a while, and return a VG_TRC_* value to the
555 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000556static
sewardje663cb92002-04-12 10:26:32 +0000557UInt run_thread_for_a_while ( ThreadId tid )
558{
sewardj7ccc5c22002-04-24 21:39:11 +0000559 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000560 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000561 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000562 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000563 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000564
sewardj671ff542002-05-07 09:25:30 +0000565 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000566 VG_(load_thread_state) ( tid );
567 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
568 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000569 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000570 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000571 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000572 /* We get here if the client didn't take a fault. */
573 } else {
574 /* We get here if the client took a fault, which caused our
575 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000576 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000577 vg_assert(trc == 0);
578 trc = VG_TRC_UNRESUMABLE_SIGNAL;
579 }
sewardj872051c2002-07-13 12:12:56 +0000580
581 vg_assert(!VG_(scheduler_jmpbuf_valid));
582
sewardje663cb92002-04-12 10:26:32 +0000583 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000584 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000585 return trc;
586}
587
588
sewardj20917d82002-05-28 01:36:45 +0000589static
590void mostly_clear_thread_record ( ThreadId tid )
591{
sewardj20917d82002-05-28 01:36:45 +0000592 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000593 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000594 VG_(threads)[tid].tid = tid;
595 VG_(threads)[tid].status = VgTs_Empty;
596 VG_(threads)[tid].associated_mx = NULL;
597 VG_(threads)[tid].associated_cv = NULL;
598 VG_(threads)[tid].awaken_at = 0;
599 VG_(threads)[tid].joinee_retval = NULL;
600 VG_(threads)[tid].joiner_thread_return = NULL;
601 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000602 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000603 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
604 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
605 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000606 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000607 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000608 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
609 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardj00a66b12002-10-12 16:42:35 +0000610 VG_(threads)[tid].specifics_ptr = NULL;
sewardj20917d82002-05-28 01:36:45 +0000611}
612
613
sewardje663cb92002-04-12 10:26:32 +0000614/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000615 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000616 caller takes care to park the client's state is parked in
617 VG_(baseBlock).
618*/
619void VG_(scheduler_init) ( void )
620{
621 Int i;
622 Addr startup_esp;
623 ThreadId tid_main;
624
625 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000626
627 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
daywalkera2562202002-07-15 19:39:51 +0000628 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)
njn25e49d8e72002-09-23 09:36:25 +0000629 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_3)
630 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_4)) {
sewardja1679dd2002-05-10 22:31:40 +0000631 /* Jolly good! */
632 } else {
njn25e49d8e72002-09-23 09:36:25 +0000633 VG_(printf)(
634 "%%esp at startup = %p is not near %p, %p, %p or %p; aborting\n",
635 (void*)startup_esp,
636 (void*)VG_STARTUP_STACK_BASE_1,
637 (void*)VG_STARTUP_STACK_BASE_2,
638 (void*)VG_STARTUP_STACK_BASE_3,
639 (void*)VG_STARTUP_STACK_BASE_4
640 );
njne427a662002-10-02 11:08:25 +0000641 VG_(core_panic)("unexpected %esp at startup");
sewardje663cb92002-04-12 10:26:32 +0000642 }
643
sewardj6072c362002-04-19 14:40:57 +0000644 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000645 mostly_clear_thread_record(i);
646 VG_(threads)[i].stack_size = 0;
647 VG_(threads)[i].stack_base = (Addr)NULL;
648 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000649 }
650
651 for (i = 0; i < VG_N_WAITING_FDS; i++)
652 vg_waiting_fds[i].fd = -1; /* not in use */
653
sewardj5f07b662002-04-23 16:52:51 +0000654 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
655 vg_thread_keys[i].inuse = False;
656 vg_thread_keys[i].destructor = NULL;
657 }
658
sewardj2cb00342002-06-28 01:46:26 +0000659 vg_fhstack_used = 0;
660
sewardje663cb92002-04-12 10:26:32 +0000661 /* Assert this is thread zero, which has certain magic
662 properties. */
663 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000664 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000665 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000666
667 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000668 vg_tid_currently_in_baseBlock = tid_main;
sewardjb52a1b02002-10-23 21:38:22 +0000669 vg_tid_last_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000670 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000671
sewardj018f7622002-05-15 21:13:39 +0000672 VG_(threads)[tid_main].stack_highest_word
673 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000674
sewardj1e8cdc92002-04-18 11:37:52 +0000675 /* So now ... */
676 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000677
678 /* Not running client code right now. */
679 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000680}
681
682
683/* What if fd isn't a valid fd? */
684static
685void set_fd_nonblocking ( Int fd )
686{
687 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
688 vg_assert(!VG_(is_kerror)(res));
689 res |= VKI_O_NONBLOCK;
690 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
691 vg_assert(!VG_(is_kerror)(res));
692}
693
694static
695void set_fd_blocking ( Int fd )
696{
697 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
698 vg_assert(!VG_(is_kerror)(res));
699 res &= ~VKI_O_NONBLOCK;
700 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
701 vg_assert(!VG_(is_kerror)(res));
702}
703
704static
705Bool fd_is_blockful ( Int fd )
706{
707 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
708 vg_assert(!VG_(is_kerror)(res));
709 return (res & VKI_O_NONBLOCK) ? False : True;
710}
711
sewardj3947e622002-05-23 16:52:11 +0000712static
713Bool fd_is_valid ( Int fd )
714{
715 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
716 return VG_(is_kerror)(res) ? False : True;
717}
718
sewardje663cb92002-04-12 10:26:32 +0000719
720
sewardj6072c362002-04-19 14:40:57 +0000721/* vthread tid is returning from a signal handler; modify its
722 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000723
724/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
725 for read or write, has been interrupted by a signal. Find and
726 clear the relevant vg_waiting_fd[] entry. Most of the code in this
727 procedure is total paranoia, if you look closely. */
728static
729void cleanup_waiting_fd_table ( ThreadId tid )
730{
731 Int i, waiters;
732
sewardjb48e5002002-05-13 00:16:03 +0000733 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000734 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
735 vg_assert(VG_(threads)[tid].m_eax == __NR_read
736 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000737
738 /* Excessively paranoidly ... find the fd this op was waiting
739 for, and mark it as not being waited on. */
740 waiters = 0;
741 for (i = 0; i < VG_N_WAITING_FDS; i++) {
742 if (vg_waiting_fds[i].tid == tid) {
743 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000744 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000745 }
746 }
747 vg_assert(waiters == 1);
748 for (i = 0; i < VG_N_WAITING_FDS; i++)
749 if (vg_waiting_fds[i].tid == tid)
750 break;
751 vg_assert(i < VG_N_WAITING_FDS);
752 vg_assert(vg_waiting_fds[i].fd != -1);
753 vg_waiting_fds[i].fd = -1; /* not in use */
754}
755
756
sewardj6072c362002-04-19 14:40:57 +0000757static
758void handle_signal_return ( ThreadId tid )
759{
760 Char msg_buf[100];
761 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000762 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000763
sewardjb48e5002002-05-13 00:16:03 +0000764 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000765
sewardj9a2224b2002-06-19 10:17:40 +0000766 /* Increment signal-returned counter. Used only to implement
767 pause(). */
768 VG_(threads)[tid].n_signals_returned++;
769
sewardj6072c362002-04-19 14:40:57 +0000770 restart_blocked_syscalls = VG_(signal_returns)(tid);
771
772 if (restart_blocked_syscalls)
773 /* Easy; we don't have to do anything. */
774 return;
775
sewardj018f7622002-05-15 21:13:39 +0000776 if (VG_(threads)[tid].status == VgTs_WaitFD
777 && (VG_(threads)[tid].m_eax == __NR_read
778 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000779 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000780 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000781 VG_(threads)[tid].m_eax = -VKI_EINTR;
782 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000783
sewardj6072c362002-04-19 14:40:57 +0000784 if (VG_(clo_trace_sched)) {
785 VG_(sprintf)(msg_buf,
786 "read() / write() interrupted by signal; return EINTR" );
787 print_sched_event(tid, msg_buf);
788 }
789 return;
790 }
791
sewardj645030e2002-06-06 01:27:39 +0000792 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000793 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000794 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000795 write the unused time to nanosleep's second param, but that's
796 too much effort ... we just say that 1 nanosecond was not
797 used, and return EINTR. */
798 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
799 if (rem != NULL) {
800 rem->tv_sec = 0;
801 rem->tv_nsec = 1;
802 }
803 SET_EAX(tid, -VKI_EINTR);
804 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000805 return;
806 }
807
sewardj018f7622002-05-15 21:13:39 +0000808 if (VG_(threads)[tid].status == VgTs_WaitFD) {
njne427a662002-10-02 11:08:25 +0000809 VG_(core_panic)("handle_signal_return: unknown interrupted syscall");
sewardj1ffa8da2002-04-26 22:47:57 +0000810 }
811
sewardj6072c362002-04-19 14:40:57 +0000812 /* All other cases? Just return. */
813}
814
815
sewardje663cb92002-04-12 10:26:32 +0000816static
817void sched_do_syscall ( ThreadId tid )
818{
njn25e49d8e72002-09-23 09:36:25 +0000819 UInt saved_eax;
820 UInt res, syscall_no;
821 UInt fd;
822 void* pre_res;
823 Bool orig_fd_blockness;
824 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000825
sewardjb48e5002002-05-13 00:16:03 +0000826 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000827 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000828
sewardj018f7622002-05-15 21:13:39 +0000829 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000830
831 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000832 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000833 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000834 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000835 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000836 t_awaken
837 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000838 + (UInt)1000ULL * (UInt)(req->tv_sec)
839 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000840 VG_(threads)[tid].status = VgTs_Sleeping;
841 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000842 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000843 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000844 t_now, t_awaken-t_now);
845 print_sched_event(tid, msg_buf);
846 }
847 /* Force the scheduler to run something else for a while. */
848 return;
849 }
850
sewardjaec22c02002-04-29 01:58:08 +0000851 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000852 /* We think it's non-blocking. Just do it in the normal way. */
853 VG_(perform_assumed_nonblocking_syscall)(tid);
854 /* The thread is still runnable. */
855 return;
856 }
857
sewardje663cb92002-04-12 10:26:32 +0000858 /* Set the fd to nonblocking, and do the syscall, which will return
859 immediately, in order to lodge a request with the Linux kernel.
860 We later poll for I/O completion using select(). */
861
sewardj018f7622002-05-15 21:13:39 +0000862 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000863
864 /* Deal with error case immediately. */
865 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000866 if (VG_(needs).core_errors)
867 VG_(message)(Vg_UserMsg,
868 "Warning: invalid file descriptor %d in syscall %s",
869 fd, syscall_no == __NR_read ? "read()" : "write()" );
870 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000871 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000872 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000873 /* We're still runnable. */
874 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
875 return;
876 }
877
878 /* From here onwards we know that fd is valid. */
879
sewardje663cb92002-04-12 10:26:32 +0000880 orig_fd_blockness = fd_is_blockful(fd);
881 set_fd_nonblocking(fd);
882 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000883 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000884
885 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000886 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000887 KERNEL_DO_SYSCALL(tid,res);
888
889 /* Restore original blockfulness of the fd. */
890 if (orig_fd_blockness)
891 set_fd_blocking(fd);
892 else
893 set_fd_nonblocking(fd);
894
sewardjaec22c02002-04-29 01:58:08 +0000895 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
896 /* Finish off in the normal way. Don't restore %EAX, since that
897 now (correctly) holds the result of the call. We get here if either:
898 1. The call didn't block, or
899 2. The fd was already in nonblocking mode before we started to
900 mess with it. In this case, we're not expecting to handle
901 the I/O completion -- the client is. So don't file a
902 completion-wait entry.
903 */
njn25e49d8e72002-09-23 09:36:25 +0000904 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000905 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000906 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000907
908 } else {
909
sewardjaec22c02002-04-29 01:58:08 +0000910 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
911
sewardje663cb92002-04-12 10:26:32 +0000912 /* It would have blocked. First, restore %EAX to what it was
913 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000914 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000915 /* Put this fd in a table of fds on which we are waiting for
916 completion. The arguments for select() later are constructed
917 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000918 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
919 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000920 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000921 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000922 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000923 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
924 print_sched_event(tid, msg_buf);
925 }
926
927 }
928}
929
930
931/* Find out which of the fds in vg_waiting_fds are now ready to go, by
932 making enquiries with select(), and mark them as ready. We have to
933 wait for the requesting threads to fall into the the WaitFD state
934 before we can actually finally deliver the results, so this
935 procedure doesn't do that; complete_blocked_syscalls() does it.
936
937 It might seem odd that a thread which has done a blocking syscall
938 is not in WaitFD state; the way this can happen is if it initially
939 becomes WaitFD, but then a signal is delivered to it, so it becomes
940 Runnable for a while. In this case we have to wait for the
941 sighandler to return, whereupon the WaitFD state is resumed, and
942 only at that point can the I/O result be delivered to it. However,
943 this point may be long after the fd is actually ready.
944
945 So, poll_for_ready_fds() merely detects fds which are ready.
946 complete_blocked_syscalls() does the second half of the trick,
947 possibly much later: it delivers the results from ready fds to
948 threads in WaitFD state.
949*/
sewardj9a199dc2002-04-14 13:01:38 +0000950static
sewardje663cb92002-04-12 10:26:32 +0000951void poll_for_ready_fds ( void )
952{
953 vki_ksigset_t saved_procmask;
954 vki_fd_set readfds;
955 vki_fd_set writefds;
956 vki_fd_set exceptfds;
957 struct vki_timeval timeout;
958 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
959 ThreadId tid;
960 Bool rd_ok, wr_ok, ex_ok;
961 Char msg_buf[100];
962
sewardje462e202002-04-13 04:09:07 +0000963 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000964 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000965
sewardje663cb92002-04-12 10:26:32 +0000966 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000967 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000968 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000969 break;
sewardj6072c362002-04-19 14:40:57 +0000970
sewardj5f07b662002-04-23 16:52:51 +0000971 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000972 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000973 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000974 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000975 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000976 continue;
sewardj018f7622002-05-15 21:13:39 +0000977 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +0000978 /* Resume this thread. Set to zero the remaining-time
979 (second) arg of nanosleep, since it's used up all its
980 time. */
sewardj018f7622002-05-15 21:13:39 +0000981 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
982 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +0000983 if (rem != NULL) {
984 rem->tv_sec = 0;
985 rem->tv_nsec = 0;
986 }
987 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +0000988 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +0000989 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +0000990 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000991 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000992 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +0000993 t_now);
994 print_sched_event(tid, msg_buf);
995 }
sewardje663cb92002-04-12 10:26:32 +0000996 }
997 }
998 }
sewardje663cb92002-04-12 10:26:32 +0000999
sewardje462e202002-04-13 04:09:07 +00001000 /* And look for threads waiting on file descriptors which are now
1001 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +00001002 timeout.tv_sec = 0;
1003 timeout.tv_usec = 0;
1004
1005 VKI_FD_ZERO(&readfds);
1006 VKI_FD_ZERO(&writefds);
1007 VKI_FD_ZERO(&exceptfds);
1008 fd_max = -1;
1009 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1010 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1011 continue;
1012 if (vg_waiting_fds[i].ready /* already ready? */)
1013 continue;
1014 fd = vg_waiting_fds[i].fd;
1015 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001016 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001017 if (fd > fd_max)
1018 fd_max = fd;
1019 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001020 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001021 syscall_no = vg_waiting_fds[i].syscall_no;
1022 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001023 case __NR_read:
1024 /* In order to catch timeout events on fds which are
1025 readable and which have been ioctl(TCSETA)'d with a
1026 VTIMEout, we appear to need to ask if the fd is
1027 writable, for some reason. Ask me not why. Since this
1028 is strange and potentially troublesome we only do it if
1029 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001030 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001031 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001032 VKI_FD_SET(fd, &readfds); break;
1033 case __NR_write:
1034 VKI_FD_SET(fd, &writefds); break;
1035 default:
njne427a662002-10-02 11:08:25 +00001036 VG_(core_panic)("poll_for_ready_fds: unexpected syscall");
sewardje663cb92002-04-12 10:26:32 +00001037 /*NOTREACHED*/
1038 break;
1039 }
1040 }
1041
sewardje462e202002-04-13 04:09:07 +00001042 /* Short cut: if no fds are waiting, give up now. */
1043 if (fd_max == -1)
1044 return;
1045
sewardje663cb92002-04-12 10:26:32 +00001046 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1047 getting interrupted. */
1048 VG_(block_all_host_signals)( &saved_procmask );
1049
1050 n_ready = VG_(select)
1051 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1052 if (VG_(is_kerror)(n_ready)) {
1053 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
njne427a662002-10-02 11:08:25 +00001054 VG_(core_panic)("poll_for_ready_fds: select failed?!");
sewardje663cb92002-04-12 10:26:32 +00001055 /*NOTREACHED*/
1056 }
1057
1058 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001059 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001060
1061 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1062
1063 if (n_ready == 0)
1064 return;
1065
1066 /* Inspect all the fds we know about, and handle any completions that
1067 have happened. */
1068 /*
1069 VG_(printf)("\n\n");
1070 for (fd = 0; fd < 100; fd++)
1071 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1072 VG_(printf)("X"); } else { VG_(printf)("."); };
1073 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1074 */
1075
1076 for (fd = 0; fd <= fd_max; fd++) {
1077 rd_ok = VKI_FD_ISSET(fd, &readfds);
1078 wr_ok = VKI_FD_ISSET(fd, &writefds);
1079 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1080
1081 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1082 if (n_ok == 0)
1083 continue;
1084 if (n_ok > 1) {
1085 VG_(printf)("offending fd = %d\n", fd);
njne427a662002-10-02 11:08:25 +00001086 VG_(core_panic)("poll_for_ready_fds: multiple events on fd");
sewardje663cb92002-04-12 10:26:32 +00001087 }
sewardjbc7d8782002-06-30 12:44:54 +00001088
sewardje663cb92002-04-12 10:26:32 +00001089 /* An I/O event completed for fd. Find the thread which
1090 requested this. */
1091 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1092 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1093 continue;
1094 if (vg_waiting_fds[i].fd == fd)
1095 break;
1096 }
1097
1098 /* And a bit more paranoia ... */
1099 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1100
1101 /* Mark the fd as ready. */
1102 vg_assert(! vg_waiting_fds[i].ready);
1103 vg_waiting_fds[i].ready = True;
1104 }
1105}
1106
1107
1108/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001109static
sewardje663cb92002-04-12 10:26:32 +00001110void complete_blocked_syscalls ( void )
1111{
1112 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001113 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001114 ThreadId tid;
1115 Char msg_buf[100];
1116
1117 /* Inspect all the outstanding fds we know about. */
1118
1119 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1120 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1121 continue;
1122 if (! vg_waiting_fds[i].ready)
1123 continue;
1124
1125 fd = vg_waiting_fds[i].fd;
1126 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001127 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001128
1129 /* The thread actually has to be waiting for the I/O event it
1130 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001131 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001132 continue;
1133
1134 /* Ok, actually do it! We can safely use %EAX as the syscall
1135 number, because the speculative call made by
1136 sched_do_syscall() doesn't change %EAX in the case where the
1137 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001138 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001139 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001140
njn25e49d8e72002-09-23 09:36:25 +00001141 pre_res = vg_waiting_fds[i].pre_result;
1142
sewardjbc7d8782002-06-30 12:44:54 +00001143 /* In a rare case pertaining to writing into a pipe, write()
1144 will block when asked to write > 4096 bytes even though the
1145 kernel claims, when asked via select(), that blocking will
1146 not occur for a write on that fd. This can cause deadlocks.
1147 An easy answer is to limit the size of the write to 4096
1148 anyway and hope that the client program's logic can handle
1149 the short write. That shoulds dubious to me, so we don't do
1150 it by default. */
1151 if (syscall_no == __NR_write
1152 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1153 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1154 /* VG_(printf)("truncate write from %d to 4096\n",
1155 VG_(threads)[tid].m_edx ); */
1156 VG_(threads)[tid].m_edx = 4096;
1157 }
1158
sewardje663cb92002-04-12 10:26:32 +00001159 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001160 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001161
1162 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001163 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001164 /* Mark slot as no longer in use. */
1165 vg_waiting_fds[i].fd = -1;
1166 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001167 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001168 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1169 print_sched_event(tid, msg_buf);
1170 }
1171 }
1172}
1173
1174
1175static
sewardj5f07b662002-04-23 16:52:51 +00001176void check_for_pthread_cond_timedwait ( void )
1177{
sewardj51c0aaf2002-04-25 01:32:10 +00001178 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001179 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001180 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001181 continue;
sewardj018f7622002-05-15 21:13:39 +00001182 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001183 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001184 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001185 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001186 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001187 }
sewardj5f07b662002-04-23 16:52:51 +00001188 }
1189}
1190
1191
1192static
sewardje663cb92002-04-12 10:26:32 +00001193void nanosleep_for_a_while ( void )
1194{
1195 Int res;
1196 struct vki_timespec req;
1197 struct vki_timespec rem;
1198 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001199 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001200 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001201 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001202}
1203
1204
1205/* ---------------------------------------------------------------------
1206 The scheduler proper.
1207 ------------------------------------------------------------------ */
1208
1209/* Run user-space threads until either
1210 * Deadlock occurs
1211 * One thread asks to shutdown Valgrind
1212 * The specified number of basic blocks has gone by.
1213*/
1214VgSchedReturnCode VG_(scheduler) ( void )
1215{
1216 ThreadId tid, tid_next;
1217 UInt trc;
1218 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001219 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001220 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001221 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001222
sewardje663cb92002-04-12 10:26:32 +00001223 /* Start with the root thread. tid in general indicates the
1224 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001225 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001226
1227 /* This is the top level scheduler loop. It falls into three
1228 phases. */
1229 while (True) {
1230
sewardj6072c362002-04-19 14:40:57 +00001231 /* ======================= Phase 0 of 3 =======================
1232 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001233 stage1:
sewardj6072c362002-04-19 14:40:57 +00001234 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001235 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001236
sewardje663cb92002-04-12 10:26:32 +00001237 /* ======================= Phase 1 of 3 =======================
1238 Handle I/O completions and signals. This may change the
1239 status of various threads. Then select a new thread to run,
1240 or declare deadlock, or sleep if there are no runnable
1241 threads but some are blocked on I/O. */
1242
sewardje663cb92002-04-12 10:26:32 +00001243 /* Was a debug-stop requested? */
1244 if (VG_(bbs_to_go) == 0)
1245 goto debug_stop;
1246
1247 /* Do the following loop until a runnable thread is found, or
1248 deadlock is detected. */
1249 while (True) {
1250
1251 /* For stats purposes only. */
1252 VG_(num_scheduling_events_MAJOR) ++;
1253
1254 /* See if any I/O operations which we were waiting for have
1255 completed, and, if so, make runnable the relevant waiting
1256 threads. */
1257 poll_for_ready_fds();
1258 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001259 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001260
1261 /* See if there are any signals which need to be delivered. If
1262 so, choose thread(s) to deliver them to, and build signal
1263 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001264
1265 /* Be careful about delivering signals to a thread waiting
1266 for a mutex. In particular, when the handler is running,
1267 that thread is temporarily apparently-not-waiting for the
1268 mutex, so if it is unlocked by another thread whilst the
1269 handler is running, this thread is not informed. When the
1270 handler returns, the thread resumes waiting on the mutex,
1271 even if, as a result, it has missed the unlocking of it.
1272 Potential deadlock. This sounds all very strange, but the
1273 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001274 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001275 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001276 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001277
1278 /* Try and find a thread (tid) to run. */
1279 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001280 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001281 while (True) {
1282 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001283 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001284 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1285 || VG_(threads)[tid_next].status == VgTs_Sleeping
1286 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1287 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1288 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001289 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001290 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001291 break; /* We can run this one. */
1292 if (tid_next == tid)
1293 break; /* been all the way round */
1294 }
1295 tid = tid_next;
1296
sewardj018f7622002-05-15 21:13:39 +00001297 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001298 /* Found a suitable candidate. Fall out of this loop, so
1299 we can advance to stage 2 of the scheduler: actually
1300 running the thread. */
1301 break;
1302 }
1303
1304 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001305 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001306 /* No runnable threads and no prospect of any appearing
1307 even if we wait for an arbitrary length of time. In
1308 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001309 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001310 return VgSrc_Deadlock;
1311 }
1312
1313 /* At least one thread is in a fd-wait state. Delay for a
1314 while, and go round again, in the hope that eventually a
1315 thread becomes runnable. */
1316 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001317 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001318 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001319 }
1320
1321
1322 /* ======================= Phase 2 of 3 =======================
1323 Wahey! We've finally decided that thread tid is runnable, so
1324 we now do that. Run it for as much of a quanta as possible.
1325 Trivial requests are handled and the thread continues. The
1326 aim is not to do too many of Phase 1 since it is expensive. */
1327
1328 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001329 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001330
njn25e49d8e72002-09-23 09:36:25 +00001331 VG_TRACK( thread_run, tid );
1332
sewardje663cb92002-04-12 10:26:32 +00001333 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1334 that it decrements the counter before testing it for zero, so
1335 that if VG_(dispatch_ctr) is set to N you get at most N-1
1336 iterations. Also this means that VG_(dispatch_ctr) must
1337 exceed zero before entering the innerloop. Also also, the
1338 decrement is done before the bb is actually run, so you
1339 always get at least one decrement even if nothing happens.
1340 */
1341 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1342 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1343 else
1344 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1345
1346 /* ... and remember what we asked for. */
1347 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1348
sewardj1e8cdc92002-04-18 11:37:52 +00001349 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001350 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001351
sewardje663cb92002-04-12 10:26:32 +00001352 /* Actually run thread tid. */
1353 while (True) {
1354
sewardj7e87e382002-05-03 19:09:05 +00001355 VG_(last_run_tid) = tid;
1356
sewardje663cb92002-04-12 10:26:32 +00001357 /* For stats purposes only. */
1358 VG_(num_scheduling_events_MINOR) ++;
1359
1360 if (0)
1361 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1362 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001363# if 0
1364 if (VG_(bbs_done) > 31700000 + 0) {
1365 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001366 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001367 NULL,NULL,NULL);
1368 }
sewardj018f7622002-05-15 21:13:39 +00001369 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001370# endif
sewardje663cb92002-04-12 10:26:32 +00001371
1372 trc = run_thread_for_a_while ( tid );
1373
sewardjb3eef6b2002-05-01 00:05:27 +00001374# if 0
sewardj018f7622002-05-15 21:13:39 +00001375 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001376 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001377 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001378 }
1379# endif
1380
sewardje663cb92002-04-12 10:26:32 +00001381 /* Deal quickly with trivial scheduling events, and resume the
1382 thread. */
1383
1384 if (trc == VG_TRC_INNER_FASTMISS) {
1385 vg_assert(VG_(dispatch_ctr) > 0);
1386
1387 /* Trivial event. Miss in the fast-cache. Do a full
1388 lookup for it. */
1389 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001390 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001391 if (trans_addr == (Addr)0) {
1392 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001393 create_translation_for(
1394 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001395 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001396 if (trans_addr == (Addr)0)
njne427a662002-10-02 11:08:25 +00001397 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
sewardje663cb92002-04-12 10:26:32 +00001398 }
1399 continue; /* with this thread */
1400 }
1401
1402 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001403 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1404 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001405
1406 /* Are we really absolutely totally quitting? */
1407 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1408 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1409 VG_(message)(Vg_DebugMsg,
1410 "__libc_freeres() done; really quitting!");
1411 }
1412 return VgSrc_ExitSyscall;
1413 }
1414
sewardj124ca2a2002-06-20 10:19:38 +00001415 do_client_request(tid);
1416 /* Following the request, we try and continue with the
1417 same thread if still runnable. If not, go back to
1418 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001419 if (VG_(threads)[tid].status == VgTs_Runnable
1420 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001421 continue; /* with this thread */
1422 else
1423 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001424 }
1425
sewardj51c0aaf2002-04-25 01:32:10 +00001426 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1427 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001428 to become non-runnable. One special case: spot the
1429 client doing calls to exit() and take this as the cue
1430 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001431# if 0
1432 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001433 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001434 VG_(printf)("\nBEFORE\n");
1435 for (i = 10; i >= -10; i--)
1436 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1437 }
1438# endif
1439
sewardj1fe7b002002-07-16 01:43:15 +00001440 /* Deal with calling __libc_freeres() at exit. When the
1441 client does __NR_exit, it's exiting for good. So we
1442 then run VG_(__libc_freeres_wrapper). That quits by
1443 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1444 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001445 currently running.
1446
1447 If not valgrinding (cachegrinding, etc) don't do this.
1448 __libc_freeres does some invalid frees which crash
1449 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001450
sewardj858964b2002-10-05 14:15:43 +00001451 if (VG_(threads)[tid].m_eax == __NR_exit) {
1452
1453 /* If __NR_exit, remember the supplied argument. */
njn25e49d8e72002-09-23 09:36:25 +00001454 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1455
sewardj858964b2002-10-05 14:15:43 +00001456 /* Only run __libc_freeres if the skin says it's ok and
1457 it hasn't been overridden with --run-libc-freeres=no
1458 on the command line. */
1459
1460 if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
1461
sewardj00631892002-10-05 15:34:38 +00001462 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001463 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1464 VG_(message)(Vg_DebugMsg,
1465 "Caught __NR_exit; running __libc_freeres()");
1466 }
1467 VG_(nuke_all_threads_except) ( tid );
1468 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1469 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1470 goto stage1; /* party on, dudes (but not for much longer :) */
1471
1472 } else {
1473 /* We won't run __libc_freeres; just exit now. */
sewardj00631892002-10-05 15:34:38 +00001474 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001475 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1476 VG_(message)(Vg_DebugMsg,
1477 "Caught __NR_exit; quitting");
1478 }
1479 return VgSrc_ExitSyscall;
1480 }
1481
sewardjade9d0d2002-07-26 10:52:48 +00001482 }
1483
sewardj858964b2002-10-05 14:15:43 +00001484 /* We've dealt with __NR_exit at this point. */
1485 vg_assert(VG_(threads)[tid].m_eax != __NR_exit);
sewardj7e87e382002-05-03 19:09:05 +00001486
sewardj83798bf2002-05-24 00:11:16 +00001487 /* Trap syscalls to __NR_sched_yield and just have this
1488 thread yield instead. Not essential, just an
1489 optimisation. */
1490 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1491 SET_EAX(tid, 0); /* syscall returns with success */
1492 goto stage1; /* find a new thread to run */
1493 }
1494
sewardj51c0aaf2002-04-25 01:32:10 +00001495 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001496
1497# if 0
1498 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001499 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001500 VG_(printf)("AFTER\n");
1501 for (i = 10; i >= -10; i--)
1502 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1503 }
1504# endif
1505
sewardj77f0fc12002-07-12 01:23:03 +00001506 if (VG_(threads)[tid].status == VgTs_Runnable) {
1507 /* Better do a signal check, since if in a tight loop
1508 with a slow syscall it may be a very long time
1509 before we get back to the main signal check in Stage 1. */
1510 sigs_delivered = VG_(deliver_signals)();
1511 if (sigs_delivered)
1512 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001513 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001514 } else {
1515 goto stage1;
1516 }
sewardj51c0aaf2002-04-25 01:32:10 +00001517 }
1518
sewardjd7fd4d22002-04-24 01:57:27 +00001519 /* It's an event we can't quickly deal with. Give up running
1520 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001521 break;
1522 }
1523
1524 /* ======================= Phase 3 of 3 =======================
1525 Handle non-trivial thread requests, mostly pthread stuff. */
1526
1527 /* Ok, we've fallen out of the dispatcher for a
1528 non-completely-trivial reason. First, update basic-block
1529 counters. */
1530
1531 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1532 vg_assert(done_this_time >= 0);
1533 VG_(bbs_to_go) -= (ULong)done_this_time;
1534 VG_(bbs_done) += (ULong)done_this_time;
1535
1536 if (0 && trc != VG_TRC_INNER_FASTMISS)
1537 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1538 tid, done_this_time, (Int)trc );
1539
1540 if (0 && trc != VG_TRC_INNER_FASTMISS)
1541 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1542 tid, VG_(bbs_done),
1543 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001544
sewardje663cb92002-04-12 10:26:32 +00001545 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001546 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001547
1548 switch (trc) {
1549
sewardje663cb92002-04-12 10:26:32 +00001550 case VG_TRC_INNER_COUNTERZERO:
1551 /* Timeslice is out. Let a new thread be scheduled,
1552 simply by doing nothing, causing us to arrive back at
1553 Phase 1. */
1554 if (VG_(bbs_to_go) == 0) {
1555 goto debug_stop;
1556 }
1557 vg_assert(VG_(dispatch_ctr) == 0);
1558 break;
1559
1560 case VG_TRC_UNRESUMABLE_SIGNAL:
1561 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1562 away. Again, do nothing, so we wind up back at Phase
1563 1, whereupon the signal will be "delivered". */
1564 break;
1565
sewardje663cb92002-04-12 10:26:32 +00001566 default:
1567 VG_(printf)("\ntrc = %d\n", trc);
njne427a662002-10-02 11:08:25 +00001568 VG_(core_panic)("VG_(scheduler), phase 3: "
1569 "unexpected thread return code");
sewardje663cb92002-04-12 10:26:32 +00001570 /* NOTREACHED */
1571 break;
1572
1573 } /* switch (trc) */
1574
1575 /* That completes Phase 3 of 3. Return now to the top of the
1576 main scheduler loop, to Phase 1 of 3. */
1577
1578 } /* top-level scheduler loop */
1579
1580
1581 /* NOTREACHED */
njne427a662002-10-02 11:08:25 +00001582 VG_(core_panic)("scheduler: post-main-loop ?!");
sewardje663cb92002-04-12 10:26:32 +00001583 /* NOTREACHED */
1584
1585 debug_stop:
1586 /* If we exited because of a debug stop, print the translation
1587 of the last block executed -- by translating it again, and
1588 throwing away the result. */
1589 VG_(printf)(
1590 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001591 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +00001592 VG_(threads)[tid].m_eip, NULL, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001593 VG_(printf)("\n");
1594 VG_(printf)(
1595 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1596
1597 return VgSrc_BbsDone;
1598}
1599
1600
1601/* ---------------------------------------------------------------------
1602 The pthread implementation.
1603 ------------------------------------------------------------------ */
1604
1605#include <pthread.h>
1606#include <errno.h>
1607
sewardjbf290b92002-05-01 02:28:01 +00001608#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001609 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001610
1611/* /usr/include/bits/pthreadtypes.h:
1612 typedef unsigned long int pthread_t;
1613*/
1614
sewardje663cb92002-04-12 10:26:32 +00001615
sewardj604ec3c2002-04-18 22:38:41 +00001616/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001617 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001618 -------------------------------------------------------- */
1619
sewardj20917d82002-05-28 01:36:45 +00001620/* We've decided to action a cancellation on tid. Make it jump to
1621 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1622 as the arg. */
1623static
1624void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1625{
1626 Char msg_buf[100];
1627 vg_assert(VG_(is_valid_tid)(tid));
1628 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1629 handler -- which is really thread_exit_wrapper() in
1630 vg_libpthread.c. */
1631 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1632 VG_(threads)[tid].m_esp -= 4;
1633 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1634 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1635 VG_(threads)[tid].status = VgTs_Runnable;
1636 /* Make sure we aren't cancelled again whilst handling this
1637 cancellation. */
1638 VG_(threads)[tid].cancel_st = False;
1639 if (VG_(clo_trace_sched)) {
1640 VG_(sprintf)(msg_buf,
1641 "jump to cancellation handler (hdlr = %p)",
1642 VG_(threads)[tid].cancel_pend);
1643 print_sched_event(tid, msg_buf);
1644 }
1645}
1646
1647
1648
sewardjb48e5002002-05-13 00:16:03 +00001649/* Release resources and generally clean up once a thread has finally
1650 disappeared. */
1651static
1652void cleanup_after_thread_exited ( ThreadId tid )
1653{
sewardj89f20fd2002-06-30 10:57:30 +00001654 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001655 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001656 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1657 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001658 /* Its stack is now off-limits */
1659 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1660 VG_(threads)[tid].stack_size );
1661
sewardjb48e5002002-05-13 00:16:03 +00001662 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001663 thread, and get rid of signal handlers specifically arranged for
1664 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001665 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001666 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001667
1668 /* Clean up the waiting_fd table */
1669 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1670 if (vg_waiting_fds[i].tid == tid) {
1671 vg_waiting_fds[i].fd = -1; /* not in use */
1672 }
1673 }
sewardj92a59562002-09-30 00:53:10 +00001674
1675 /* Deallocate its LDT, if it ever had one. */
1676 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1677 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001678}
1679
1680
sewardj20917d82002-05-28 01:36:45 +00001681/* Look for matching pairs of threads waiting for joiners and threads
1682 waiting for joinees. For each such pair copy the return value of
1683 the joinee into the joiner, let the joiner resume and discard the
1684 joinee. */
1685static
1686void maybe_rendezvous_joiners_and_joinees ( void )
1687{
1688 Char msg_buf[100];
1689 void** thread_return;
1690 ThreadId jnr, jee;
1691
1692 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1693 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1694 continue;
1695 jee = VG_(threads)[jnr].joiner_jee_tid;
1696 if (jee == VG_INVALID_THREADID)
1697 continue;
1698 vg_assert(VG_(is_valid_tid)(jee));
1699 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1700 continue;
1701 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1702 joined by ... well, any thread. So let's do it! */
1703
1704 /* Copy return value to where joiner wants it. */
1705 thread_return = VG_(threads)[jnr].joiner_thread_return;
1706 if (thread_return != NULL) {
1707 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001708 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1709 "pthread_join: thread_return",
1710 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001711
sewardj20917d82002-05-28 01:36:45 +00001712 *thread_return = VG_(threads)[jee].joinee_retval;
1713 /* Not really right, since it makes the thread's return value
1714 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001715 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001716 }
1717
1718 /* Joinee is discarded */
1719 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1720 cleanup_after_thread_exited ( jee );
sewardjc4a810d2002-11-13 22:25:51 +00001721 if (VG_(clo_trace_sched)) {
1722 VG_(sprintf)(msg_buf,
1723 "rendezvous with joinee %d. %d resumes, %d exits.",
1724 jee, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001725 print_sched_event(jnr, msg_buf);
1726 }
sewardjc4a810d2002-11-13 22:25:51 +00001727
1728 VG_TRACK( post_thread_join, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001729
1730 /* joiner returns with success */
1731 VG_(threads)[jnr].status = VgTs_Runnable;
1732 SET_EDX(jnr, 0);
1733 }
1734}
1735
1736
sewardjccef2e62002-05-29 19:26:32 +00001737/* Nuke all threads other than tid. POSIX specifies that this should
1738 happen in __NR_exec, and after a __NR_fork() when I am the child,
1739 as POSIX requires. */
1740void VG_(nuke_all_threads_except) ( ThreadId me )
1741{
1742 ThreadId tid;
1743 for (tid = 1; tid < VG_N_THREADS; tid++) {
1744 if (tid == me
1745 || VG_(threads)[tid].status == VgTs_Empty)
1746 continue;
sewardjef037c72002-05-30 00:40:03 +00001747 if (0)
1748 VG_(printf)(
1749 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001750 VG_(threads)[tid].status = VgTs_Empty;
1751 cleanup_after_thread_exited( tid );
1752 }
1753}
1754
1755
sewardj20917d82002-05-28 01:36:45 +00001756/* -----------------------------------------------------------
1757 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1758 -------------------------------------------------------- */
1759
sewardje663cb92002-04-12 10:26:32 +00001760static
sewardj8ad94e12002-05-29 00:10:20 +00001761void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1762{
1763 Int sp;
1764 Char msg_buf[100];
1765 vg_assert(VG_(is_valid_tid)(tid));
1766 sp = VG_(threads)[tid].custack_used;
1767 if (VG_(clo_trace_sched)) {
1768 VG_(sprintf)(msg_buf,
1769 "cleanup_push (fn %p, arg %p) -> slot %d",
1770 cu->fn, cu->arg, sp);
1771 print_sched_event(tid, msg_buf);
1772 }
1773 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1774 if (sp == VG_N_CLEANUPSTACK)
njne427a662002-10-02 11:08:25 +00001775 VG_(core_panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
sewardj8ad94e12002-05-29 00:10:20 +00001776 " Increase and recompile.");
1777 VG_(threads)[tid].custack[sp] = *cu;
1778 sp++;
1779 VG_(threads)[tid].custack_used = sp;
1780 SET_EDX(tid, 0);
1781}
1782
1783
1784static
1785void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1786{
1787 Int sp;
1788 Char msg_buf[100];
1789 vg_assert(VG_(is_valid_tid)(tid));
1790 sp = VG_(threads)[tid].custack_used;
1791 if (VG_(clo_trace_sched)) {
njn36650922002-10-04 09:18:09 +00001792 VG_(sprintf)(msg_buf, "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001793 print_sched_event(tid, msg_buf);
1794 }
1795 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1796 if (sp == 0) {
1797 SET_EDX(tid, -1);
1798 return;
1799 }
1800 sp--;
njn36650922002-10-04 09:18:09 +00001801 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
1802 "cleanup pop", (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001803 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001804 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001805 VG_(threads)[tid].custack_used = sp;
1806 SET_EDX(tid, 0);
1807}
1808
1809
1810static
sewardjff42d1d2002-05-22 13:17:31 +00001811void do_pthread_yield ( ThreadId tid )
1812{
1813 Char msg_buf[100];
1814 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001815 if (VG_(clo_trace_sched)) {
1816 VG_(sprintf)(msg_buf, "yield");
1817 print_sched_event(tid, msg_buf);
1818 }
1819 SET_EDX(tid, 0);
1820}
1821
1822
1823static
sewardj20917d82002-05-28 01:36:45 +00001824void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001825{
sewardj7989d0c2002-05-28 11:00:01 +00001826 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001827 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001828 if (VG_(clo_trace_sched)) {
1829 VG_(sprintf)(msg_buf, "testcancel");
1830 print_sched_event(tid, msg_buf);
1831 }
sewardj20917d82002-05-28 01:36:45 +00001832 if (/* is there a cancellation pending on this thread? */
1833 VG_(threads)[tid].cancel_pend != NULL
1834 && /* is this thread accepting cancellations? */
1835 VG_(threads)[tid].cancel_st) {
1836 /* Ok, let's do the cancellation. */
1837 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001838 } else {
sewardj20917d82002-05-28 01:36:45 +00001839 /* No, we keep going. */
1840 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001841 }
sewardje663cb92002-04-12 10:26:32 +00001842}
1843
1844
1845static
sewardj20917d82002-05-28 01:36:45 +00001846void do__set_cancelstate ( ThreadId tid, Int state )
1847{
1848 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001849 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001850 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001851 if (VG_(clo_trace_sched)) {
1852 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1853 state==PTHREAD_CANCEL_ENABLE
1854 ? "ENABLE"
1855 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1856 print_sched_event(tid, msg_buf);
1857 }
sewardj20917d82002-05-28 01:36:45 +00001858 old_st = VG_(threads)[tid].cancel_st;
1859 if (state == PTHREAD_CANCEL_ENABLE) {
1860 VG_(threads)[tid].cancel_st = True;
1861 } else
1862 if (state == PTHREAD_CANCEL_DISABLE) {
1863 VG_(threads)[tid].cancel_st = False;
1864 } else {
njne427a662002-10-02 11:08:25 +00001865 VG_(core_panic)("do__set_cancelstate");
sewardj20917d82002-05-28 01:36:45 +00001866 }
1867 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1868 : PTHREAD_CANCEL_DISABLE);
1869}
1870
1871
1872static
1873void do__set_canceltype ( ThreadId tid, Int type )
1874{
1875 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001876 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001877 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001878 if (VG_(clo_trace_sched)) {
1879 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1880 type==PTHREAD_CANCEL_ASYNCHRONOUS
1881 ? "ASYNCHRONOUS"
1882 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1883 print_sched_event(tid, msg_buf);
1884 }
sewardj20917d82002-05-28 01:36:45 +00001885 old_ty = VG_(threads)[tid].cancel_ty;
1886 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1887 VG_(threads)[tid].cancel_ty = False;
1888 } else
1889 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001890 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001891 } else {
njne427a662002-10-02 11:08:25 +00001892 VG_(core_panic)("do__set_canceltype");
sewardj20917d82002-05-28 01:36:45 +00001893 }
1894 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1895 : PTHREAD_CANCEL_ASYNCHRONOUS);
1896}
1897
1898
sewardj7989d0c2002-05-28 11:00:01 +00001899/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001900static
sewardj7989d0c2002-05-28 11:00:01 +00001901void do__set_or_get_detach ( ThreadId tid,
1902 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001903{
sewardj7989d0c2002-05-28 11:00:01 +00001904 ThreadId i;
1905 Char msg_buf[100];
1906 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1907 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001908 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001909 if (VG_(clo_trace_sched)) {
1910 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1911 what==0 ? "not-detached" : (
1912 what==1 ? "detached" : (
1913 what==2 ? "fetch old value" : "???")),
1914 det );
1915 print_sched_event(tid, msg_buf);
1916 }
1917
1918 if (!VG_(is_valid_tid)(det)) {
1919 SET_EDX(tid, -1);
1920 return;
1921 }
1922
sewardj20917d82002-05-28 01:36:45 +00001923 switch (what) {
1924 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001925 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001926 return;
sewardj7989d0c2002-05-28 11:00:01 +00001927 case 1: /* set detached. If someone is in a join-wait for det,
1928 do not detach. */
1929 for (i = 1; i < VG_N_THREADS; i++) {
1930 if (VG_(threads)[i].status == VgTs_WaitJoinee
1931 && VG_(threads)[i].joiner_jee_tid == det) {
1932 SET_EDX(tid, 0);
1933 if (VG_(clo_trace_sched)) {
1934 VG_(sprintf)(msg_buf,
njn9b6d34e2002-10-15 08:48:08 +00001935 "tid %d not detached because %d in join-wait for it",
sewardj7989d0c2002-05-28 11:00:01 +00001936 det, i);
1937 print_sched_event(tid, msg_buf);
1938 }
1939 return;
1940 }
1941 }
1942 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001943 SET_EDX(tid, 0);
1944 return;
1945 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001946 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001947 SET_EDX(tid, 0);
1948 return;
1949 default:
njne427a662002-10-02 11:08:25 +00001950 VG_(core_panic)("do__set_or_get_detach");
sewardj20917d82002-05-28 01:36:45 +00001951 }
1952}
1953
1954
1955static
1956void do__set_cancelpend ( ThreadId tid,
1957 ThreadId cee,
1958 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001959{
1960 Char msg_buf[100];
1961
sewardj20917d82002-05-28 01:36:45 +00001962 vg_assert(VG_(is_valid_tid)(tid));
1963 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1964
sewardj7989d0c2002-05-28 11:00:01 +00001965 if (!VG_(is_valid_tid)(cee)) {
1966 if (VG_(clo_trace_sched)) {
1967 VG_(sprintf)(msg_buf,
1968 "set_cancelpend for invalid tid %d", cee);
1969 print_sched_event(tid, msg_buf);
1970 }
njn25e49d8e72002-09-23 09:36:25 +00001971 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00001972 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00001973 SET_EDX(tid, -VKI_ESRCH);
1974 return;
1975 }
sewardj20917d82002-05-28 01:36:45 +00001976
1977 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
1978
1979 if (VG_(clo_trace_sched)) {
1980 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001981 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00001982 cancelpend_hdlr, tid);
1983 print_sched_event(cee, msg_buf);
1984 }
1985
1986 /* Thread doing the cancelling returns with success. */
1987 SET_EDX(tid, 0);
1988
1989 /* Perhaps we can nuke the cancellee right now? */
1990 do__testcancel(cee);
1991}
1992
1993
1994static
1995void do_pthread_join ( ThreadId tid,
1996 ThreadId jee, void** thread_return )
1997{
1998 Char msg_buf[100];
1999 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00002000 /* jee, the joinee, is the thread specified as an arg in thread
2001 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00002002 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00002003 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002004
2005 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002006 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002007 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002008 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002009 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002010 return;
2011 }
2012
sewardj20917d82002-05-28 01:36:45 +00002013 /* Flush any completed pairs, so as to make sure what we're looking
2014 at is up-to-date. */
2015 maybe_rendezvous_joiners_and_joinees();
2016
2017 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002018 if (jee < 0
2019 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002020 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002021 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002022 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002023 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002024 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002025 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002026 return;
2027 }
2028
sewardj20917d82002-05-28 01:36:45 +00002029 /* Is anyone else already in a join-wait for jee? */
2030 for (i = 1; i < VG_N_THREADS; i++) {
2031 if (i == tid) continue;
2032 if (VG_(threads)[i].status == VgTs_WaitJoinee
2033 && VG_(threads)[i].joiner_jee_tid == jee) {
2034 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002035 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002036 "pthread_join: another thread already "
2037 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002038 SET_EDX(tid, EINVAL);
2039 VG_(threads)[tid].status = VgTs_Runnable;
2040 return;
2041 }
sewardje663cb92002-04-12 10:26:32 +00002042 }
2043
sewardj20917d82002-05-28 01:36:45 +00002044 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002045 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002046 VG_(threads)[tid].joiner_thread_return = thread_return;
2047 VG_(threads)[tid].joiner_jee_tid = jee;
2048
2049 /* Look for matching joiners and joinees and do the right thing. */
2050 maybe_rendezvous_joiners_and_joinees();
2051
2052 /* Return value is irrelevant since this this thread becomes
2053 non-runnable. maybe_resume_joiner() will cause it to return the
2054 right value when it resumes. */
2055
sewardj8937c812002-04-12 20:12:20 +00002056 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002057 VG_(sprintf)(msg_buf,
2058 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002059 print_sched_event(tid, msg_buf);
2060 }
sewardje663cb92002-04-12 10:26:32 +00002061}
2062
2063
sewardj20917d82002-05-28 01:36:45 +00002064/* ( void* ): calling thread waits for joiner and returns the void* to
2065 it. This is one of two ways in which a thread can finally exit --
2066 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002067static
sewardj20917d82002-05-28 01:36:45 +00002068void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002069{
sewardj20917d82002-05-28 01:36:45 +00002070 Char msg_buf[100];
2071 vg_assert(VG_(is_valid_tid)(tid));
2072 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2073 if (VG_(clo_trace_sched)) {
2074 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002075 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002076 print_sched_event(tid, msg_buf);
2077 }
2078 VG_(threads)[tid].status = VgTs_WaitJoiner;
2079 VG_(threads)[tid].joinee_retval = retval;
2080 maybe_rendezvous_joiners_and_joinees();
2081}
2082
2083
2084/* ( no-args ): calling thread disappears from the system forever.
2085 Reclaim resources. */
2086static
2087void do__quit ( ThreadId tid )
2088{
2089 Char msg_buf[100];
2090 vg_assert(VG_(is_valid_tid)(tid));
2091 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2092 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2093 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002094 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002095 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002096 print_sched_event(tid, msg_buf);
2097 }
2098 /* Return value is irrelevant; this thread will not get
2099 rescheduled. */
2100}
2101
2102
2103/* Should never be entered. If it is, will be on the simulated
2104 CPU. */
2105static
2106void do__apply_in_new_thread_bogusRA ( void )
2107{
njne427a662002-10-02 11:08:25 +00002108 VG_(core_panic)("do__apply_in_new_thread_bogusRA");
sewardj20917d82002-05-28 01:36:45 +00002109}
2110
2111/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2112 MUST NOT return -- ever. Eventually it will do either __QUIT or
2113 __WAIT_JOINER. Return the child tid to the parent. */
2114static
2115void do__apply_in_new_thread ( ThreadId parent_tid,
2116 void* (*fn)(void *),
2117 void* arg )
2118{
sewardje663cb92002-04-12 10:26:32 +00002119 Addr new_stack;
2120 UInt new_stk_szb;
2121 ThreadId tid;
2122 Char msg_buf[100];
2123
2124 /* Paranoia ... */
2125 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2126
sewardj018f7622002-05-15 21:13:39 +00002127 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002128
sewardj1e8cdc92002-04-18 11:37:52 +00002129 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002130
2131 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002132 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002133 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002134
sewardjc4a810d2002-11-13 22:25:51 +00002135 /* do this early, before the child gets any memory writes */
2136 VG_TRACK ( post_thread_create, parent_tid, tid );
2137
sewardjf6374322002-11-13 22:35:55 +00002138 /* Create new thread with default attrs:
2139 deferred cancellation, not detached
2140 */
2141 mostly_clear_thread_record(tid);
2142 VG_(threads)[tid].status = VgTs_Runnable;
2143
sewardje663cb92002-04-12 10:26:32 +00002144 /* Copy the parent's CPU state into the child's, in a roundabout
2145 way (via baseBlock). */
2146 VG_(load_thread_state)(parent_tid);
sewardjca340b32002-12-08 22:14:11 +00002147
2148 /* We inherit our parent's LDT. */
2149 if (VG_(threads)[parent_tid].ldt == NULL) {
2150 /* We hope this is the common case. */
2151 VG_(baseBlock)[VGOFF_(ldt)] = 0;
2152 } else {
2153 /* No luck .. we have to take a copy of the parent's. */
2154 VG_(threads)[tid].ldt
2155 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2156 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
2157 }
2158
sewardje663cb92002-04-12 10:26:32 +00002159 VG_(save_thread_state)(tid);
sewardjf6374322002-11-13 22:35:55 +00002160 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +00002161
2162 /* Consider allocating the child a stack, if the one it already has
2163 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002164 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002165
sewardj018f7622002-05-15 21:13:39 +00002166 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002167 /* Again, for good measure :) We definitely don't want to be
2168 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002169 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002170 /* for now, we don't handle the case of anything other than
2171 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002172 vg_assert(VG_(threads)[tid].stack_size == 0);
2173 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002174 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2175 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002176 VG_(threads)[tid].stack_base = new_stack;
2177 VG_(threads)[tid].stack_size = new_stk_szb;
2178 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002179 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002180 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002181 }
sewardj1e8cdc92002-04-18 11:37:52 +00002182
njn25e49d8e72002-09-23 09:36:25 +00002183 /* Having got memory to hold the thread's stack:
2184 - set %esp as base + size
2185 - mark everything below %esp inaccessible
2186 - mark redzone at stack end inaccessible
2187 */
2188 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2189 + VG_(threads)[tid].stack_size
2190 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002191
njn25e49d8e72002-09-23 09:36:25 +00002192 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2193 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2194 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2195 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002196
njn25e49d8e72002-09-23 09:36:25 +00002197 /* push two args */
2198 VG_(threads)[tid].m_esp -= 8;
2199 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2200 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2201 "new thread: stack",
2202 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2203
2204 /* push arg and (bogus) return address */
2205 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002206 * (UInt*)(VG_(threads)[tid].m_esp)
2207 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002208
njn25e49d8e72002-09-23 09:36:25 +00002209 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002210
2211 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002212 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002213
sewardj8937c812002-04-12 20:12:20 +00002214 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002215 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002216 print_sched_event(tid, msg_buf);
2217 }
2218
sewardj018f7622002-05-15 21:13:39 +00002219 /* We inherit our parent's signal mask. */
2220 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002221 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002222
sewardj20917d82002-05-28 01:36:45 +00002223 /* return child's tid to parent */
2224 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002225}
2226
2227
sewardj604ec3c2002-04-18 22:38:41 +00002228/* -----------------------------------------------------------
2229 MUTEXes
2230 -------------------------------------------------------- */
2231
sewardj604ec3c2002-04-18 22:38:41 +00002232/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002233 typedef struct
2234 {
2235 int __m_reserved; -- Reserved for future use
2236 int __m_count; -- Depth of recursive locking
2237 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2238 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2239 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2240 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002241
sewardj6072c362002-04-19 14:40:57 +00002242 #define PTHREAD_MUTEX_INITIALIZER \
2243 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2244 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2245 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2246 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2247 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2248 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2249 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002250
sewardj6072c362002-04-19 14:40:57 +00002251 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002252
sewardj6072c362002-04-19 14:40:57 +00002253 __m_kind never changes and indicates whether or not it is recursive.
2254
2255 __m_count indicates the lock count; if 0, the mutex is not owned by
2256 anybody.
2257
2258 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2259 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2260 statically initialised mutexes correctly appear
2261 to belong to nobody.
2262
2263 In summary, a not-in-use mutex is distinguised by having __m_owner
2264 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2265 conditions holds, the other should too.
2266
2267 There is no linked list of threads waiting for this mutex. Instead
2268 a thread in WaitMX state points at the mutex with its waited_on_mx
2269 field. This makes _unlock() inefficient, but simple to implement the
2270 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002271
sewardj604ec3c2002-04-18 22:38:41 +00002272 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002273 deals with that for us.
2274*/
sewardje663cb92002-04-12 10:26:32 +00002275
sewardj3b5d8862002-04-20 13:53:23 +00002276/* Helper fns ... */
2277static
2278void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2279 Char* caller )
2280{
2281 Int i;
2282 Char msg_buf[100];
2283
2284 /* Find some arbitrary thread waiting on this mutex, and make it
2285 runnable. If none are waiting, mark the mutex as not held. */
2286 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002287 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002288 continue;
sewardj018f7622002-05-15 21:13:39 +00002289 if (VG_(threads)[i].status == VgTs_WaitMX
2290 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002291 break;
2292 }
2293
sewardj0af43bc2002-10-22 04:30:35 +00002294 VG_TRACK( post_mutex_unlock, (ThreadId)mutex->__m_owner, mutex );
2295
sewardj3b5d8862002-04-20 13:53:23 +00002296 vg_assert(i <= VG_N_THREADS);
2297 if (i == VG_N_THREADS) {
2298 /* Nobody else is waiting on it. */
2299 mutex->__m_count = 0;
2300 mutex->__m_owner = VG_INVALID_THREADID;
2301 } else {
2302 /* Notionally transfer the hold to thread i, whose
2303 pthread_mutex_lock() call now returns with 0 (success). */
2304 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002305 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002306 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002307 VG_(threads)[i].status = VgTs_Runnable;
2308 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002309 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002310
sewardj0af43bc2002-10-22 04:30:35 +00002311 VG_TRACK( post_mutex_lock, (ThreadId)i, mutex);
2312
sewardj3b5d8862002-04-20 13:53:23 +00002313 if (VG_(clo_trace_pthread_level) >= 1) {
2314 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2315 caller, mutex );
2316 print_pthread_event(i, msg_buf);
2317 }
2318 }
2319}
2320
sewardje663cb92002-04-12 10:26:32 +00002321
2322static
sewardj30671ff2002-04-21 00:13:57 +00002323void do_pthread_mutex_lock( ThreadId tid,
2324 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002325 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002326{
sewardj30671ff2002-04-21 00:13:57 +00002327 Char msg_buf[100];
2328 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002329 = is_trylock ? "pthread_mutex_trylock"
2330 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002331
sewardj604ec3c2002-04-18 22:38:41 +00002332 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002333 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002334 print_pthread_event(tid, msg_buf);
2335 }
2336
2337 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002338 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002339 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002340
2341 /* POSIX doesn't mandate this, but for sanity ... */
2342 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002343 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002344 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002345 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002346 return;
2347 }
2348
sewardj604ec3c2002-04-18 22:38:41 +00002349 /* More paranoia ... */
2350 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002351# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002352 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002353 case PTHREAD_MUTEX_ADAPTIVE_NP:
2354# endif
sewardja1679dd2002-05-10 22:31:40 +00002355# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002356 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002357# endif
sewardj604ec3c2002-04-18 22:38:41 +00002358 case PTHREAD_MUTEX_RECURSIVE_NP:
2359 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002360 if (mutex->__m_count >= 0) break;
2361 /* else fall thru */
2362 default:
njn25e49d8e72002-09-23 09:36:25 +00002363 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002364 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002365 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002366 return;
sewardje663cb92002-04-12 10:26:32 +00002367 }
2368
sewardj604ec3c2002-04-18 22:38:41 +00002369 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002370
sewardjb48e5002002-05-13 00:16:03 +00002371 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002372
2373 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002374 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002375 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002376 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002377 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002378 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002379 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002380 if (0)
2381 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2382 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002383 return;
2384 } else {
sewardj30671ff2002-04-21 00:13:57 +00002385 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002386 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002387 else
sewardjc3bd5f52002-05-01 03:24:23 +00002388 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002389 return;
2390 }
2391 } else {
sewardj6072c362002-04-19 14:40:57 +00002392 /* Someone else has it; we have to wait. Mark ourselves
2393 thusly. */
sewardj05553872002-04-20 20:53:17 +00002394 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002395 if (is_trylock) {
2396 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002397 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002398 } else {
sewardjdca84112002-11-13 22:29:34 +00002399 VG_TRACK ( pre_mutex_lock, tid, mutex );
2400
sewardj018f7622002-05-15 21:13:39 +00002401 VG_(threads)[tid].status = VgTs_WaitMX;
2402 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002403 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002404 if (VG_(clo_trace_pthread_level) >= 1) {
2405 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2406 caller, mutex );
2407 print_pthread_event(tid, msg_buf);
2408 }
2409 }
sewardje663cb92002-04-12 10:26:32 +00002410 return;
2411 }
sewardjf8f819e2002-04-17 23:21:37 +00002412
sewardje663cb92002-04-12 10:26:32 +00002413 } else {
sewardj6072c362002-04-19 14:40:57 +00002414 /* Nobody owns it. Sanity check ... */
2415 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjdca84112002-11-13 22:29:34 +00002416
2417 VG_TRACK ( pre_mutex_lock, tid, mutex );
2418
sewardjf8f819e2002-04-17 23:21:37 +00002419 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002420 mutex->__m_count = 1;
2421 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002422
2423 VG_TRACK( post_mutex_lock, tid, mutex);
2424
sewardje663cb92002-04-12 10:26:32 +00002425 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002426 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002427 }
sewardjf8f819e2002-04-17 23:21:37 +00002428
sewardje663cb92002-04-12 10:26:32 +00002429}
2430
2431
2432static
2433void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002434 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002435{
sewardj3b5d8862002-04-20 13:53:23 +00002436 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002437
sewardj45b4b372002-04-16 22:50:32 +00002438 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002439 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002440 print_pthread_event(tid, msg_buf);
2441 }
2442
sewardj604ec3c2002-04-18 22:38:41 +00002443 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002444 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002445 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002446
2447 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002448 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002449 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002450 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002451 return;
2452 }
2453
sewardjd8acdf22002-11-13 21:57:52 +00002454 /* If this was locked before the dawn of time, pretend it was
2455 locked now so that it balances with unlocks */
2456 if (mutex->__m_kind & VG_PTHREAD_PREHISTORY) {
2457 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
sewardjdca84112002-11-13 22:29:34 +00002458 VG_TRACK( pre_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
sewardjd8acdf22002-11-13 21:57:52 +00002459 VG_TRACK( post_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
2460 }
2461
sewardj604ec3c2002-04-18 22:38:41 +00002462 /* More paranoia ... */
2463 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002464# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002465 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002466 case PTHREAD_MUTEX_ADAPTIVE_NP:
2467# endif
sewardja1679dd2002-05-10 22:31:40 +00002468# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002469 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002470# endif
sewardj604ec3c2002-04-18 22:38:41 +00002471 case PTHREAD_MUTEX_RECURSIVE_NP:
2472 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002473 if (mutex->__m_count >= 0) break;
2474 /* else fall thru */
2475 default:
njn25e49d8e72002-09-23 09:36:25 +00002476 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002477 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002478 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002479 return;
2480 }
sewardje663cb92002-04-12 10:26:32 +00002481
2482 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002483 if (mutex->__m_count == 0) {
2484 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002485 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002486 "pthread_mutex_unlock: mutex is not locked");
2487 SET_EDX(tid, EPERM);
2488 return;
2489 }
2490
2491 if ((ThreadId)mutex->__m_owner != tid) {
2492 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002493 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002494 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002495 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002496 return;
2497 }
2498
sewardjf8f819e2002-04-17 23:21:37 +00002499 /* If it's a multiply-locked recursive mutex, just decrement the
2500 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002501 if (mutex->__m_count > 1) {
2502 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2503 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002504 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002505 return;
2506 }
2507
sewardj604ec3c2002-04-18 22:38:41 +00002508 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002509 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002510 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002511 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002512
sewardj3b5d8862002-04-20 13:53:23 +00002513 /* Release at max one thread waiting on this mutex. */
2514 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002515
sewardj3b5d8862002-04-20 13:53:23 +00002516 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002517 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002518}
2519
2520
sewardj6072c362002-04-19 14:40:57 +00002521/* -----------------------------------------------------------
2522 CONDITION VARIABLES
2523 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002524
sewardj6072c362002-04-19 14:40:57 +00002525/* The relevant native types are as follows:
2526 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002527
sewardj6072c362002-04-19 14:40:57 +00002528 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2529 typedef struct
2530 {
2531 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2532 _pthread_descr __c_waiting; -- Threads waiting on this condition
2533 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002534
sewardj6072c362002-04-19 14:40:57 +00002535 -- Attribute for conditionally variables.
2536 typedef struct
2537 {
2538 int __dummy;
2539 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002540
sewardj6072c362002-04-19 14:40:57 +00002541 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002542
sewardj3b5d8862002-04-20 13:53:23 +00002543 We don't use any fields of pthread_cond_t for anything at all.
2544 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002545
2546 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002547 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002548
sewardj77e466c2002-04-14 02:29:29 +00002549
sewardj5f07b662002-04-23 16:52:51 +00002550static
2551void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2552{
2553 Char msg_buf[100];
2554 pthread_mutex_t* mx;
2555 pthread_cond_t* cv;
2556
sewardjb48e5002002-05-13 00:16:03 +00002557 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002558 && VG_(threads)[tid].status == VgTs_WaitCV
2559 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2560 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002561 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002562 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002563 vg_assert(cv != NULL);
2564
2565 if (mx->__m_owner == VG_INVALID_THREADID) {
2566 /* Currently unheld; hand it out to thread tid. */
2567 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002568 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002569 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002570 VG_(threads)[tid].associated_cv = NULL;
2571 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002572 mx->__m_owner = (_pthread_descr)tid;
2573 mx->__m_count = 1;
2574
sewardj0af43bc2002-10-22 04:30:35 +00002575 VG_TRACK( post_mutex_lock, tid, mx );
2576
sewardj5f07b662002-04-23 16:52:51 +00002577 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002578 VG_(sprintf)(msg_buf,
2579 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2580 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002581 print_pthread_event(tid, msg_buf);
2582 }
2583 } else {
2584 /* Currently held. Make thread tid be blocked on it. */
2585 vg_assert(mx->__m_count > 0);
sewardjdca84112002-11-13 22:29:34 +00002586 VG_TRACK( pre_mutex_lock, tid, mx );
2587
sewardj018f7622002-05-15 21:13:39 +00002588 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002589 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002590 VG_(threads)[tid].associated_cv = NULL;
2591 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002592 if (VG_(clo_trace_pthread_level) >= 1) {
2593 VG_(sprintf)(msg_buf,
2594 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2595 cv, mx );
2596 print_pthread_event(tid, msg_buf);
2597 }
2598
2599 }
2600}
2601
2602
sewardj3b5d8862002-04-20 13:53:23 +00002603static
2604void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2605 Int n_to_release,
2606 Char* caller )
2607{
2608 Int i;
2609 Char msg_buf[100];
2610 pthread_mutex_t* mx;
2611
2612 while (True) {
2613 if (n_to_release == 0)
2614 return;
2615
2616 /* Find a thread waiting on this CV. */
2617 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002618 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002619 continue;
sewardj018f7622002-05-15 21:13:39 +00002620 if (VG_(threads)[i].status == VgTs_WaitCV
2621 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002622 break;
2623 }
2624 vg_assert(i <= VG_N_THREADS);
2625
2626 if (i == VG_N_THREADS) {
2627 /* Nobody else is waiting on it. */
2628 return;
2629 }
2630
sewardj018f7622002-05-15 21:13:39 +00002631 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002632 vg_assert(mx != NULL);
2633
sewardjdca84112002-11-13 22:29:34 +00002634 VG_TRACK( pre_mutex_lock, i, mx );
2635
sewardj3b5d8862002-04-20 13:53:23 +00002636 if (mx->__m_owner == VG_INVALID_THREADID) {
2637 /* Currently unheld; hand it out to thread i. */
2638 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002639 VG_(threads)[i].status = VgTs_Runnable;
2640 VG_(threads)[i].associated_cv = NULL;
2641 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002642 mx->__m_owner = (_pthread_descr)i;
2643 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002644 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002645
sewardj0af43bc2002-10-22 04:30:35 +00002646 VG_TRACK( post_mutex_lock, i, mx );
2647
sewardj3b5d8862002-04-20 13:53:23 +00002648 if (VG_(clo_trace_pthread_level) >= 1) {
2649 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2650 caller, cond, mx );
2651 print_pthread_event(i, msg_buf);
2652 }
2653
2654 } else {
2655 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002656 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002657 VG_(threads)[i].status = VgTs_WaitMX;
2658 VG_(threads)[i].associated_cv = NULL;
2659 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002660 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002661
2662 if (VG_(clo_trace_pthread_level) >= 1) {
2663 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2664 caller, cond, mx );
2665 print_pthread_event(i, msg_buf);
2666 }
2667
2668 }
2669
2670 n_to_release--;
2671 }
2672}
2673
2674
2675static
2676void do_pthread_cond_wait ( ThreadId tid,
2677 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002678 pthread_mutex_t *mutex,
2679 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002680{
2681 Char msg_buf[100];
2682
sewardj5f07b662002-04-23 16:52:51 +00002683 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2684 ms_end is the ending millisecond. */
2685
sewardj3b5d8862002-04-20 13:53:23 +00002686 /* pre: mutex should be a valid mutex and owned by tid. */
2687 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002688 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2689 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002690 print_pthread_event(tid, msg_buf);
2691 }
2692
2693 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002694 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002695 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002696
2697 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002698 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002699 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002700 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002701 return;
2702 }
2703
2704 /* More paranoia ... */
2705 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002706# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002707 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002708 case PTHREAD_MUTEX_ADAPTIVE_NP:
2709# endif
sewardja1679dd2002-05-10 22:31:40 +00002710# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002711 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002712# endif
sewardj3b5d8862002-04-20 13:53:23 +00002713 case PTHREAD_MUTEX_RECURSIVE_NP:
2714 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002715 if (mutex->__m_count >= 0) break;
2716 /* else fall thru */
2717 default:
njn25e49d8e72002-09-23 09:36:25 +00002718 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002719 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002720 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002721 return;
2722 }
2723
2724 /* Barf if we don't currently hold the mutex. */
2725 if (mutex->__m_count == 0 /* nobody holds it */
2726 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002727 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002728 "pthread_cond_wait/timedwait: mutex is unlocked "
2729 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002730 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002731 return;
2732 }
2733
2734 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002735 VG_(threads)[tid].status = VgTs_WaitCV;
2736 VG_(threads)[tid].associated_cv = cond;
2737 VG_(threads)[tid].associated_mx = mutex;
2738 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002739
2740 if (VG_(clo_trace_pthread_level) >= 1) {
2741 VG_(sprintf)(msg_buf,
2742 "pthread_cond_wait cv %p, mx %p: BLOCK",
2743 cond, mutex );
2744 print_pthread_event(tid, msg_buf);
2745 }
2746
2747 /* Release the mutex. */
2748 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2749}
2750
2751
2752static
2753void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2754 Bool broadcast,
2755 pthread_cond_t *cond )
2756{
2757 Char msg_buf[100];
2758 Char* caller
2759 = broadcast ? "pthread_cond_broadcast"
2760 : "pthread_cond_signal ";
2761
2762 if (VG_(clo_trace_pthread_level) >= 2) {
2763 VG_(sprintf)(msg_buf, "%s cv %p ...",
2764 caller, cond );
2765 print_pthread_event(tid, msg_buf);
2766 }
2767
2768 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002769 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002770 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002771
2772 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002773 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002774 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002775 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002776 return;
2777 }
2778
2779 release_N_threads_waiting_on_cond (
2780 cond,
2781 broadcast ? VG_N_THREADS : 1,
2782 caller
2783 );
2784
sewardjc3bd5f52002-05-01 03:24:23 +00002785 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002786}
2787
sewardj77e466c2002-04-14 02:29:29 +00002788
sewardj5f07b662002-04-23 16:52:51 +00002789/* -----------------------------------------------------------
2790 THREAD SPECIFIC DATA
2791 -------------------------------------------------------- */
2792
2793static __inline__
2794Bool is_valid_key ( ThreadKey k )
2795{
2796 /* k unsigned; hence no < 0 check */
2797 if (k >= VG_N_THREAD_KEYS) return False;
2798 if (!vg_thread_keys[k].inuse) return False;
2799 return True;
2800}
2801
sewardj00a66b12002-10-12 16:42:35 +00002802
2803/* Return in %EDX a value of 1 if the key is valid, else 0. */
2804static
2805void do_pthread_key_validate ( ThreadId tid,
2806 pthread_key_t key )
2807{
2808 Char msg_buf[100];
2809
2810 if (VG_(clo_trace_pthread_level) >= 1) {
2811 VG_(sprintf)(msg_buf, "pthread_key_validate key %p",
2812 key );
2813 print_pthread_event(tid, msg_buf);
2814 }
2815
2816 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
2817 vg_assert(VG_(is_valid_tid)(tid)
2818 && VG_(threads)[tid].status == VgTs_Runnable);
2819
2820 if (is_valid_key((ThreadKey)key)) {
2821 SET_EDX(tid, 1);
2822 } else {
2823 SET_EDX(tid, 0);
2824 }
2825}
2826
2827
sewardj5f07b662002-04-23 16:52:51 +00002828static
2829void do_pthread_key_create ( ThreadId tid,
2830 pthread_key_t* key,
2831 void (*destructor)(void*) )
2832{
2833 Int i;
2834 Char msg_buf[100];
2835
2836 if (VG_(clo_trace_pthread_level) >= 1) {
2837 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2838 key, destructor );
2839 print_pthread_event(tid, msg_buf);
2840 }
2841
2842 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002843 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002844 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002845
2846 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2847 if (!vg_thread_keys[i].inuse)
2848 break;
2849
2850 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002851 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002852 return;
2853 */
njne427a662002-10-02 11:08:25 +00002854 VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2855 " increase and recompile");
sewardj5f07b662002-04-23 16:52:51 +00002856 }
2857
sewardj870497a2002-05-29 01:06:47 +00002858 vg_thread_keys[i].inuse = True;
2859 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002860
sewardj5a3798b2002-06-04 23:24:22 +00002861 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002862 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2863 "pthread_key_create: key",
2864 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002865 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002866 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002867
2868 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002869}
2870
2871
2872static
2873void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2874{
2875 Char msg_buf[100];
2876 if (VG_(clo_trace_pthread_level) >= 1) {
2877 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2878 key );
2879 print_pthread_event(tid, msg_buf);
2880 }
2881
sewardjb48e5002002-05-13 00:16:03 +00002882 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002883 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002884
2885 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002886 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002887 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002888 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002889 return;
2890 }
2891
2892 vg_thread_keys[key].inuse = False;
sewardj00a66b12002-10-12 16:42:35 +00002893 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002894}
2895
2896
sewardj00a66b12002-10-12 16:42:35 +00002897/* Get the .specific_ptr for a thread. Return 1 if the thread-slot
2898 isn't in use, so that client-space can scan all thread slots. 1
2899 cannot be confused with NULL or a legitimately-aligned specific_ptr
2900 value. */
sewardj5f07b662002-04-23 16:52:51 +00002901static
sewardj00a66b12002-10-12 16:42:35 +00002902void do_pthread_getspecific_ptr ( ThreadId tid )
sewardj5f07b662002-04-23 16:52:51 +00002903{
sewardj00a66b12002-10-12 16:42:35 +00002904 void** specifics_ptr;
2905 Char msg_buf[100];
2906
sewardj5f07b662002-04-23 16:52:51 +00002907 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002908 VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
sewardj5f07b662002-04-23 16:52:51 +00002909 print_pthread_event(tid, msg_buf);
2910 }
2911
sewardj00a66b12002-10-12 16:42:35 +00002912 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardj5f07b662002-04-23 16:52:51 +00002913
sewardj00a66b12002-10-12 16:42:35 +00002914 if (VG_(threads)[tid].status == VgTs_Empty) {
2915 SET_EDX(tid, 1);
sewardj5f07b662002-04-23 16:52:51 +00002916 return;
2917 }
2918
sewardj00a66b12002-10-12 16:42:35 +00002919 specifics_ptr = VG_(threads)[tid].specifics_ptr;
2920 vg_assert(specifics_ptr == NULL
2921 || IS_ALIGNED4_ADDR(specifics_ptr));
2922
2923 SET_EDX(tid, (UInt)specifics_ptr);
sewardj5f07b662002-04-23 16:52:51 +00002924}
2925
2926
2927static
sewardj00a66b12002-10-12 16:42:35 +00002928void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
sewardj5f07b662002-04-23 16:52:51 +00002929{
2930 Char msg_buf[100];
2931 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002932 VG_(sprintf)(msg_buf, "pthread_setspecific_ptr ptr %p",
2933 ptr );
sewardj5f07b662002-04-23 16:52:51 +00002934 print_pthread_event(tid, msg_buf);
2935 }
2936
sewardjb48e5002002-05-13 00:16:03 +00002937 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002938 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002939
sewardj00a66b12002-10-12 16:42:35 +00002940 VG_(threads)[tid].specifics_ptr = ptr;
sewardjc3bd5f52002-05-01 03:24:23 +00002941 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002942}
2943
2944
sewardj870497a2002-05-29 01:06:47 +00002945/* Helper for calling destructors at thread exit. If key is valid,
2946 copy the thread's specific value into cu->arg and put the *key*'s
2947 destructor fn address in cu->fn. Then return 0 to the caller.
2948 Otherwise return non-zero to the caller. */
2949static
2950void do__get_key_destr_and_spec ( ThreadId tid,
2951 pthread_key_t key,
2952 CleanupEntry* cu )
2953{
2954 Char msg_buf[100];
2955 if (VG_(clo_trace_pthread_level) >= 1) {
2956 VG_(sprintf)(msg_buf,
2957 "get_key_destr_and_arg (key = %d)", key );
2958 print_pthread_event(tid, msg_buf);
2959 }
2960 vg_assert(VG_(is_valid_tid)(tid));
2961 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00002962
sewardj870497a2002-05-29 01:06:47 +00002963 if (!vg_thread_keys[key].inuse) {
2964 SET_EDX(tid, -1);
2965 return;
2966 }
njn36650922002-10-04 09:18:09 +00002967 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
sewardj00a66b12002-10-12 16:42:35 +00002968 "get_key_destr_and_spec: cu", (Addr)cu,
njn36650922002-10-04 09:18:09 +00002969 sizeof(CleanupEntry) );
sewardj00a66b12002-10-12 16:42:35 +00002970
sewardj870497a2002-05-29 01:06:47 +00002971 cu->fn = vg_thread_keys[key].destructor;
sewardj00a66b12002-10-12 16:42:35 +00002972 if (VG_(threads)[tid].specifics_ptr == NULL) {
2973 cu->arg = NULL;
2974 } else {
2975 VG_TRACK( pre_mem_read, Vg_CorePThread, & VG_(threads)[tid],
2976 "get_key_destr_and_spec: key",
2977 (Addr)(&VG_(threads)[tid].specifics_ptr[key]),
2978 sizeof(void*) );
2979 cu->arg = VG_(threads)[tid].specifics_ptr[key];
2980 }
2981
njn25e49d8e72002-09-23 09:36:25 +00002982 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00002983 SET_EDX(tid, 0);
2984}
2985
2986
sewardjb48e5002002-05-13 00:16:03 +00002987/* ---------------------------------------------------
2988 SIGNALS
2989 ------------------------------------------------ */
2990
2991/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002992 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2993 for OK and 1 for some kind of addressing error, which the
2994 vg_libpthread.c routine turns into return values 0 and EFAULT
2995 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002996static
2997void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002998 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002999 vki_ksigset_t* newmask,
3000 vki_ksigset_t* oldmask )
3001{
3002 Char msg_buf[100];
3003 if (VG_(clo_trace_pthread_level) >= 1) {
3004 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00003005 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
3006 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003007 print_pthread_event(tid, msg_buf);
3008 }
3009
3010 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003011 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003012
njn25e49d8e72002-09-23 09:36:25 +00003013 if (newmask)
3014 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3015 "pthread_sigmask: newmask",
3016 (Addr)newmask, sizeof(vki_ksigset_t));
3017 if (oldmask)
3018 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3019 "pthread_sigmask: oldmask",
3020 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00003021
sewardj018f7622002-05-15 21:13:39 +00003022 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003023
njn25e49d8e72002-09-23 09:36:25 +00003024 if (oldmask)
3025 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00003026
sewardj018f7622002-05-15 21:13:39 +00003027 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00003028 SET_EDX(tid, 0);
3029}
3030
3031
3032static
3033void do_sigwait ( ThreadId tid,
3034 vki_ksigset_t* set,
3035 Int* sig )
3036{
sewardj018f7622002-05-15 21:13:39 +00003037 vki_ksigset_t irrelevant_sigmask;
3038 Char msg_buf[100];
3039
sewardjb48e5002002-05-13 00:16:03 +00003040 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3041 VG_(sprintf)(msg_buf,
3042 "suspend due to sigwait(): set %p, sig %p",
3043 set, sig );
3044 print_pthread_event(tid, msg_buf);
3045 }
3046
3047 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003048 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003049
sewardj018f7622002-05-15 21:13:39 +00003050 /* Change SCSS */
3051 VG_(threads)[tid].sigs_waited_for = *set;
3052 VG_(threads)[tid].status = VgTs_WaitSIG;
3053
3054 VG_(block_all_host_signals)( &irrelevant_sigmask );
3055 VG_(handle_SCSS_change)( False /* lazy update */ );
3056}
3057
3058
3059static
3060void do_pthread_kill ( ThreadId tid, /* me */
3061 ThreadId thread, /* thread to signal */
3062 Int sig )
3063{
3064 Char msg_buf[100];
3065
3066 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3067 VG_(sprintf)(msg_buf,
3068 "pthread_kill thread %d, signo %d",
3069 thread, sig );
3070 print_pthread_event(tid, msg_buf);
3071 }
3072
3073 vg_assert(VG_(is_valid_tid)(tid)
3074 && VG_(threads)[tid].status == VgTs_Runnable);
3075
sewardj4dced352002-06-04 22:54:20 +00003076 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003077 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003078 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003079 SET_EDX(tid, -VKI_ESRCH);
3080 return;
3081 }
3082
3083 if (sig < 1 || sig > VKI_KNSIG) {
3084 SET_EDX(tid, -VKI_EINVAL);
3085 return;
3086 }
3087
3088 VG_(send_signal_to_thread)( thread, sig );
3089 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003090}
3091
3092
sewardj2cb00342002-06-28 01:46:26 +00003093/* -----------------------------------------------------------
3094 FORK HANDLERS.
3095 -------------------------------------------------------- */
3096
3097static
3098void do__set_fhstack_used ( ThreadId tid, Int n )
3099{
3100 Char msg_buf[100];
3101 if (VG_(clo_trace_sched)) {
3102 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3103 print_pthread_event(tid, msg_buf);
3104 }
3105
3106 vg_assert(VG_(is_valid_tid)(tid)
3107 && VG_(threads)[tid].status == VgTs_Runnable);
3108
3109 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3110 vg_fhstack_used = n;
3111 SET_EDX(tid, 0);
3112 } else {
3113 SET_EDX(tid, -1);
3114 }
3115}
3116
3117
3118static
3119void do__get_fhstack_used ( ThreadId tid )
3120{
3121 Int n;
3122 Char msg_buf[100];
3123 if (VG_(clo_trace_sched)) {
3124 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3125 print_pthread_event(tid, msg_buf);
3126 }
3127
3128 vg_assert(VG_(is_valid_tid)(tid)
3129 && VG_(threads)[tid].status == VgTs_Runnable);
3130
3131 n = vg_fhstack_used;
3132 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3133 SET_EDX(tid, n);
3134}
3135
3136static
3137void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3138{
3139 Char msg_buf[100];
3140 if (VG_(clo_trace_sched)) {
3141 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3142 print_pthread_event(tid, msg_buf);
3143 }
3144
3145 vg_assert(VG_(is_valid_tid)(tid)
3146 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003147 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3148 "pthread_atfork: prepare/parent/child",
3149 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003150
njn25e49d8e72002-09-23 09:36:25 +00003151 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003152 SET_EDX(tid, -1);
3153 return;
3154 }
3155
3156 vg_fhstack[n] = *fh;
3157 SET_EDX(tid, 0);
3158}
3159
3160
3161static
3162void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3163 ForkHandlerEntry* fh )
3164{
3165 Char msg_buf[100];
3166 if (VG_(clo_trace_sched)) {
3167 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3168 print_pthread_event(tid, msg_buf);
3169 }
3170
3171 vg_assert(VG_(is_valid_tid)(tid)
3172 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003173 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3174 "fork: prepare/parent/child",
3175 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003176
njn25e49d8e72002-09-23 09:36:25 +00003177 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003178 SET_EDX(tid, -1);
3179 return;
3180 }
3181
3182 *fh = vg_fhstack[n];
3183 SET_EDX(tid, 0);
3184
njn25e49d8e72002-09-23 09:36:25 +00003185 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003186}
3187
3188
sewardje663cb92002-04-12 10:26:32 +00003189/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003190 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003191 ------------------------------------------------------------------ */
3192
sewardj124ca2a2002-06-20 10:19:38 +00003193/* Do a client request for the thread tid. After the request, tid may
3194 or may not still be runnable; if not, the scheduler will have to
3195 choose a new thread to run.
3196*/
sewardje663cb92002-04-12 10:26:32 +00003197static
sewardj124ca2a2002-06-20 10:19:38 +00003198void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003199{
njn25e49d8e72002-09-23 09:36:25 +00003200# define RETURN_WITH(vvv) \
3201 { tst->m_edx = (vvv); \
3202 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003203 }
3204
3205 ThreadState* tst = &VG_(threads)[tid];
3206 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3207 UInt req_no = arg[0];
3208
3209 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003210 switch (req_no) {
3211
sewardj124ca2a2002-06-20 10:19:38 +00003212 case VG_USERREQ__MALLOC:
3213 RETURN_WITH(
3214 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3215 );
3216 break;
3217
3218 case VG_USERREQ__BUILTIN_NEW:
3219 RETURN_WITH(
3220 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3221 );
3222 break;
3223
3224 case VG_USERREQ__BUILTIN_VEC_NEW:
3225 RETURN_WITH(
3226 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3227 );
3228 break;
3229
3230 case VG_USERREQ__FREE:
3231 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3232 RETURN_WITH(0); /* irrelevant */
3233 break;
3234
3235 case VG_USERREQ__BUILTIN_DELETE:
3236 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3237 RETURN_WITH(0); /* irrelevant */
3238 break;
3239
3240 case VG_USERREQ__BUILTIN_VEC_DELETE:
3241 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3242 RETURN_WITH(0); /* irrelevant */
3243 break;
3244
3245 case VG_USERREQ__CALLOC:
3246 RETURN_WITH(
3247 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3248 );
3249 break;
3250
3251 case VG_USERREQ__REALLOC:
3252 RETURN_WITH(
3253 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3254 );
3255 break;
3256
3257 case VG_USERREQ__MEMALIGN:
3258 RETURN_WITH(
3259 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3260 );
3261 break;
3262
3263 case VG_USERREQ__PTHREAD_GET_THREADID:
3264 RETURN_WITH(tid);
3265 break;
3266
3267 case VG_USERREQ__RUNNING_ON_VALGRIND:
3268 RETURN_WITH(1);
3269 break;
3270
3271 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3272 RETURN_WITH(VG_(clo_trace_pthread_level));
3273 break;
3274
3275 case VG_USERREQ__READ_MILLISECOND_TIMER:
3276 RETURN_WITH(VG_(read_millisecond_timer)());
3277 break;
3278
3279 /* Some of these may make thread tid non-runnable, but the
3280 scheduler checks for that on return from this function. */
3281 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3282 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3283 break;
3284
3285 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3286 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3287 break;
3288
3289 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3290 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3291 break;
3292
sewardj00a66b12002-10-12 16:42:35 +00003293 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
3294 do_pthread_getspecific_ptr ( tid );
sewardj124ca2a2002-06-20 10:19:38 +00003295 break;
3296
3297 case VG_USERREQ__SET_CANCELTYPE:
3298 do__set_canceltype ( tid, arg[1] );
3299 break;
3300
3301 case VG_USERREQ__CLEANUP_PUSH:
3302 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3303 break;
3304
3305 case VG_USERREQ__CLEANUP_POP:
3306 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3307 break;
3308
3309 case VG_USERREQ__TESTCANCEL:
3310 do__testcancel ( tid );
3311 break;
3312
3313 case VG_USERREQ__GET_N_SIGS_RETURNED:
3314 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3315 break;
3316
sewardje663cb92002-04-12 10:26:32 +00003317 case VG_USERREQ__PTHREAD_JOIN:
3318 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3319 break;
3320
sewardj3b5d8862002-04-20 13:53:23 +00003321 case VG_USERREQ__PTHREAD_COND_WAIT:
3322 do_pthread_cond_wait( tid,
3323 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003324 (pthread_mutex_t *)(arg[2]),
3325 0xFFFFFFFF /* no timeout */ );
3326 break;
3327
3328 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3329 do_pthread_cond_wait( tid,
3330 (pthread_cond_t *)(arg[1]),
3331 (pthread_mutex_t *)(arg[2]),
3332 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003333 break;
3334
3335 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3336 do_pthread_cond_signal_or_broadcast(
3337 tid,
3338 False, /* signal, not broadcast */
3339 (pthread_cond_t *)(arg[1]) );
3340 break;
3341
3342 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3343 do_pthread_cond_signal_or_broadcast(
3344 tid,
3345 True, /* broadcast, not signal */
3346 (pthread_cond_t *)(arg[1]) );
3347 break;
3348
sewardj00a66b12002-10-12 16:42:35 +00003349 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
3350 do_pthread_key_validate ( tid,
3351 (pthread_key_t)(arg[1]) );
3352 break;
3353
sewardj5f07b662002-04-23 16:52:51 +00003354 case VG_USERREQ__PTHREAD_KEY_CREATE:
3355 do_pthread_key_create ( tid,
3356 (pthread_key_t*)(arg[1]),
3357 (void(*)(void*))(arg[2]) );
3358 break;
3359
3360 case VG_USERREQ__PTHREAD_KEY_DELETE:
3361 do_pthread_key_delete ( tid,
3362 (pthread_key_t)(arg[1]) );
3363 break;
3364
sewardj00a66b12002-10-12 16:42:35 +00003365 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
3366 do_pthread_setspecific_ptr ( tid,
3367 (void**)(arg[1]) );
sewardj5f07b662002-04-23 16:52:51 +00003368 break;
3369
sewardjb48e5002002-05-13 00:16:03 +00003370 case VG_USERREQ__PTHREAD_SIGMASK:
3371 do_pthread_sigmask ( tid,
3372 arg[1],
3373 (vki_ksigset_t*)(arg[2]),
3374 (vki_ksigset_t*)(arg[3]) );
3375 break;
3376
3377 case VG_USERREQ__SIGWAIT:
3378 do_sigwait ( tid,
3379 (vki_ksigset_t*)(arg[1]),
3380 (Int*)(arg[2]) );
3381 break;
3382
sewardj018f7622002-05-15 21:13:39 +00003383 case VG_USERREQ__PTHREAD_KILL:
3384 do_pthread_kill ( tid, arg[1], arg[2] );
3385 break;
3386
sewardjff42d1d2002-05-22 13:17:31 +00003387 case VG_USERREQ__PTHREAD_YIELD:
3388 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003389 /* On return from do_client_request(), the scheduler will
3390 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003391 break;
sewardj018f7622002-05-15 21:13:39 +00003392
sewardj7989d0c2002-05-28 11:00:01 +00003393 case VG_USERREQ__SET_CANCELSTATE:
3394 do__set_cancelstate ( tid, arg[1] );
3395 break;
3396
sewardj7989d0c2002-05-28 11:00:01 +00003397 case VG_USERREQ__SET_OR_GET_DETACH:
3398 do__set_or_get_detach ( tid, arg[1], arg[2] );
3399 break;
3400
3401 case VG_USERREQ__SET_CANCELPEND:
3402 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3403 break;
3404
3405 case VG_USERREQ__WAIT_JOINER:
3406 do__wait_joiner ( tid, (void*)arg[1] );
3407 break;
3408
3409 case VG_USERREQ__QUIT:
3410 do__quit ( tid );
3411 break;
3412
3413 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3414 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3415 (void*)arg[2] );
3416 break;
3417
sewardj870497a2002-05-29 01:06:47 +00003418 case VG_USERREQ__GET_KEY_D_AND_S:
3419 do__get_key_destr_and_spec ( tid,
3420 (pthread_key_t)arg[1],
3421 (CleanupEntry*)arg[2] );
3422 break;
3423
sewardjef037c72002-05-30 00:40:03 +00003424 case VG_USERREQ__NUKE_OTHER_THREADS:
3425 VG_(nuke_all_threads_except) ( tid );
3426 SET_EDX(tid, 0);
3427 break;
3428
sewardj4dced352002-06-04 22:54:20 +00003429 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003430 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003431 SET_EDX(tid, 0);
3432 break;
3433
sewardj2cb00342002-06-28 01:46:26 +00003434 case VG_USERREQ__SET_FHSTACK_USED:
3435 do__set_fhstack_used( tid, (Int)(arg[1]) );
3436 break;
3437
3438 case VG_USERREQ__GET_FHSTACK_USED:
3439 do__get_fhstack_used( tid );
3440 break;
3441
3442 case VG_USERREQ__SET_FHSTACK_ENTRY:
3443 do__set_fhstack_entry( tid, (Int)(arg[1]),
3444 (ForkHandlerEntry*)(arg[2]) );
3445 break;
3446
3447 case VG_USERREQ__GET_FHSTACK_ENTRY:
3448 do__get_fhstack_entry( tid, (Int)(arg[1]),
3449 (ForkHandlerEntry*)(arg[2]) );
3450 break;
3451
sewardj77e466c2002-04-14 02:29:29 +00003452 case VG_USERREQ__SIGNAL_RETURNS:
3453 handle_signal_return(tid);
3454 break;
sewardj69a72a52002-11-03 13:41:41 +00003455
3456 case VG_USERREQ__LOGMESSAGE:
3457 VG_(message)(Vg_UserMsg, "%s", (Char*)(arg[1]));
3458 break;
sewardj54cacf02002-04-12 23:24:59 +00003459
njn25e49d8e72002-09-23 09:36:25 +00003460 /* Requests from the client program */
3461
3462 case VG_USERREQ__DISCARD_TRANSLATIONS:
3463 if (VG_(clo_verbosity) > 2)
3464 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3465 " addr %p, len %d\n",
3466 (void*)arg[1], arg[2] );
3467
3468 VG_(invalidate_translations)( arg[1], arg[2] );
3469
3470 SET_EDX( tid, 0 ); /* return value is meaningless */
3471 break;
3472
sewardje663cb92002-04-12 10:26:32 +00003473 default:
njn25e49d8e72002-09-23 09:36:25 +00003474 if (VG_(needs).client_requests) {
sewardj34042512002-10-22 04:14:35 +00003475 UInt ret;
3476
njn25e49d8e72002-09-23 09:36:25 +00003477 if (VG_(clo_verbosity) > 2)
3478 VG_(printf)("client request: code %d, addr %p, len %d\n",
3479 arg[0], (void*)arg[1], arg[2] );
3480
sewardj34042512002-10-22 04:14:35 +00003481 if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret ))
3482 SET_EDX(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00003483 } else {
sewardj34042512002-10-22 04:14:35 +00003484 static Bool whined = False;
3485
3486 if (!whined) {
3487 VG_(message)(Vg_UserMsg, "Warning:\n"
3488 " unhandled client request: 0x%x (%c%c+%d). Perhaps\n"
3489 " VG_(needs).client_requests should be set?\n",
3490 arg[0], (arg[0] >> 24) & 0xff, (arg[0] >> 16) & 0xff,
3491 arg[0] & 0xffff);
3492 whined = True;
3493 }
njn25e49d8e72002-09-23 09:36:25 +00003494 }
sewardje663cb92002-04-12 10:26:32 +00003495 break;
3496 }
sewardj124ca2a2002-06-20 10:19:38 +00003497
3498# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003499}
3500
3501
sewardj6072c362002-04-19 14:40:57 +00003502/* ---------------------------------------------------------------------
3503 Sanity checking.
3504 ------------------------------------------------------------------ */
3505
3506/* Internal consistency checks on the sched/pthread structures. */
3507static
3508void scheduler_sanity ( void )
3509{
sewardj3b5d8862002-04-20 13:53:23 +00003510 pthread_mutex_t* mx;
3511 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003512 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003513
sewardj6072c362002-04-19 14:40:57 +00003514 /* VG_(printf)("scheduler_sanity\n"); */
3515 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003516 mx = VG_(threads)[i].associated_mx;
3517 cv = VG_(threads)[i].associated_cv;
3518 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003519 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3520 it's actually held by someone, since otherwise this thread
3521 is deadlocked, (4) the mutex's owner is not us, since
3522 otherwise this thread is also deadlocked. The logic in
3523 do_pthread_mutex_lock rejects attempts by a thread to lock
3524 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003525
sewardjbf290b92002-05-01 02:28:01 +00003526 (2) has been seen to fail sometimes. I don't know why.
3527 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003528 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003529 /* 1 */ vg_assert(mx != NULL);
3530 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003531 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003532 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003533 } else
sewardj018f7622002-05-15 21:13:39 +00003534 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003535 vg_assert(cv != NULL);
3536 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003537 } else {
sewardj05553872002-04-20 20:53:17 +00003538 /* Unfortunately these don't hold true when a sighandler is
3539 running. To be fixed. */
3540 /* vg_assert(cv == NULL); */
3541 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003542 }
sewardjbf290b92002-05-01 02:28:01 +00003543
sewardj018f7622002-05-15 21:13:39 +00003544 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003545 Int
sewardj018f7622002-05-15 21:13:39 +00003546 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3547 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003548 if (i > 1 /* not the root thread */
3549 && stack_used
3550 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3551 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003552 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003553 "thread %d: stack used %d, available %d",
3554 i, stack_used, VG_PTHREAD_STACK_MIN );
3555 VG_(message)(Vg_UserMsg,
3556 "Terminating Valgrind. If thread(s) "
3557 "really need more stack, increase");
3558 VG_(message)(Vg_UserMsg,
3559 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3560 VG_(exit)(1);
3561 }
sewardjb48e5002002-05-13 00:16:03 +00003562
sewardj018f7622002-05-15 21:13:39 +00003563 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003564 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003565 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003566 } else {
3567 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003568 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003569 }
3570
sewardjbf290b92002-05-01 02:28:01 +00003571 }
sewardj6072c362002-04-19 14:40:57 +00003572 }
sewardj5f07b662002-04-23 16:52:51 +00003573
3574 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3575 if (!vg_thread_keys[i].inuse)
3576 vg_assert(vg_thread_keys[i].destructor == NULL);
3577 }
sewardj6072c362002-04-19 14:40:57 +00003578}
3579
3580
sewardje663cb92002-04-12 10:26:32 +00003581/*--------------------------------------------------------------------*/
3582/*--- end vg_scheduler.c ---*/
3583/*--------------------------------------------------------------------*/