blob: 59804c4c60b65d43f01481e6d2471ef1ae1f9c85 [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{
319 Addr trans_addr;
320 TTEntry tte;
321 Int orig_size, trans_size;
322 /* Ensure there is space to hold a translation. */
323 VG_(maybe_do_lru_pass)();
sewardj018f7622002-05-15 21:13:39 +0000324 VG_(translate)( &VG_(threads)[tid],
sewardj1e8cdc92002-04-18 11:37:52 +0000325 orig_addr, &orig_size, &trans_addr, &trans_size );
sewardje663cb92002-04-12 10:26:32 +0000326 /* Copy data at trans_addr into the translation cache.
327 Returned pointer is to the code, not to the 4-byte
328 header. */
329 /* Since the .orig_size and .trans_size fields are
330 UShort, be paranoid. */
331 vg_assert(orig_size > 0 && orig_size < 65536);
332 vg_assert(trans_size > 0 && trans_size < 65536);
333 tte.orig_size = orig_size;
334 tte.orig_addr = orig_addr;
335 tte.trans_size = trans_size;
336 tte.trans_addr = VG_(copy_to_transcache)
337 ( trans_addr, trans_size );
338 tte.mru_epoch = VG_(current_epoch);
339 /* 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 /* Add to trans tab and set back pointer. */
342 VG_(add_to_trans_tab) ( &tte );
343 /* Update stats. */
344 VG_(this_epoch_in_count) ++;
345 VG_(this_epoch_in_osize) += orig_size;
346 VG_(this_epoch_in_tsize) += trans_size;
347 VG_(overall_in_count) ++;
348 VG_(overall_in_osize) += orig_size;
349 VG_(overall_in_tsize) += trans_size;
sewardje663cb92002-04-12 10:26:32 +0000350}
351
352
353/* Allocate a completely empty ThreadState record. */
354static
355ThreadId vg_alloc_ThreadState ( void )
356{
357 Int i;
sewardj6072c362002-04-19 14:40:57 +0000358 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000359 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000360 return i;
361 }
362 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
363 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000364 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000365 /*NOTREACHED*/
366}
367
njn25e49d8e72002-09-23 09:36:25 +0000368ThreadState* VG_(get_ThreadState)( ThreadId tid )
369{
370 vg_assert(tid >= 0 && tid < VG_N_THREADS);
371 return & VG_(threads)[tid];
372}
sewardje663cb92002-04-12 10:26:32 +0000373
sewardj1e8cdc92002-04-18 11:37:52 +0000374ThreadState* VG_(get_current_thread_state) ( void )
375{
sewardj018f7622002-05-15 21:13:39 +0000376 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
377 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000378}
379
380
381ThreadId VG_(get_current_tid) ( void )
382{
sewardjb52a1b02002-10-23 21:38:22 +0000383 if (!VG_(is_valid_tid)(vg_tid_currently_in_baseBlock))
384 return VG_INVALID_THREADID;
sewardj1e8cdc92002-04-18 11:37:52 +0000385 return vg_tid_currently_in_baseBlock;
386}
387
sewardjb52a1b02002-10-23 21:38:22 +0000388ThreadId VG_(get_current_or_recent_tid) ( void )
njn25e49d8e72002-09-23 09:36:25 +0000389{
sewardjb52a1b02002-10-23 21:38:22 +0000390 vg_assert(vg_tid_currently_in_baseBlock == vg_tid_last_in_baseBlock ||
391 vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
392 vg_assert(VG_(is_valid_tid)(vg_tid_last_in_baseBlock));
393
394 return vg_tid_last_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000395}
396
sewardj7ab2aca2002-10-20 19:40:32 +0000397ThreadId VG_(get_tid_from_ThreadState) (ThreadState* tst)
398{
399 vg_assert(tst >= &VG_(threads)[1] && tst < &VG_(threads)[VG_N_THREADS]);
400 return tst->tid;
401}
402
sewardj1e8cdc92002-04-18 11:37:52 +0000403
sewardje663cb92002-04-12 10:26:32 +0000404/* Copy the saved state of a thread into VG_(baseBlock), ready for it
405 to be run. */
406__inline__
407void VG_(load_thread_state) ( ThreadId tid )
408{
409 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000410 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
411
sewardj92a59562002-09-30 00:53:10 +0000412 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
413 VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs;
414 VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss;
415 VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds;
416 VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es;
417 VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs;
418 VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs;
419
sewardj018f7622002-05-15 21:13:39 +0000420 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
421 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
422 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
423 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
424 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
425 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
426 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
427 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
428 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags;
429 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000430
431 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000432 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000433
njn25e49d8e72002-09-23 09:36:25 +0000434 if (VG_(needs).shadow_regs) {
435 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
436 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
437 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
438 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
439 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
440 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
441 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
442 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
443 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
444 } else {
445 /* Fields shouldn't be used -- check their values haven't changed. */
446 /* Nb: they are written to by some macros like SET_EDX, but they
447 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
448 vg_assert(
449 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
450 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
451 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
452 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
453 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
454 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
455 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
456 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
457 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
458 }
sewardj1e8cdc92002-04-18 11:37:52 +0000459
460 vg_tid_currently_in_baseBlock = tid;
sewardjb52a1b02002-10-23 21:38:22 +0000461 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000462}
463
464
465/* Copy the state of a thread from VG_(baseBlock), presumably after it
466 has been descheduled. For sanity-check purposes, fill the vacated
467 VG_(baseBlock) with garbage so as to make the system more likely to
468 fail quickly if we erroneously continue to poke around inside
469 VG_(baseBlock) without first doing a load_thread_state().
470*/
471__inline__
472void VG_(save_thread_state) ( ThreadId tid )
473{
474 Int i;
475 const UInt junk = 0xDEADBEEF;
476
sewardj1e8cdc92002-04-18 11:37:52 +0000477 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
478
sewardj92a59562002-09-30 00:53:10 +0000479
480 /* We don't copy out the LDT entry, because it can never be changed
481 by the normal actions of the thread, only by the modify_ldt
482 syscall, in which case we will correctly be updating
483 VG_(threads)[tid].ldt. */
484 vg_assert((void*)VG_(threads)[tid].ldt
485 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
486
487 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
488 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
489 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
490 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
491 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
492 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
493
sewardj018f7622002-05-15 21:13:39 +0000494 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
495 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
496 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
497 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
498 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
499 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
500 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
501 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
502 VG_(threads)[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
503 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000504
505 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000506 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000507
njn25e49d8e72002-09-23 09:36:25 +0000508 if (VG_(needs).shadow_regs) {
509 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
510 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
511 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
512 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
513 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
514 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
515 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
516 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
517 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
518 } else {
519 /* Fill with recognisable junk */
520 VG_(threads)[tid].sh_eax =
521 VG_(threads)[tid].sh_ebx =
522 VG_(threads)[tid].sh_ecx =
523 VG_(threads)[tid].sh_edx =
524 VG_(threads)[tid].sh_esi =
525 VG_(threads)[tid].sh_edi =
526 VG_(threads)[tid].sh_ebp =
527 VG_(threads)[tid].sh_esp =
528 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
529 }
sewardje663cb92002-04-12 10:26:32 +0000530
531 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000532 VG_(baseBlock)[VGOFF_(ldt)] = junk;
533 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
534 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
535 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
536 VG_(baseBlock)[VGOFF_(m_es)] = junk;
537 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
538 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
539
sewardje663cb92002-04-12 10:26:32 +0000540 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
541 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
542 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
543 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
544 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
545 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
546 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
547 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
548 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
549 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
550
551 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
552 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000553
554 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000555}
556
557
558/* Run the thread tid for a while, and return a VG_TRC_* value to the
559 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000560static
sewardje663cb92002-04-12 10:26:32 +0000561UInt run_thread_for_a_while ( ThreadId tid )
562{
sewardj7ccc5c22002-04-24 21:39:11 +0000563 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000564 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000565 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000566 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000567 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000568
sewardj671ff542002-05-07 09:25:30 +0000569 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000570 VG_(load_thread_state) ( tid );
571 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
572 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000573 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000574 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000575 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000576 /* We get here if the client didn't take a fault. */
577 } else {
578 /* We get here if the client took a fault, which caused our
579 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000580 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000581 vg_assert(trc == 0);
582 trc = VG_TRC_UNRESUMABLE_SIGNAL;
583 }
sewardj872051c2002-07-13 12:12:56 +0000584
585 vg_assert(!VG_(scheduler_jmpbuf_valid));
586
sewardje663cb92002-04-12 10:26:32 +0000587 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000588 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000589 return trc;
590}
591
592
593/* Increment the LRU epoch counter. */
594static
595void increment_epoch ( void )
596{
597 VG_(current_epoch)++;
598 if (VG_(clo_verbosity) > 2) {
599 UInt tt_used, tc_used;
600 VG_(get_tt_tc_used) ( &tt_used, &tc_used );
601 VG_(message)(Vg_UserMsg,
602 "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
603 VG_(bbs_done),
604 VG_(this_epoch_in_count),
605 VG_(this_epoch_in_osize),
606 VG_(this_epoch_in_tsize),
607 VG_(this_epoch_out_count),
608 VG_(this_epoch_out_osize),
609 VG_(this_epoch_out_tsize),
610 tt_used, tc_used
611 );
612 }
613 VG_(this_epoch_in_count) = 0;
614 VG_(this_epoch_in_osize) = 0;
615 VG_(this_epoch_in_tsize) = 0;
616 VG_(this_epoch_out_count) = 0;
617 VG_(this_epoch_out_osize) = 0;
618 VG_(this_epoch_out_tsize) = 0;
619}
620
621
sewardj20917d82002-05-28 01:36:45 +0000622static
623void mostly_clear_thread_record ( ThreadId tid )
624{
sewardj20917d82002-05-28 01:36:45 +0000625 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000626 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000627 VG_(threads)[tid].tid = tid;
628 VG_(threads)[tid].status = VgTs_Empty;
629 VG_(threads)[tid].associated_mx = NULL;
630 VG_(threads)[tid].associated_cv = NULL;
631 VG_(threads)[tid].awaken_at = 0;
632 VG_(threads)[tid].joinee_retval = NULL;
633 VG_(threads)[tid].joiner_thread_return = NULL;
634 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000635 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000636 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
637 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
638 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000639 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000640 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000641 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
642 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardj00a66b12002-10-12 16:42:35 +0000643 VG_(threads)[tid].specifics_ptr = NULL;
sewardj20917d82002-05-28 01:36:45 +0000644}
645
646
sewardje663cb92002-04-12 10:26:32 +0000647/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000648 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000649 caller takes care to park the client's state is parked in
650 VG_(baseBlock).
651*/
652void VG_(scheduler_init) ( void )
653{
654 Int i;
655 Addr startup_esp;
656 ThreadId tid_main;
657
658 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000659
660 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
daywalkera2562202002-07-15 19:39:51 +0000661 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)
njn25e49d8e72002-09-23 09:36:25 +0000662 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_3)
663 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_4)) {
sewardja1679dd2002-05-10 22:31:40 +0000664 /* Jolly good! */
665 } else {
njn25e49d8e72002-09-23 09:36:25 +0000666 VG_(printf)(
667 "%%esp at startup = %p is not near %p, %p, %p or %p; aborting\n",
668 (void*)startup_esp,
669 (void*)VG_STARTUP_STACK_BASE_1,
670 (void*)VG_STARTUP_STACK_BASE_2,
671 (void*)VG_STARTUP_STACK_BASE_3,
672 (void*)VG_STARTUP_STACK_BASE_4
673 );
njne427a662002-10-02 11:08:25 +0000674 VG_(core_panic)("unexpected %esp at startup");
sewardje663cb92002-04-12 10:26:32 +0000675 }
676
sewardj6072c362002-04-19 14:40:57 +0000677 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000678 mostly_clear_thread_record(i);
679 VG_(threads)[i].stack_size = 0;
680 VG_(threads)[i].stack_base = (Addr)NULL;
681 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000682 }
683
684 for (i = 0; i < VG_N_WAITING_FDS; i++)
685 vg_waiting_fds[i].fd = -1; /* not in use */
686
sewardj5f07b662002-04-23 16:52:51 +0000687 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
688 vg_thread_keys[i].inuse = False;
689 vg_thread_keys[i].destructor = NULL;
690 }
691
sewardj2cb00342002-06-28 01:46:26 +0000692 vg_fhstack_used = 0;
693
sewardje663cb92002-04-12 10:26:32 +0000694 /* Assert this is thread zero, which has certain magic
695 properties. */
696 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000697 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000698 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000699
700 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000701 vg_tid_currently_in_baseBlock = tid_main;
sewardjb52a1b02002-10-23 21:38:22 +0000702 vg_tid_last_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000703 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000704
sewardj018f7622002-05-15 21:13:39 +0000705 VG_(threads)[tid_main].stack_highest_word
706 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000707
sewardj1e8cdc92002-04-18 11:37:52 +0000708 /* So now ... */
709 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000710
711 /* Not running client code right now. */
712 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000713}
714
715
716/* What if fd isn't a valid fd? */
717static
718void set_fd_nonblocking ( Int fd )
719{
720 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
721 vg_assert(!VG_(is_kerror)(res));
722 res |= VKI_O_NONBLOCK;
723 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
724 vg_assert(!VG_(is_kerror)(res));
725}
726
727static
728void set_fd_blocking ( Int fd )
729{
730 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
731 vg_assert(!VG_(is_kerror)(res));
732 res &= ~VKI_O_NONBLOCK;
733 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
734 vg_assert(!VG_(is_kerror)(res));
735}
736
737static
738Bool fd_is_blockful ( Int fd )
739{
740 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
741 vg_assert(!VG_(is_kerror)(res));
742 return (res & VKI_O_NONBLOCK) ? False : True;
743}
744
sewardj3947e622002-05-23 16:52:11 +0000745static
746Bool fd_is_valid ( Int fd )
747{
748 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
749 return VG_(is_kerror)(res) ? False : True;
750}
751
sewardje663cb92002-04-12 10:26:32 +0000752
753
sewardj6072c362002-04-19 14:40:57 +0000754/* vthread tid is returning from a signal handler; modify its
755 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000756
757/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
758 for read or write, has been interrupted by a signal. Find and
759 clear the relevant vg_waiting_fd[] entry. Most of the code in this
760 procedure is total paranoia, if you look closely. */
761static
762void cleanup_waiting_fd_table ( ThreadId tid )
763{
764 Int i, waiters;
765
sewardjb48e5002002-05-13 00:16:03 +0000766 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000767 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
768 vg_assert(VG_(threads)[tid].m_eax == __NR_read
769 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000770
771 /* Excessively paranoidly ... find the fd this op was waiting
772 for, and mark it as not being waited on. */
773 waiters = 0;
774 for (i = 0; i < VG_N_WAITING_FDS; i++) {
775 if (vg_waiting_fds[i].tid == tid) {
776 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000777 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000778 }
779 }
780 vg_assert(waiters == 1);
781 for (i = 0; i < VG_N_WAITING_FDS; i++)
782 if (vg_waiting_fds[i].tid == tid)
783 break;
784 vg_assert(i < VG_N_WAITING_FDS);
785 vg_assert(vg_waiting_fds[i].fd != -1);
786 vg_waiting_fds[i].fd = -1; /* not in use */
787}
788
789
sewardj6072c362002-04-19 14:40:57 +0000790static
791void handle_signal_return ( ThreadId tid )
792{
793 Char msg_buf[100];
794 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000795 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000796
sewardjb48e5002002-05-13 00:16:03 +0000797 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000798
sewardj9a2224b2002-06-19 10:17:40 +0000799 /* Increment signal-returned counter. Used only to implement
800 pause(). */
801 VG_(threads)[tid].n_signals_returned++;
802
sewardj6072c362002-04-19 14:40:57 +0000803 restart_blocked_syscalls = VG_(signal_returns)(tid);
804
805 if (restart_blocked_syscalls)
806 /* Easy; we don't have to do anything. */
807 return;
808
sewardj018f7622002-05-15 21:13:39 +0000809 if (VG_(threads)[tid].status == VgTs_WaitFD
810 && (VG_(threads)[tid].m_eax == __NR_read
811 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000812 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000813 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000814 VG_(threads)[tid].m_eax = -VKI_EINTR;
815 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000816
sewardj6072c362002-04-19 14:40:57 +0000817 if (VG_(clo_trace_sched)) {
818 VG_(sprintf)(msg_buf,
819 "read() / write() interrupted by signal; return EINTR" );
820 print_sched_event(tid, msg_buf);
821 }
822 return;
823 }
824
sewardj645030e2002-06-06 01:27:39 +0000825 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000826 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000827 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000828 write the unused time to nanosleep's second param, but that's
829 too much effort ... we just say that 1 nanosecond was not
830 used, and return EINTR. */
831 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
832 if (rem != NULL) {
833 rem->tv_sec = 0;
834 rem->tv_nsec = 1;
835 }
836 SET_EAX(tid, -VKI_EINTR);
837 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000838 return;
839 }
840
sewardj018f7622002-05-15 21:13:39 +0000841 if (VG_(threads)[tid].status == VgTs_WaitFD) {
njne427a662002-10-02 11:08:25 +0000842 VG_(core_panic)("handle_signal_return: unknown interrupted syscall");
sewardj1ffa8da2002-04-26 22:47:57 +0000843 }
844
sewardj6072c362002-04-19 14:40:57 +0000845 /* All other cases? Just return. */
846}
847
848
sewardje663cb92002-04-12 10:26:32 +0000849static
850void sched_do_syscall ( ThreadId tid )
851{
njn25e49d8e72002-09-23 09:36:25 +0000852 UInt saved_eax;
853 UInt res, syscall_no;
854 UInt fd;
855 void* pre_res;
856 Bool orig_fd_blockness;
857 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000858
sewardjb48e5002002-05-13 00:16:03 +0000859 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000860 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000861
sewardj018f7622002-05-15 21:13:39 +0000862 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000863
864 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000865 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000866 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000867 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000868 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000869 t_awaken
870 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000871 + (UInt)1000ULL * (UInt)(req->tv_sec)
872 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000873 VG_(threads)[tid].status = VgTs_Sleeping;
874 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000875 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000876 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000877 t_now, t_awaken-t_now);
878 print_sched_event(tid, msg_buf);
879 }
880 /* Force the scheduler to run something else for a while. */
881 return;
882 }
883
sewardjaec22c02002-04-29 01:58:08 +0000884 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000885 /* We think it's non-blocking. Just do it in the normal way. */
886 VG_(perform_assumed_nonblocking_syscall)(tid);
887 /* The thread is still runnable. */
888 return;
889 }
890
sewardje663cb92002-04-12 10:26:32 +0000891 /* Set the fd to nonblocking, and do the syscall, which will return
892 immediately, in order to lodge a request with the Linux kernel.
893 We later poll for I/O completion using select(). */
894
sewardj018f7622002-05-15 21:13:39 +0000895 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000896
897 /* Deal with error case immediately. */
898 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000899 if (VG_(needs).core_errors)
900 VG_(message)(Vg_UserMsg,
901 "Warning: invalid file descriptor %d in syscall %s",
902 fd, syscall_no == __NR_read ? "read()" : "write()" );
903 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000904 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000905 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000906 /* We're still runnable. */
907 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
908 return;
909 }
910
911 /* From here onwards we know that fd is valid. */
912
sewardje663cb92002-04-12 10:26:32 +0000913 orig_fd_blockness = fd_is_blockful(fd);
914 set_fd_nonblocking(fd);
915 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000916 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000917
918 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000919 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000920 KERNEL_DO_SYSCALL(tid,res);
921
922 /* Restore original blockfulness of the fd. */
923 if (orig_fd_blockness)
924 set_fd_blocking(fd);
925 else
926 set_fd_nonblocking(fd);
927
sewardjaec22c02002-04-29 01:58:08 +0000928 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
929 /* Finish off in the normal way. Don't restore %EAX, since that
930 now (correctly) holds the result of the call. We get here if either:
931 1. The call didn't block, or
932 2. The fd was already in nonblocking mode before we started to
933 mess with it. In this case, we're not expecting to handle
934 the I/O completion -- the client is. So don't file a
935 completion-wait entry.
936 */
njn25e49d8e72002-09-23 09:36:25 +0000937 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000938 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000939 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000940
941 } else {
942
sewardjaec22c02002-04-29 01:58:08 +0000943 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
944
sewardje663cb92002-04-12 10:26:32 +0000945 /* It would have blocked. First, restore %EAX to what it was
946 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000947 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000948 /* Put this fd in a table of fds on which we are waiting for
949 completion. The arguments for select() later are constructed
950 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000951 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
952 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000953 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000954 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000955 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000956 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
957 print_sched_event(tid, msg_buf);
958 }
959
960 }
961}
962
963
964/* Find out which of the fds in vg_waiting_fds are now ready to go, by
965 making enquiries with select(), and mark them as ready. We have to
966 wait for the requesting threads to fall into the the WaitFD state
967 before we can actually finally deliver the results, so this
968 procedure doesn't do that; complete_blocked_syscalls() does it.
969
970 It might seem odd that a thread which has done a blocking syscall
971 is not in WaitFD state; the way this can happen is if it initially
972 becomes WaitFD, but then a signal is delivered to it, so it becomes
973 Runnable for a while. In this case we have to wait for the
974 sighandler to return, whereupon the WaitFD state is resumed, and
975 only at that point can the I/O result be delivered to it. However,
976 this point may be long after the fd is actually ready.
977
978 So, poll_for_ready_fds() merely detects fds which are ready.
979 complete_blocked_syscalls() does the second half of the trick,
980 possibly much later: it delivers the results from ready fds to
981 threads in WaitFD state.
982*/
sewardj9a199dc2002-04-14 13:01:38 +0000983static
sewardje663cb92002-04-12 10:26:32 +0000984void poll_for_ready_fds ( void )
985{
986 vki_ksigset_t saved_procmask;
987 vki_fd_set readfds;
988 vki_fd_set writefds;
989 vki_fd_set exceptfds;
990 struct vki_timeval timeout;
991 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
992 ThreadId tid;
993 Bool rd_ok, wr_ok, ex_ok;
994 Char msg_buf[100];
995
sewardje462e202002-04-13 04:09:07 +0000996 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000997 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000998
sewardje663cb92002-04-12 10:26:32 +0000999 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +00001000 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +00001001 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +00001002 break;
sewardj6072c362002-04-19 14:40:57 +00001003
sewardj5f07b662002-04-23 16:52:51 +00001004 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +00001005 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +00001006 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +00001007 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00001008 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +00001009 continue;
sewardj018f7622002-05-15 21:13:39 +00001010 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +00001011 /* Resume this thread. Set to zero the remaining-time
1012 (second) arg of nanosleep, since it's used up all its
1013 time. */
sewardj018f7622002-05-15 21:13:39 +00001014 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
1015 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +00001016 if (rem != NULL) {
1017 rem->tv_sec = 0;
1018 rem->tv_nsec = 0;
1019 }
1020 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +00001021 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +00001022 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +00001023 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +00001024 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +00001025 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +00001026 t_now);
1027 print_sched_event(tid, msg_buf);
1028 }
sewardje663cb92002-04-12 10:26:32 +00001029 }
1030 }
1031 }
sewardje663cb92002-04-12 10:26:32 +00001032
sewardje462e202002-04-13 04:09:07 +00001033 /* And look for threads waiting on file descriptors which are now
1034 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +00001035 timeout.tv_sec = 0;
1036 timeout.tv_usec = 0;
1037
1038 VKI_FD_ZERO(&readfds);
1039 VKI_FD_ZERO(&writefds);
1040 VKI_FD_ZERO(&exceptfds);
1041 fd_max = -1;
1042 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1043 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1044 continue;
1045 if (vg_waiting_fds[i].ready /* already ready? */)
1046 continue;
1047 fd = vg_waiting_fds[i].fd;
1048 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001049 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001050 if (fd > fd_max)
1051 fd_max = fd;
1052 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001053 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001054 syscall_no = vg_waiting_fds[i].syscall_no;
1055 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001056 case __NR_read:
1057 /* In order to catch timeout events on fds which are
1058 readable and which have been ioctl(TCSETA)'d with a
1059 VTIMEout, we appear to need to ask if the fd is
1060 writable, for some reason. Ask me not why. Since this
1061 is strange and potentially troublesome we only do it if
1062 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001063 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001064 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001065 VKI_FD_SET(fd, &readfds); break;
1066 case __NR_write:
1067 VKI_FD_SET(fd, &writefds); break;
1068 default:
njne427a662002-10-02 11:08:25 +00001069 VG_(core_panic)("poll_for_ready_fds: unexpected syscall");
sewardje663cb92002-04-12 10:26:32 +00001070 /*NOTREACHED*/
1071 break;
1072 }
1073 }
1074
sewardje462e202002-04-13 04:09:07 +00001075 /* Short cut: if no fds are waiting, give up now. */
1076 if (fd_max == -1)
1077 return;
1078
sewardje663cb92002-04-12 10:26:32 +00001079 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1080 getting interrupted. */
1081 VG_(block_all_host_signals)( &saved_procmask );
1082
1083 n_ready = VG_(select)
1084 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1085 if (VG_(is_kerror)(n_ready)) {
1086 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
njne427a662002-10-02 11:08:25 +00001087 VG_(core_panic)("poll_for_ready_fds: select failed?!");
sewardje663cb92002-04-12 10:26:32 +00001088 /*NOTREACHED*/
1089 }
1090
1091 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001092 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001093
1094 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1095
1096 if (n_ready == 0)
1097 return;
1098
1099 /* Inspect all the fds we know about, and handle any completions that
1100 have happened. */
1101 /*
1102 VG_(printf)("\n\n");
1103 for (fd = 0; fd < 100; fd++)
1104 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1105 VG_(printf)("X"); } else { VG_(printf)("."); };
1106 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1107 */
1108
1109 for (fd = 0; fd <= fd_max; fd++) {
1110 rd_ok = VKI_FD_ISSET(fd, &readfds);
1111 wr_ok = VKI_FD_ISSET(fd, &writefds);
1112 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1113
1114 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1115 if (n_ok == 0)
1116 continue;
1117 if (n_ok > 1) {
1118 VG_(printf)("offending fd = %d\n", fd);
njne427a662002-10-02 11:08:25 +00001119 VG_(core_panic)("poll_for_ready_fds: multiple events on fd");
sewardje663cb92002-04-12 10:26:32 +00001120 }
sewardjbc7d8782002-06-30 12:44:54 +00001121
sewardje663cb92002-04-12 10:26:32 +00001122 /* An I/O event completed for fd. Find the thread which
1123 requested this. */
1124 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1125 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1126 continue;
1127 if (vg_waiting_fds[i].fd == fd)
1128 break;
1129 }
1130
1131 /* And a bit more paranoia ... */
1132 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1133
1134 /* Mark the fd as ready. */
1135 vg_assert(! vg_waiting_fds[i].ready);
1136 vg_waiting_fds[i].ready = True;
1137 }
1138}
1139
1140
1141/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001142static
sewardje663cb92002-04-12 10:26:32 +00001143void complete_blocked_syscalls ( void )
1144{
1145 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001146 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001147 ThreadId tid;
1148 Char msg_buf[100];
1149
1150 /* Inspect all the outstanding fds we know about. */
1151
1152 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1153 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1154 continue;
1155 if (! vg_waiting_fds[i].ready)
1156 continue;
1157
1158 fd = vg_waiting_fds[i].fd;
1159 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001160 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001161
1162 /* The thread actually has to be waiting for the I/O event it
1163 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001164 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001165 continue;
1166
1167 /* Ok, actually do it! We can safely use %EAX as the syscall
1168 number, because the speculative call made by
1169 sched_do_syscall() doesn't change %EAX in the case where the
1170 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001171 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001172 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001173
njn25e49d8e72002-09-23 09:36:25 +00001174 pre_res = vg_waiting_fds[i].pre_result;
1175
sewardjbc7d8782002-06-30 12:44:54 +00001176 /* In a rare case pertaining to writing into a pipe, write()
1177 will block when asked to write > 4096 bytes even though the
1178 kernel claims, when asked via select(), that blocking will
1179 not occur for a write on that fd. This can cause deadlocks.
1180 An easy answer is to limit the size of the write to 4096
1181 anyway and hope that the client program's logic can handle
1182 the short write. That shoulds dubious to me, so we don't do
1183 it by default. */
1184 if (syscall_no == __NR_write
1185 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1186 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1187 /* VG_(printf)("truncate write from %d to 4096\n",
1188 VG_(threads)[tid].m_edx ); */
1189 VG_(threads)[tid].m_edx = 4096;
1190 }
1191
sewardje663cb92002-04-12 10:26:32 +00001192 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001193 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001194
1195 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001196 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001197 /* Mark slot as no longer in use. */
1198 vg_waiting_fds[i].fd = -1;
1199 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001200 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001201 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1202 print_sched_event(tid, msg_buf);
1203 }
1204 }
1205}
1206
1207
1208static
sewardj5f07b662002-04-23 16:52:51 +00001209void check_for_pthread_cond_timedwait ( void )
1210{
sewardj51c0aaf2002-04-25 01:32:10 +00001211 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001212 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001213 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001214 continue;
sewardj018f7622002-05-15 21:13:39 +00001215 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001216 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001217 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001218 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001219 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001220 }
sewardj5f07b662002-04-23 16:52:51 +00001221 }
1222}
1223
1224
1225static
sewardje663cb92002-04-12 10:26:32 +00001226void nanosleep_for_a_while ( void )
1227{
1228 Int res;
1229 struct vki_timespec req;
1230 struct vki_timespec rem;
1231 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001232 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001233 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001234 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001235}
1236
1237
1238/* ---------------------------------------------------------------------
1239 The scheduler proper.
1240 ------------------------------------------------------------------ */
1241
1242/* Run user-space threads until either
1243 * Deadlock occurs
1244 * One thread asks to shutdown Valgrind
1245 * The specified number of basic blocks has gone by.
1246*/
1247VgSchedReturnCode VG_(scheduler) ( void )
1248{
1249 ThreadId tid, tid_next;
1250 UInt trc;
1251 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001252 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001253 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001254 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001255
1256 /* For the LRU structures, records when the epoch began. */
1257 ULong lru_epoch_started_at = 0;
1258
1259 /* Start with the root thread. tid in general indicates the
1260 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001261 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001262
1263 /* This is the top level scheduler loop. It falls into three
1264 phases. */
1265 while (True) {
1266
sewardj6072c362002-04-19 14:40:57 +00001267 /* ======================= Phase 0 of 3 =======================
1268 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001269 stage1:
sewardj6072c362002-04-19 14:40:57 +00001270 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001271 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001272
sewardje663cb92002-04-12 10:26:32 +00001273 /* ======================= Phase 1 of 3 =======================
1274 Handle I/O completions and signals. This may change the
1275 status of various threads. Then select a new thread to run,
1276 or declare deadlock, or sleep if there are no runnable
1277 threads but some are blocked on I/O. */
1278
1279 /* Age the LRU structures if an epoch has been completed. */
1280 if (VG_(bbs_done) - lru_epoch_started_at >= VG_BBS_PER_EPOCH) {
1281 lru_epoch_started_at = VG_(bbs_done);
1282 increment_epoch();
1283 }
1284
1285 /* Was a debug-stop requested? */
1286 if (VG_(bbs_to_go) == 0)
1287 goto debug_stop;
1288
1289 /* Do the following loop until a runnable thread is found, or
1290 deadlock is detected. */
1291 while (True) {
1292
1293 /* For stats purposes only. */
1294 VG_(num_scheduling_events_MAJOR) ++;
1295
1296 /* See if any I/O operations which we were waiting for have
1297 completed, and, if so, make runnable the relevant waiting
1298 threads. */
1299 poll_for_ready_fds();
1300 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001301 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001302
1303 /* See if there are any signals which need to be delivered. If
1304 so, choose thread(s) to deliver them to, and build signal
1305 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001306
1307 /* Be careful about delivering signals to a thread waiting
1308 for a mutex. In particular, when the handler is running,
1309 that thread is temporarily apparently-not-waiting for the
1310 mutex, so if it is unlocked by another thread whilst the
1311 handler is running, this thread is not informed. When the
1312 handler returns, the thread resumes waiting on the mutex,
1313 even if, as a result, it has missed the unlocking of it.
1314 Potential deadlock. This sounds all very strange, but the
1315 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001316 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001317 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001318 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001319
1320 /* Try and find a thread (tid) to run. */
1321 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001322 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001323 while (True) {
1324 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001325 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001326 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1327 || VG_(threads)[tid_next].status == VgTs_Sleeping
1328 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1329 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1330 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001331 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001332 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001333 break; /* We can run this one. */
1334 if (tid_next == tid)
1335 break; /* been all the way round */
1336 }
1337 tid = tid_next;
1338
sewardj018f7622002-05-15 21:13:39 +00001339 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001340 /* Found a suitable candidate. Fall out of this loop, so
1341 we can advance to stage 2 of the scheduler: actually
1342 running the thread. */
1343 break;
1344 }
1345
1346 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001347 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001348 /* No runnable threads and no prospect of any appearing
1349 even if we wait for an arbitrary length of time. In
1350 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001351 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001352 return VgSrc_Deadlock;
1353 }
1354
1355 /* At least one thread is in a fd-wait state. Delay for a
1356 while, and go round again, in the hope that eventually a
1357 thread becomes runnable. */
1358 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001359 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001360 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001361 }
1362
1363
1364 /* ======================= Phase 2 of 3 =======================
1365 Wahey! We've finally decided that thread tid is runnable, so
1366 we now do that. Run it for as much of a quanta as possible.
1367 Trivial requests are handled and the thread continues. The
1368 aim is not to do too many of Phase 1 since it is expensive. */
1369
1370 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001371 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001372
njn25e49d8e72002-09-23 09:36:25 +00001373 VG_TRACK( thread_run, tid );
1374
sewardje663cb92002-04-12 10:26:32 +00001375 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1376 that it decrements the counter before testing it for zero, so
1377 that if VG_(dispatch_ctr) is set to N you get at most N-1
1378 iterations. Also this means that VG_(dispatch_ctr) must
1379 exceed zero before entering the innerloop. Also also, the
1380 decrement is done before the bb is actually run, so you
1381 always get at least one decrement even if nothing happens.
1382 */
1383 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1384 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1385 else
1386 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1387
1388 /* ... and remember what we asked for. */
1389 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1390
sewardj1e8cdc92002-04-18 11:37:52 +00001391 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001392 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001393
sewardje663cb92002-04-12 10:26:32 +00001394 /* Actually run thread tid. */
1395 while (True) {
1396
sewardj7e87e382002-05-03 19:09:05 +00001397 VG_(last_run_tid) = tid;
1398
sewardje663cb92002-04-12 10:26:32 +00001399 /* For stats purposes only. */
1400 VG_(num_scheduling_events_MINOR) ++;
1401
1402 if (0)
1403 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1404 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001405# if 0
1406 if (VG_(bbs_done) > 31700000 + 0) {
1407 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001408 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001409 NULL,NULL,NULL);
1410 }
sewardj018f7622002-05-15 21:13:39 +00001411 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001412# endif
sewardje663cb92002-04-12 10:26:32 +00001413
1414 trc = run_thread_for_a_while ( tid );
1415
sewardjb3eef6b2002-05-01 00:05:27 +00001416# if 0
sewardj018f7622002-05-15 21:13:39 +00001417 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001418 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001419 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001420 }
1421# endif
1422
sewardje663cb92002-04-12 10:26:32 +00001423 /* Deal quickly with trivial scheduling events, and resume the
1424 thread. */
1425
1426 if (trc == VG_TRC_INNER_FASTMISS) {
1427 vg_assert(VG_(dispatch_ctr) > 0);
1428
1429 /* Trivial event. Miss in the fast-cache. Do a full
1430 lookup for it. */
1431 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001432 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001433 if (trans_addr == (Addr)0) {
1434 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001435 create_translation_for(
1436 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001437 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001438 if (trans_addr == (Addr)0)
njne427a662002-10-02 11:08:25 +00001439 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
sewardje663cb92002-04-12 10:26:32 +00001440 }
1441 continue; /* with this thread */
1442 }
1443
1444 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001445 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1446 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001447
1448 /* Are we really absolutely totally quitting? */
1449 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1450 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1451 VG_(message)(Vg_DebugMsg,
1452 "__libc_freeres() done; really quitting!");
1453 }
1454 return VgSrc_ExitSyscall;
1455 }
1456
sewardj124ca2a2002-06-20 10:19:38 +00001457 do_client_request(tid);
1458 /* Following the request, we try and continue with the
1459 same thread if still runnable. If not, go back to
1460 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001461 if (VG_(threads)[tid].status == VgTs_Runnable
1462 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001463 continue; /* with this thread */
1464 else
1465 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001466 }
1467
sewardj51c0aaf2002-04-25 01:32:10 +00001468 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1469 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001470 to become non-runnable. One special case: spot the
1471 client doing calls to exit() and take this as the cue
1472 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001473# if 0
1474 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001475 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001476 VG_(printf)("\nBEFORE\n");
1477 for (i = 10; i >= -10; i--)
1478 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1479 }
1480# endif
1481
sewardj1fe7b002002-07-16 01:43:15 +00001482 /* Deal with calling __libc_freeres() at exit. When the
1483 client does __NR_exit, it's exiting for good. So we
1484 then run VG_(__libc_freeres_wrapper). That quits by
1485 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1486 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001487 currently running.
1488
1489 If not valgrinding (cachegrinding, etc) don't do this.
1490 __libc_freeres does some invalid frees which crash
1491 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001492
sewardj858964b2002-10-05 14:15:43 +00001493 if (VG_(threads)[tid].m_eax == __NR_exit) {
1494
1495 /* If __NR_exit, remember the supplied argument. */
njn25e49d8e72002-09-23 09:36:25 +00001496 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1497
sewardj858964b2002-10-05 14:15:43 +00001498 /* Only run __libc_freeres if the skin says it's ok and
1499 it hasn't been overridden with --run-libc-freeres=no
1500 on the command line. */
1501
1502 if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
1503
sewardj00631892002-10-05 15:34:38 +00001504 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001505 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1506 VG_(message)(Vg_DebugMsg,
1507 "Caught __NR_exit; running __libc_freeres()");
1508 }
1509 VG_(nuke_all_threads_except) ( tid );
1510 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1511 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1512 goto stage1; /* party on, dudes (but not for much longer :) */
1513
1514 } else {
1515 /* We won't run __libc_freeres; just exit now. */
sewardj00631892002-10-05 15:34:38 +00001516 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001517 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1518 VG_(message)(Vg_DebugMsg,
1519 "Caught __NR_exit; quitting");
1520 }
1521 return VgSrc_ExitSyscall;
1522 }
1523
sewardjade9d0d2002-07-26 10:52:48 +00001524 }
1525
sewardj858964b2002-10-05 14:15:43 +00001526 /* We've dealt with __NR_exit at this point. */
1527 vg_assert(VG_(threads)[tid].m_eax != __NR_exit);
sewardj7e87e382002-05-03 19:09:05 +00001528
sewardj83798bf2002-05-24 00:11:16 +00001529 /* Trap syscalls to __NR_sched_yield and just have this
1530 thread yield instead. Not essential, just an
1531 optimisation. */
1532 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1533 SET_EAX(tid, 0); /* syscall returns with success */
1534 goto stage1; /* find a new thread to run */
1535 }
1536
sewardj51c0aaf2002-04-25 01:32:10 +00001537 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001538
1539# if 0
1540 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001541 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001542 VG_(printf)("AFTER\n");
1543 for (i = 10; i >= -10; i--)
1544 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1545 }
1546# endif
1547
sewardj77f0fc12002-07-12 01:23:03 +00001548 if (VG_(threads)[tid].status == VgTs_Runnable) {
1549 /* Better do a signal check, since if in a tight loop
1550 with a slow syscall it may be a very long time
1551 before we get back to the main signal check in Stage 1. */
1552 sigs_delivered = VG_(deliver_signals)();
1553 if (sigs_delivered)
1554 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001555 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001556 } else {
1557 goto stage1;
1558 }
sewardj51c0aaf2002-04-25 01:32:10 +00001559 }
1560
sewardjd7fd4d22002-04-24 01:57:27 +00001561 /* It's an event we can't quickly deal with. Give up running
1562 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001563 break;
1564 }
1565
1566 /* ======================= Phase 3 of 3 =======================
1567 Handle non-trivial thread requests, mostly pthread stuff. */
1568
1569 /* Ok, we've fallen out of the dispatcher for a
1570 non-completely-trivial reason. First, update basic-block
1571 counters. */
1572
1573 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1574 vg_assert(done_this_time >= 0);
1575 VG_(bbs_to_go) -= (ULong)done_this_time;
1576 VG_(bbs_done) += (ULong)done_this_time;
1577
1578 if (0 && trc != VG_TRC_INNER_FASTMISS)
1579 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1580 tid, done_this_time, (Int)trc );
1581
1582 if (0 && trc != VG_TRC_INNER_FASTMISS)
1583 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1584 tid, VG_(bbs_done),
1585 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001586
sewardje663cb92002-04-12 10:26:32 +00001587 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001588 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001589
1590 switch (trc) {
1591
sewardje663cb92002-04-12 10:26:32 +00001592 case VG_TRC_INNER_COUNTERZERO:
1593 /* Timeslice is out. Let a new thread be scheduled,
1594 simply by doing nothing, causing us to arrive back at
1595 Phase 1. */
1596 if (VG_(bbs_to_go) == 0) {
1597 goto debug_stop;
1598 }
1599 vg_assert(VG_(dispatch_ctr) == 0);
1600 break;
1601
1602 case VG_TRC_UNRESUMABLE_SIGNAL:
1603 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1604 away. Again, do nothing, so we wind up back at Phase
1605 1, whereupon the signal will be "delivered". */
1606 break;
1607
sewardje663cb92002-04-12 10:26:32 +00001608 default:
1609 VG_(printf)("\ntrc = %d\n", trc);
njne427a662002-10-02 11:08:25 +00001610 VG_(core_panic)("VG_(scheduler), phase 3: "
1611 "unexpected thread return code");
sewardje663cb92002-04-12 10:26:32 +00001612 /* NOTREACHED */
1613 break;
1614
1615 } /* switch (trc) */
1616
1617 /* That completes Phase 3 of 3. Return now to the top of the
1618 main scheduler loop, to Phase 1 of 3. */
1619
1620 } /* top-level scheduler loop */
1621
1622
1623 /* NOTREACHED */
njne427a662002-10-02 11:08:25 +00001624 VG_(core_panic)("scheduler: post-main-loop ?!");
sewardje663cb92002-04-12 10:26:32 +00001625 /* NOTREACHED */
1626
1627 debug_stop:
1628 /* If we exited because of a debug stop, print the translation
1629 of the last block executed -- by translating it again, and
1630 throwing away the result. */
1631 VG_(printf)(
1632 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001633 VG_(translate)( &VG_(threads)[tid],
1634 VG_(threads)[tid].m_eip, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001635 VG_(printf)("\n");
1636 VG_(printf)(
1637 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1638
1639 return VgSrc_BbsDone;
1640}
1641
1642
1643/* ---------------------------------------------------------------------
1644 The pthread implementation.
1645 ------------------------------------------------------------------ */
1646
1647#include <pthread.h>
1648#include <errno.h>
1649
sewardjbf290b92002-05-01 02:28:01 +00001650#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001651 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001652
1653/* /usr/include/bits/pthreadtypes.h:
1654 typedef unsigned long int pthread_t;
1655*/
1656
sewardje663cb92002-04-12 10:26:32 +00001657
sewardj604ec3c2002-04-18 22:38:41 +00001658/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001659 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001660 -------------------------------------------------------- */
1661
sewardj20917d82002-05-28 01:36:45 +00001662/* We've decided to action a cancellation on tid. Make it jump to
1663 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1664 as the arg. */
1665static
1666void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1667{
1668 Char msg_buf[100];
1669 vg_assert(VG_(is_valid_tid)(tid));
1670 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1671 handler -- which is really thread_exit_wrapper() in
1672 vg_libpthread.c. */
1673 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1674 VG_(threads)[tid].m_esp -= 4;
1675 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1676 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1677 VG_(threads)[tid].status = VgTs_Runnable;
1678 /* Make sure we aren't cancelled again whilst handling this
1679 cancellation. */
1680 VG_(threads)[tid].cancel_st = False;
1681 if (VG_(clo_trace_sched)) {
1682 VG_(sprintf)(msg_buf,
1683 "jump to cancellation handler (hdlr = %p)",
1684 VG_(threads)[tid].cancel_pend);
1685 print_sched_event(tid, msg_buf);
1686 }
1687}
1688
1689
1690
sewardjb48e5002002-05-13 00:16:03 +00001691/* Release resources and generally clean up once a thread has finally
1692 disappeared. */
1693static
1694void cleanup_after_thread_exited ( ThreadId tid )
1695{
sewardj89f20fd2002-06-30 10:57:30 +00001696 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001697 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001698 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1699 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001700 /* Its stack is now off-limits */
1701 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1702 VG_(threads)[tid].stack_size );
1703
sewardjb48e5002002-05-13 00:16:03 +00001704 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001705 thread, and get rid of signal handlers specifically arranged for
1706 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001707 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001708 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001709
1710 /* Clean up the waiting_fd table */
1711 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1712 if (vg_waiting_fds[i].tid == tid) {
1713 vg_waiting_fds[i].fd = -1; /* not in use */
1714 }
1715 }
sewardj92a59562002-09-30 00:53:10 +00001716
1717 /* Deallocate its LDT, if it ever had one. */
1718 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1719 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001720}
1721
1722
sewardj20917d82002-05-28 01:36:45 +00001723/* Look for matching pairs of threads waiting for joiners and threads
1724 waiting for joinees. For each such pair copy the return value of
1725 the joinee into the joiner, let the joiner resume and discard the
1726 joinee. */
1727static
1728void maybe_rendezvous_joiners_and_joinees ( void )
1729{
1730 Char msg_buf[100];
1731 void** thread_return;
1732 ThreadId jnr, jee;
1733
1734 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1735 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1736 continue;
1737 jee = VG_(threads)[jnr].joiner_jee_tid;
1738 if (jee == VG_INVALID_THREADID)
1739 continue;
1740 vg_assert(VG_(is_valid_tid)(jee));
1741 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1742 continue;
1743 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1744 joined by ... well, any thread. So let's do it! */
1745
1746 /* Copy return value to where joiner wants it. */
1747 thread_return = VG_(threads)[jnr].joiner_thread_return;
1748 if (thread_return != NULL) {
1749 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001750 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1751 "pthread_join: thread_return",
1752 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001753
sewardj20917d82002-05-28 01:36:45 +00001754 *thread_return = VG_(threads)[jee].joinee_retval;
1755 /* Not really right, since it makes the thread's return value
1756 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001757 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001758 }
1759
1760 /* Joinee is discarded */
1761 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1762 cleanup_after_thread_exited ( jee );
1763 if (VG_(clo_trace_sched)) {
1764 VG_(sprintf)(msg_buf,
1765 "rendezvous with joinee %d. %d resumes, %d exits.",
1766 jee, jnr, jee );
1767 print_sched_event(jnr, msg_buf);
1768 }
1769
1770 /* joiner returns with success */
1771 VG_(threads)[jnr].status = VgTs_Runnable;
1772 SET_EDX(jnr, 0);
1773 }
1774}
1775
1776
sewardjccef2e62002-05-29 19:26:32 +00001777/* Nuke all threads other than tid. POSIX specifies that this should
1778 happen in __NR_exec, and after a __NR_fork() when I am the child,
1779 as POSIX requires. */
1780void VG_(nuke_all_threads_except) ( ThreadId me )
1781{
1782 ThreadId tid;
1783 for (tid = 1; tid < VG_N_THREADS; tid++) {
1784 if (tid == me
1785 || VG_(threads)[tid].status == VgTs_Empty)
1786 continue;
sewardjef037c72002-05-30 00:40:03 +00001787 if (0)
1788 VG_(printf)(
1789 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001790 VG_(threads)[tid].status = VgTs_Empty;
1791 cleanup_after_thread_exited( tid );
1792 }
1793}
1794
1795
sewardj20917d82002-05-28 01:36:45 +00001796/* -----------------------------------------------------------
1797 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1798 -------------------------------------------------------- */
1799
sewardje663cb92002-04-12 10:26:32 +00001800static
sewardj8ad94e12002-05-29 00:10:20 +00001801void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1802{
1803 Int sp;
1804 Char msg_buf[100];
1805 vg_assert(VG_(is_valid_tid)(tid));
1806 sp = VG_(threads)[tid].custack_used;
1807 if (VG_(clo_trace_sched)) {
1808 VG_(sprintf)(msg_buf,
1809 "cleanup_push (fn %p, arg %p) -> slot %d",
1810 cu->fn, cu->arg, sp);
1811 print_sched_event(tid, msg_buf);
1812 }
1813 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1814 if (sp == VG_N_CLEANUPSTACK)
njne427a662002-10-02 11:08:25 +00001815 VG_(core_panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
sewardj8ad94e12002-05-29 00:10:20 +00001816 " Increase and recompile.");
1817 VG_(threads)[tid].custack[sp] = *cu;
1818 sp++;
1819 VG_(threads)[tid].custack_used = sp;
1820 SET_EDX(tid, 0);
1821}
1822
1823
1824static
1825void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1826{
1827 Int sp;
1828 Char msg_buf[100];
1829 vg_assert(VG_(is_valid_tid)(tid));
1830 sp = VG_(threads)[tid].custack_used;
1831 if (VG_(clo_trace_sched)) {
njn36650922002-10-04 09:18:09 +00001832 VG_(sprintf)(msg_buf, "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001833 print_sched_event(tid, msg_buf);
1834 }
1835 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1836 if (sp == 0) {
1837 SET_EDX(tid, -1);
1838 return;
1839 }
1840 sp--;
njn36650922002-10-04 09:18:09 +00001841 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
1842 "cleanup pop", (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001843 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001844 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001845 VG_(threads)[tid].custack_used = sp;
1846 SET_EDX(tid, 0);
1847}
1848
1849
1850static
sewardjff42d1d2002-05-22 13:17:31 +00001851void do_pthread_yield ( ThreadId tid )
1852{
1853 Char msg_buf[100];
1854 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001855 if (VG_(clo_trace_sched)) {
1856 VG_(sprintf)(msg_buf, "yield");
1857 print_sched_event(tid, msg_buf);
1858 }
1859 SET_EDX(tid, 0);
1860}
1861
1862
1863static
sewardj20917d82002-05-28 01:36:45 +00001864void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001865{
sewardj7989d0c2002-05-28 11:00:01 +00001866 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001867 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001868 if (VG_(clo_trace_sched)) {
1869 VG_(sprintf)(msg_buf, "testcancel");
1870 print_sched_event(tid, msg_buf);
1871 }
sewardj20917d82002-05-28 01:36:45 +00001872 if (/* is there a cancellation pending on this thread? */
1873 VG_(threads)[tid].cancel_pend != NULL
1874 && /* is this thread accepting cancellations? */
1875 VG_(threads)[tid].cancel_st) {
1876 /* Ok, let's do the cancellation. */
1877 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001878 } else {
sewardj20917d82002-05-28 01:36:45 +00001879 /* No, we keep going. */
1880 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001881 }
sewardje663cb92002-04-12 10:26:32 +00001882}
1883
1884
1885static
sewardj20917d82002-05-28 01:36:45 +00001886void do__set_cancelstate ( ThreadId tid, Int state )
1887{
1888 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001889 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001890 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001891 if (VG_(clo_trace_sched)) {
1892 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1893 state==PTHREAD_CANCEL_ENABLE
1894 ? "ENABLE"
1895 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1896 print_sched_event(tid, msg_buf);
1897 }
sewardj20917d82002-05-28 01:36:45 +00001898 old_st = VG_(threads)[tid].cancel_st;
1899 if (state == PTHREAD_CANCEL_ENABLE) {
1900 VG_(threads)[tid].cancel_st = True;
1901 } else
1902 if (state == PTHREAD_CANCEL_DISABLE) {
1903 VG_(threads)[tid].cancel_st = False;
1904 } else {
njne427a662002-10-02 11:08:25 +00001905 VG_(core_panic)("do__set_cancelstate");
sewardj20917d82002-05-28 01:36:45 +00001906 }
1907 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1908 : PTHREAD_CANCEL_DISABLE);
1909}
1910
1911
1912static
1913void do__set_canceltype ( ThreadId tid, Int type )
1914{
1915 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001916 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001917 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001918 if (VG_(clo_trace_sched)) {
1919 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1920 type==PTHREAD_CANCEL_ASYNCHRONOUS
1921 ? "ASYNCHRONOUS"
1922 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1923 print_sched_event(tid, msg_buf);
1924 }
sewardj20917d82002-05-28 01:36:45 +00001925 old_ty = VG_(threads)[tid].cancel_ty;
1926 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1927 VG_(threads)[tid].cancel_ty = False;
1928 } else
1929 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001930 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001931 } else {
njne427a662002-10-02 11:08:25 +00001932 VG_(core_panic)("do__set_canceltype");
sewardj20917d82002-05-28 01:36:45 +00001933 }
1934 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1935 : PTHREAD_CANCEL_ASYNCHRONOUS);
1936}
1937
1938
sewardj7989d0c2002-05-28 11:00:01 +00001939/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001940static
sewardj7989d0c2002-05-28 11:00:01 +00001941void do__set_or_get_detach ( ThreadId tid,
1942 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001943{
sewardj7989d0c2002-05-28 11:00:01 +00001944 ThreadId i;
1945 Char msg_buf[100];
1946 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1947 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001948 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001949 if (VG_(clo_trace_sched)) {
1950 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1951 what==0 ? "not-detached" : (
1952 what==1 ? "detached" : (
1953 what==2 ? "fetch old value" : "???")),
1954 det );
1955 print_sched_event(tid, msg_buf);
1956 }
1957
1958 if (!VG_(is_valid_tid)(det)) {
1959 SET_EDX(tid, -1);
1960 return;
1961 }
1962
sewardj20917d82002-05-28 01:36:45 +00001963 switch (what) {
1964 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001965 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001966 return;
sewardj7989d0c2002-05-28 11:00:01 +00001967 case 1: /* set detached. If someone is in a join-wait for det,
1968 do not detach. */
1969 for (i = 1; i < VG_N_THREADS; i++) {
1970 if (VG_(threads)[i].status == VgTs_WaitJoinee
1971 && VG_(threads)[i].joiner_jee_tid == det) {
1972 SET_EDX(tid, 0);
1973 if (VG_(clo_trace_sched)) {
1974 VG_(sprintf)(msg_buf,
njn9b6d34e2002-10-15 08:48:08 +00001975 "tid %d not detached because %d in join-wait for it",
sewardj7989d0c2002-05-28 11:00:01 +00001976 det, i);
1977 print_sched_event(tid, msg_buf);
1978 }
1979 return;
1980 }
1981 }
1982 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001983 SET_EDX(tid, 0);
1984 return;
1985 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001986 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001987 SET_EDX(tid, 0);
1988 return;
1989 default:
njne427a662002-10-02 11:08:25 +00001990 VG_(core_panic)("do__set_or_get_detach");
sewardj20917d82002-05-28 01:36:45 +00001991 }
1992}
1993
1994
1995static
1996void do__set_cancelpend ( ThreadId tid,
1997 ThreadId cee,
1998 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001999{
2000 Char msg_buf[100];
2001
sewardj20917d82002-05-28 01:36:45 +00002002 vg_assert(VG_(is_valid_tid)(tid));
2003 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2004
sewardj7989d0c2002-05-28 11:00:01 +00002005 if (!VG_(is_valid_tid)(cee)) {
2006 if (VG_(clo_trace_sched)) {
2007 VG_(sprintf)(msg_buf,
2008 "set_cancelpend for invalid tid %d", cee);
2009 print_sched_event(tid, msg_buf);
2010 }
njn25e49d8e72002-09-23 09:36:25 +00002011 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002012 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00002013 SET_EDX(tid, -VKI_ESRCH);
2014 return;
2015 }
sewardj20917d82002-05-28 01:36:45 +00002016
2017 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
2018
2019 if (VG_(clo_trace_sched)) {
2020 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002021 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00002022 cancelpend_hdlr, tid);
2023 print_sched_event(cee, msg_buf);
2024 }
2025
2026 /* Thread doing the cancelling returns with success. */
2027 SET_EDX(tid, 0);
2028
2029 /* Perhaps we can nuke the cancellee right now? */
2030 do__testcancel(cee);
2031}
2032
2033
2034static
2035void do_pthread_join ( ThreadId tid,
2036 ThreadId jee, void** thread_return )
2037{
2038 Char msg_buf[100];
2039 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00002040 /* jee, the joinee, is the thread specified as an arg in thread
2041 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00002042 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00002043 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002044
2045 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002046 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002047 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002048 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002049 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002050 return;
2051 }
2052
sewardj20917d82002-05-28 01:36:45 +00002053 /* Flush any completed pairs, so as to make sure what we're looking
2054 at is up-to-date. */
2055 maybe_rendezvous_joiners_and_joinees();
2056
2057 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002058 if (jee < 0
2059 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002060 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002061 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002062 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002063 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002064 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002065 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002066 return;
2067 }
2068
sewardj20917d82002-05-28 01:36:45 +00002069 /* Is anyone else already in a join-wait for jee? */
2070 for (i = 1; i < VG_N_THREADS; i++) {
2071 if (i == tid) continue;
2072 if (VG_(threads)[i].status == VgTs_WaitJoinee
2073 && VG_(threads)[i].joiner_jee_tid == jee) {
2074 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002075 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002076 "pthread_join: another thread already "
2077 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002078 SET_EDX(tid, EINVAL);
2079 VG_(threads)[tid].status = VgTs_Runnable;
2080 return;
2081 }
sewardje663cb92002-04-12 10:26:32 +00002082 }
2083
sewardj20917d82002-05-28 01:36:45 +00002084 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002085 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002086 VG_(threads)[tid].joiner_thread_return = thread_return;
2087 VG_(threads)[tid].joiner_jee_tid = jee;
2088
2089 /* Look for matching joiners and joinees and do the right thing. */
2090 maybe_rendezvous_joiners_and_joinees();
2091
2092 /* Return value is irrelevant since this this thread becomes
2093 non-runnable. maybe_resume_joiner() will cause it to return the
2094 right value when it resumes. */
2095
sewardj8937c812002-04-12 20:12:20 +00002096 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002097 VG_(sprintf)(msg_buf,
2098 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002099 print_sched_event(tid, msg_buf);
2100 }
sewardje663cb92002-04-12 10:26:32 +00002101}
2102
2103
sewardj20917d82002-05-28 01:36:45 +00002104/* ( void* ): calling thread waits for joiner and returns the void* to
2105 it. This is one of two ways in which a thread can finally exit --
2106 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002107static
sewardj20917d82002-05-28 01:36:45 +00002108void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002109{
sewardj20917d82002-05-28 01:36:45 +00002110 Char msg_buf[100];
2111 vg_assert(VG_(is_valid_tid)(tid));
2112 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2113 if (VG_(clo_trace_sched)) {
2114 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002115 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002116 print_sched_event(tid, msg_buf);
2117 }
2118 VG_(threads)[tid].status = VgTs_WaitJoiner;
2119 VG_(threads)[tid].joinee_retval = retval;
2120 maybe_rendezvous_joiners_and_joinees();
2121}
2122
2123
2124/* ( no-args ): calling thread disappears from the system forever.
2125 Reclaim resources. */
2126static
2127void do__quit ( ThreadId tid )
2128{
2129 Char msg_buf[100];
2130 vg_assert(VG_(is_valid_tid)(tid));
2131 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2132 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2133 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002134 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002135 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002136 print_sched_event(tid, msg_buf);
2137 }
2138 /* Return value is irrelevant; this thread will not get
2139 rescheduled. */
2140}
2141
2142
2143/* Should never be entered. If it is, will be on the simulated
2144 CPU. */
2145static
2146void do__apply_in_new_thread_bogusRA ( void )
2147{
njne427a662002-10-02 11:08:25 +00002148 VG_(core_panic)("do__apply_in_new_thread_bogusRA");
sewardj20917d82002-05-28 01:36:45 +00002149}
2150
2151/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2152 MUST NOT return -- ever. Eventually it will do either __QUIT or
2153 __WAIT_JOINER. Return the child tid to the parent. */
2154static
2155void do__apply_in_new_thread ( ThreadId parent_tid,
2156 void* (*fn)(void *),
2157 void* arg )
2158{
sewardje663cb92002-04-12 10:26:32 +00002159 Addr new_stack;
2160 UInt new_stk_szb;
2161 ThreadId tid;
2162 Char msg_buf[100];
2163
2164 /* Paranoia ... */
2165 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2166
sewardj018f7622002-05-15 21:13:39 +00002167 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002168
sewardj1e8cdc92002-04-18 11:37:52 +00002169 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002170
2171 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002172 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002173 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002174
2175 /* Copy the parent's CPU state into the child's, in a roundabout
2176 way (via baseBlock). */
2177 VG_(load_thread_state)(parent_tid);
2178 VG_(save_thread_state)(tid);
2179
2180 /* Consider allocating the child a stack, if the one it already has
2181 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002182 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002183
sewardj018f7622002-05-15 21:13:39 +00002184 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002185 /* Again, for good measure :) We definitely don't want to be
2186 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002187 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002188 /* for now, we don't handle the case of anything other than
2189 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002190 vg_assert(VG_(threads)[tid].stack_size == 0);
2191 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002192 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2193 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002194 VG_(threads)[tid].stack_base = new_stack;
2195 VG_(threads)[tid].stack_size = new_stk_szb;
2196 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002197 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002198 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002199 }
sewardj1e8cdc92002-04-18 11:37:52 +00002200
njn25e49d8e72002-09-23 09:36:25 +00002201 /* Having got memory to hold the thread's stack:
2202 - set %esp as base + size
2203 - mark everything below %esp inaccessible
2204 - mark redzone at stack end inaccessible
2205 */
2206 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2207 + VG_(threads)[tid].stack_size
2208 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002209
njn25e49d8e72002-09-23 09:36:25 +00002210 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2211 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2212 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2213 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002214
njn25e49d8e72002-09-23 09:36:25 +00002215 /* push two args */
2216 VG_(threads)[tid].m_esp -= 8;
2217 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2218 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2219 "new thread: stack",
2220 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2221
2222 /* push arg and (bogus) return address */
2223 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002224 * (UInt*)(VG_(threads)[tid].m_esp)
2225 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002226
njn25e49d8e72002-09-23 09:36:25 +00002227 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002228
2229 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002230 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002231
sewardj8937c812002-04-12 20:12:20 +00002232 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002233 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002234 print_sched_event(tid, msg_buf);
2235 }
2236
sewardj20917d82002-05-28 01:36:45 +00002237 /* Create new thread with default attrs:
2238 deferred cancellation, not detached
2239 */
2240 mostly_clear_thread_record(tid);
2241 VG_(threads)[tid].status = VgTs_Runnable;
sewardj5f07b662002-04-23 16:52:51 +00002242
sewardj018f7622002-05-15 21:13:39 +00002243 /* We inherit our parent's signal mask. */
2244 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002245 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002246
sewardj92a59562002-09-30 00:53:10 +00002247 /* We inherit our parent's LDT. */
2248 if (VG_(threads)[parent_tid].ldt == NULL) {
2249 /* We hope this is the common case. */
2250 VG_(threads)[tid].ldt = NULL;
2251 } else {
2252 /* No luck .. we have to take a copy of the parent's. */
2253 VG_(threads)[tid].ldt
2254 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2255 }
2256
sewardj20917d82002-05-28 01:36:45 +00002257 /* return child's tid to parent */
2258 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002259}
2260
2261
sewardj604ec3c2002-04-18 22:38:41 +00002262/* -----------------------------------------------------------
2263 MUTEXes
2264 -------------------------------------------------------- */
2265
sewardj604ec3c2002-04-18 22:38:41 +00002266/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002267 typedef struct
2268 {
2269 int __m_reserved; -- Reserved for future use
2270 int __m_count; -- Depth of recursive locking
2271 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2272 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2273 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2274 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002275
sewardj6072c362002-04-19 14:40:57 +00002276 #define PTHREAD_MUTEX_INITIALIZER \
2277 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2278 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2279 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2280 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2281 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2282 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2283 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002284
sewardj6072c362002-04-19 14:40:57 +00002285 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002286
sewardj6072c362002-04-19 14:40:57 +00002287 __m_kind never changes and indicates whether or not it is recursive.
2288
2289 __m_count indicates the lock count; if 0, the mutex is not owned by
2290 anybody.
2291
2292 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2293 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2294 statically initialised mutexes correctly appear
2295 to belong to nobody.
2296
2297 In summary, a not-in-use mutex is distinguised by having __m_owner
2298 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2299 conditions holds, the other should too.
2300
2301 There is no linked list of threads waiting for this mutex. Instead
2302 a thread in WaitMX state points at the mutex with its waited_on_mx
2303 field. This makes _unlock() inefficient, but simple to implement the
2304 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002305
sewardj604ec3c2002-04-18 22:38:41 +00002306 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002307 deals with that for us.
2308*/
sewardje663cb92002-04-12 10:26:32 +00002309
sewardj3b5d8862002-04-20 13:53:23 +00002310/* Helper fns ... */
2311static
2312void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2313 Char* caller )
2314{
2315 Int i;
2316 Char msg_buf[100];
2317
2318 /* Find some arbitrary thread waiting on this mutex, and make it
2319 runnable. If none are waiting, mark the mutex as not held. */
2320 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002321 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002322 continue;
sewardj018f7622002-05-15 21:13:39 +00002323 if (VG_(threads)[i].status == VgTs_WaitMX
2324 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002325 break;
2326 }
2327
sewardj0af43bc2002-10-22 04:30:35 +00002328 VG_TRACK( post_mutex_unlock, (ThreadId)mutex->__m_owner, mutex );
2329
sewardj3b5d8862002-04-20 13:53:23 +00002330 vg_assert(i <= VG_N_THREADS);
2331 if (i == VG_N_THREADS) {
2332 /* Nobody else is waiting on it. */
2333 mutex->__m_count = 0;
2334 mutex->__m_owner = VG_INVALID_THREADID;
2335 } else {
2336 /* Notionally transfer the hold to thread i, whose
2337 pthread_mutex_lock() call now returns with 0 (success). */
2338 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002339 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002340 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002341 VG_(threads)[i].status = VgTs_Runnable;
2342 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002343 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002344
sewardj0af43bc2002-10-22 04:30:35 +00002345 VG_TRACK( post_mutex_lock, (ThreadId)i, mutex);
2346
sewardj3b5d8862002-04-20 13:53:23 +00002347 if (VG_(clo_trace_pthread_level) >= 1) {
2348 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2349 caller, mutex );
2350 print_pthread_event(i, msg_buf);
2351 }
2352 }
2353}
2354
sewardje663cb92002-04-12 10:26:32 +00002355
2356static
sewardj30671ff2002-04-21 00:13:57 +00002357void do_pthread_mutex_lock( ThreadId tid,
2358 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002359 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002360{
sewardj30671ff2002-04-21 00:13:57 +00002361 Char msg_buf[100];
2362 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002363 = is_trylock ? "pthread_mutex_trylock"
2364 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002365
sewardj604ec3c2002-04-18 22:38:41 +00002366 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002367 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002368 print_pthread_event(tid, msg_buf);
2369 }
2370
2371 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002372 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002373 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002374
2375 /* POSIX doesn't mandate this, but for sanity ... */
2376 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002377 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002378 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002379 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002380 return;
2381 }
2382
sewardj604ec3c2002-04-18 22:38:41 +00002383 /* More paranoia ... */
2384 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002385# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002386 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002387 case PTHREAD_MUTEX_ADAPTIVE_NP:
2388# endif
sewardja1679dd2002-05-10 22:31:40 +00002389# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002390 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002391# endif
sewardj604ec3c2002-04-18 22:38:41 +00002392 case PTHREAD_MUTEX_RECURSIVE_NP:
2393 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002394 if (mutex->__m_count >= 0) break;
2395 /* else fall thru */
2396 default:
njn25e49d8e72002-09-23 09:36:25 +00002397 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002398 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002399 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002400 return;
sewardje663cb92002-04-12 10:26:32 +00002401 }
2402
sewardj604ec3c2002-04-18 22:38:41 +00002403 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002404
sewardjb48e5002002-05-13 00:16:03 +00002405 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002406
2407 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002408 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002409 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002410 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002411 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002412 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002413 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002414 if (0)
2415 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2416 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002417 return;
2418 } else {
sewardj30671ff2002-04-21 00:13:57 +00002419 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002420 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002421 else
sewardjc3bd5f52002-05-01 03:24:23 +00002422 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002423 return;
2424 }
2425 } else {
sewardj6072c362002-04-19 14:40:57 +00002426 /* Someone else has it; we have to wait. Mark ourselves
2427 thusly. */
sewardj05553872002-04-20 20:53:17 +00002428 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002429 if (is_trylock) {
2430 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002431 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002432 } else {
sewardj018f7622002-05-15 21:13:39 +00002433 VG_(threads)[tid].status = VgTs_WaitMX;
2434 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002435 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002436 if (VG_(clo_trace_pthread_level) >= 1) {
2437 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2438 caller, mutex );
2439 print_pthread_event(tid, msg_buf);
2440 }
2441 }
sewardje663cb92002-04-12 10:26:32 +00002442 return;
2443 }
sewardjf8f819e2002-04-17 23:21:37 +00002444
sewardje663cb92002-04-12 10:26:32 +00002445 } else {
sewardj6072c362002-04-19 14:40:57 +00002446 /* Nobody owns it. Sanity check ... */
2447 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjf8f819e2002-04-17 23:21:37 +00002448 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002449 mutex->__m_count = 1;
2450 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002451
2452 VG_TRACK( post_mutex_lock, tid, mutex);
2453
sewardje663cb92002-04-12 10:26:32 +00002454 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002455 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002456 }
sewardjf8f819e2002-04-17 23:21:37 +00002457
sewardje663cb92002-04-12 10:26:32 +00002458}
2459
2460
2461static
2462void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002463 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002464{
sewardj3b5d8862002-04-20 13:53:23 +00002465 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002466
sewardj45b4b372002-04-16 22:50:32 +00002467 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002468 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002469 print_pthread_event(tid, msg_buf);
2470 }
2471
sewardj604ec3c2002-04-18 22:38:41 +00002472 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002473 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002474 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002475
2476 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002477 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002478 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002479 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002480 return;
2481 }
2482
2483 /* More paranoia ... */
2484 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002485# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002486 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002487 case PTHREAD_MUTEX_ADAPTIVE_NP:
2488# endif
sewardja1679dd2002-05-10 22:31:40 +00002489# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002490 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002491# endif
sewardj604ec3c2002-04-18 22:38:41 +00002492 case PTHREAD_MUTEX_RECURSIVE_NP:
2493 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002494 if (mutex->__m_count >= 0) break;
2495 /* else fall thru */
2496 default:
njn25e49d8e72002-09-23 09:36:25 +00002497 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002498 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002499 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002500 return;
2501 }
sewardje663cb92002-04-12 10:26:32 +00002502
2503 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002504 if (mutex->__m_count == 0) {
2505 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002506 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002507 "pthread_mutex_unlock: mutex is not locked");
2508 SET_EDX(tid, EPERM);
2509 return;
2510 }
2511
2512 if ((ThreadId)mutex->__m_owner != tid) {
2513 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002514 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002515 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002516 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002517 return;
2518 }
2519
sewardjf8f819e2002-04-17 23:21:37 +00002520 /* If it's a multiply-locked recursive mutex, just decrement the
2521 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002522 if (mutex->__m_count > 1) {
2523 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2524 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002525 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002526 return;
2527 }
2528
sewardj604ec3c2002-04-18 22:38:41 +00002529 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002530 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002531 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002532 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002533
sewardj3b5d8862002-04-20 13:53:23 +00002534 /* Release at max one thread waiting on this mutex. */
2535 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002536
sewardj3b5d8862002-04-20 13:53:23 +00002537 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002538 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002539}
2540
2541
sewardj6072c362002-04-19 14:40:57 +00002542/* -----------------------------------------------------------
2543 CONDITION VARIABLES
2544 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002545
sewardj6072c362002-04-19 14:40:57 +00002546/* The relevant native types are as follows:
2547 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002548
sewardj6072c362002-04-19 14:40:57 +00002549 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2550 typedef struct
2551 {
2552 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2553 _pthread_descr __c_waiting; -- Threads waiting on this condition
2554 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002555
sewardj6072c362002-04-19 14:40:57 +00002556 -- Attribute for conditionally variables.
2557 typedef struct
2558 {
2559 int __dummy;
2560 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002561
sewardj6072c362002-04-19 14:40:57 +00002562 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002563
sewardj3b5d8862002-04-20 13:53:23 +00002564 We don't use any fields of pthread_cond_t for anything at all.
2565 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002566
2567 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002568 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002569
sewardj77e466c2002-04-14 02:29:29 +00002570
sewardj5f07b662002-04-23 16:52:51 +00002571static
2572void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2573{
2574 Char msg_buf[100];
2575 pthread_mutex_t* mx;
2576 pthread_cond_t* cv;
2577
sewardjb48e5002002-05-13 00:16:03 +00002578 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002579 && VG_(threads)[tid].status == VgTs_WaitCV
2580 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2581 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002582 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002583 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002584 vg_assert(cv != NULL);
2585
2586 if (mx->__m_owner == VG_INVALID_THREADID) {
2587 /* Currently unheld; hand it out to thread tid. */
2588 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002589 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002590 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002591 VG_(threads)[tid].associated_cv = NULL;
2592 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002593 mx->__m_owner = (_pthread_descr)tid;
2594 mx->__m_count = 1;
2595
sewardj0af43bc2002-10-22 04:30:35 +00002596 VG_TRACK( post_mutex_lock, tid, mx );
2597
sewardj5f07b662002-04-23 16:52:51 +00002598 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002599 VG_(sprintf)(msg_buf,
2600 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2601 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002602 print_pthread_event(tid, msg_buf);
2603 }
2604 } else {
2605 /* Currently held. Make thread tid be blocked on it. */
2606 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002607 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002608 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002609 VG_(threads)[tid].associated_cv = NULL;
2610 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002611 if (VG_(clo_trace_pthread_level) >= 1) {
2612 VG_(sprintf)(msg_buf,
2613 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2614 cv, mx );
2615 print_pthread_event(tid, msg_buf);
2616 }
2617
2618 }
2619}
2620
2621
sewardj3b5d8862002-04-20 13:53:23 +00002622static
2623void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2624 Int n_to_release,
2625 Char* caller )
2626{
2627 Int i;
2628 Char msg_buf[100];
2629 pthread_mutex_t* mx;
2630
2631 while (True) {
2632 if (n_to_release == 0)
2633 return;
2634
2635 /* Find a thread waiting on this CV. */
2636 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002637 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002638 continue;
sewardj018f7622002-05-15 21:13:39 +00002639 if (VG_(threads)[i].status == VgTs_WaitCV
2640 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002641 break;
2642 }
2643 vg_assert(i <= VG_N_THREADS);
2644
2645 if (i == VG_N_THREADS) {
2646 /* Nobody else is waiting on it. */
2647 return;
2648 }
2649
sewardj018f7622002-05-15 21:13:39 +00002650 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002651 vg_assert(mx != NULL);
2652
2653 if (mx->__m_owner == VG_INVALID_THREADID) {
2654 /* Currently unheld; hand it out to thread i. */
2655 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002656 VG_(threads)[i].status = VgTs_Runnable;
2657 VG_(threads)[i].associated_cv = NULL;
2658 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002659 mx->__m_owner = (_pthread_descr)i;
2660 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002661 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002662
sewardj0af43bc2002-10-22 04:30:35 +00002663 VG_TRACK( post_mutex_lock, i, mx );
2664
sewardj3b5d8862002-04-20 13:53:23 +00002665 if (VG_(clo_trace_pthread_level) >= 1) {
2666 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2667 caller, cond, mx );
2668 print_pthread_event(i, msg_buf);
2669 }
2670
2671 } else {
2672 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002673 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002674 VG_(threads)[i].status = VgTs_WaitMX;
2675 VG_(threads)[i].associated_cv = NULL;
2676 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002677 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002678
2679 if (VG_(clo_trace_pthread_level) >= 1) {
2680 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2681 caller, cond, mx );
2682 print_pthread_event(i, msg_buf);
2683 }
2684
2685 }
2686
2687 n_to_release--;
2688 }
2689}
2690
2691
2692static
2693void do_pthread_cond_wait ( ThreadId tid,
2694 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002695 pthread_mutex_t *mutex,
2696 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002697{
2698 Char msg_buf[100];
2699
sewardj5f07b662002-04-23 16:52:51 +00002700 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2701 ms_end is the ending millisecond. */
2702
sewardj3b5d8862002-04-20 13:53:23 +00002703 /* pre: mutex should be a valid mutex and owned by tid. */
2704 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002705 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2706 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002707 print_pthread_event(tid, msg_buf);
2708 }
2709
2710 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002711 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002712 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002713
2714 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002715 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002716 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002717 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002718 return;
2719 }
2720
2721 /* More paranoia ... */
2722 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002723# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002724 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002725 case PTHREAD_MUTEX_ADAPTIVE_NP:
2726# endif
sewardja1679dd2002-05-10 22:31:40 +00002727# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002728 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002729# endif
sewardj3b5d8862002-04-20 13:53:23 +00002730 case PTHREAD_MUTEX_RECURSIVE_NP:
2731 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002732 if (mutex->__m_count >= 0) break;
2733 /* else fall thru */
2734 default:
njn25e49d8e72002-09-23 09:36:25 +00002735 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002736 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002737 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002738 return;
2739 }
2740
2741 /* Barf if we don't currently hold the mutex. */
2742 if (mutex->__m_count == 0 /* nobody holds it */
2743 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002744 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002745 "pthread_cond_wait/timedwait: mutex is unlocked "
2746 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002747 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002748 return;
2749 }
2750
2751 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002752 VG_(threads)[tid].status = VgTs_WaitCV;
2753 VG_(threads)[tid].associated_cv = cond;
2754 VG_(threads)[tid].associated_mx = mutex;
2755 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002756
2757 if (VG_(clo_trace_pthread_level) >= 1) {
2758 VG_(sprintf)(msg_buf,
2759 "pthread_cond_wait cv %p, mx %p: BLOCK",
2760 cond, mutex );
2761 print_pthread_event(tid, msg_buf);
2762 }
2763
2764 /* Release the mutex. */
2765 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2766}
2767
2768
2769static
2770void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2771 Bool broadcast,
2772 pthread_cond_t *cond )
2773{
2774 Char msg_buf[100];
2775 Char* caller
2776 = broadcast ? "pthread_cond_broadcast"
2777 : "pthread_cond_signal ";
2778
2779 if (VG_(clo_trace_pthread_level) >= 2) {
2780 VG_(sprintf)(msg_buf, "%s cv %p ...",
2781 caller, cond );
2782 print_pthread_event(tid, msg_buf);
2783 }
2784
2785 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002786 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002787 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002788
2789 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002790 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002791 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002792 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002793 return;
2794 }
2795
2796 release_N_threads_waiting_on_cond (
2797 cond,
2798 broadcast ? VG_N_THREADS : 1,
2799 caller
2800 );
2801
sewardjc3bd5f52002-05-01 03:24:23 +00002802 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002803}
2804
sewardj77e466c2002-04-14 02:29:29 +00002805
sewardj5f07b662002-04-23 16:52:51 +00002806/* -----------------------------------------------------------
2807 THREAD SPECIFIC DATA
2808 -------------------------------------------------------- */
2809
2810static __inline__
2811Bool is_valid_key ( ThreadKey k )
2812{
2813 /* k unsigned; hence no < 0 check */
2814 if (k >= VG_N_THREAD_KEYS) return False;
2815 if (!vg_thread_keys[k].inuse) return False;
2816 return True;
2817}
2818
sewardj00a66b12002-10-12 16:42:35 +00002819
2820/* Return in %EDX a value of 1 if the key is valid, else 0. */
2821static
2822void do_pthread_key_validate ( ThreadId tid,
2823 pthread_key_t key )
2824{
2825 Char msg_buf[100];
2826
2827 if (VG_(clo_trace_pthread_level) >= 1) {
2828 VG_(sprintf)(msg_buf, "pthread_key_validate key %p",
2829 key );
2830 print_pthread_event(tid, msg_buf);
2831 }
2832
2833 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
2834 vg_assert(VG_(is_valid_tid)(tid)
2835 && VG_(threads)[tid].status == VgTs_Runnable);
2836
2837 if (is_valid_key((ThreadKey)key)) {
2838 SET_EDX(tid, 1);
2839 } else {
2840 SET_EDX(tid, 0);
2841 }
2842}
2843
2844
sewardj5f07b662002-04-23 16:52:51 +00002845static
2846void do_pthread_key_create ( ThreadId tid,
2847 pthread_key_t* key,
2848 void (*destructor)(void*) )
2849{
2850 Int i;
2851 Char msg_buf[100];
2852
2853 if (VG_(clo_trace_pthread_level) >= 1) {
2854 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2855 key, destructor );
2856 print_pthread_event(tid, msg_buf);
2857 }
2858
2859 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002860 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002861 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002862
2863 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2864 if (!vg_thread_keys[i].inuse)
2865 break;
2866
2867 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002868 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002869 return;
2870 */
njne427a662002-10-02 11:08:25 +00002871 VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2872 " increase and recompile");
sewardj5f07b662002-04-23 16:52:51 +00002873 }
2874
sewardj870497a2002-05-29 01:06:47 +00002875 vg_thread_keys[i].inuse = True;
2876 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002877
sewardj5a3798b2002-06-04 23:24:22 +00002878 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002879 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2880 "pthread_key_create: key",
2881 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002882 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002883 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002884
2885 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002886}
2887
2888
2889static
2890void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2891{
2892 Char msg_buf[100];
2893 if (VG_(clo_trace_pthread_level) >= 1) {
2894 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2895 key );
2896 print_pthread_event(tid, msg_buf);
2897 }
2898
sewardjb48e5002002-05-13 00:16:03 +00002899 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002900 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002901
2902 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002903 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002904 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002905 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002906 return;
2907 }
2908
2909 vg_thread_keys[key].inuse = False;
sewardj00a66b12002-10-12 16:42:35 +00002910 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002911}
2912
2913
sewardj00a66b12002-10-12 16:42:35 +00002914/* Get the .specific_ptr for a thread. Return 1 if the thread-slot
2915 isn't in use, so that client-space can scan all thread slots. 1
2916 cannot be confused with NULL or a legitimately-aligned specific_ptr
2917 value. */
sewardj5f07b662002-04-23 16:52:51 +00002918static
sewardj00a66b12002-10-12 16:42:35 +00002919void do_pthread_getspecific_ptr ( ThreadId tid )
sewardj5f07b662002-04-23 16:52:51 +00002920{
sewardj00a66b12002-10-12 16:42:35 +00002921 void** specifics_ptr;
2922 Char msg_buf[100];
2923
sewardj5f07b662002-04-23 16:52:51 +00002924 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002925 VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
sewardj5f07b662002-04-23 16:52:51 +00002926 print_pthread_event(tid, msg_buf);
2927 }
2928
sewardj00a66b12002-10-12 16:42:35 +00002929 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardj5f07b662002-04-23 16:52:51 +00002930
sewardj00a66b12002-10-12 16:42:35 +00002931 if (VG_(threads)[tid].status == VgTs_Empty) {
2932 SET_EDX(tid, 1);
sewardj5f07b662002-04-23 16:52:51 +00002933 return;
2934 }
2935
sewardj00a66b12002-10-12 16:42:35 +00002936 specifics_ptr = VG_(threads)[tid].specifics_ptr;
2937 vg_assert(specifics_ptr == NULL
2938 || IS_ALIGNED4_ADDR(specifics_ptr));
2939
2940 SET_EDX(tid, (UInt)specifics_ptr);
sewardj5f07b662002-04-23 16:52:51 +00002941}
2942
2943
2944static
sewardj00a66b12002-10-12 16:42:35 +00002945void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
sewardj5f07b662002-04-23 16:52:51 +00002946{
2947 Char msg_buf[100];
2948 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002949 VG_(sprintf)(msg_buf, "pthread_setspecific_ptr ptr %p",
2950 ptr );
sewardj5f07b662002-04-23 16:52:51 +00002951 print_pthread_event(tid, msg_buf);
2952 }
2953
sewardjb48e5002002-05-13 00:16:03 +00002954 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002955 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002956
sewardj00a66b12002-10-12 16:42:35 +00002957 VG_(threads)[tid].specifics_ptr = ptr;
sewardjc3bd5f52002-05-01 03:24:23 +00002958 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002959}
2960
2961
sewardj870497a2002-05-29 01:06:47 +00002962/* Helper for calling destructors at thread exit. If key is valid,
2963 copy the thread's specific value into cu->arg and put the *key*'s
2964 destructor fn address in cu->fn. Then return 0 to the caller.
2965 Otherwise return non-zero to the caller. */
2966static
2967void do__get_key_destr_and_spec ( ThreadId tid,
2968 pthread_key_t key,
2969 CleanupEntry* cu )
2970{
2971 Char msg_buf[100];
2972 if (VG_(clo_trace_pthread_level) >= 1) {
2973 VG_(sprintf)(msg_buf,
2974 "get_key_destr_and_arg (key = %d)", key );
2975 print_pthread_event(tid, msg_buf);
2976 }
2977 vg_assert(VG_(is_valid_tid)(tid));
2978 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00002979
sewardj870497a2002-05-29 01:06:47 +00002980 if (!vg_thread_keys[key].inuse) {
2981 SET_EDX(tid, -1);
2982 return;
2983 }
njn36650922002-10-04 09:18:09 +00002984 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
sewardj00a66b12002-10-12 16:42:35 +00002985 "get_key_destr_and_spec: cu", (Addr)cu,
njn36650922002-10-04 09:18:09 +00002986 sizeof(CleanupEntry) );
sewardj00a66b12002-10-12 16:42:35 +00002987
sewardj870497a2002-05-29 01:06:47 +00002988 cu->fn = vg_thread_keys[key].destructor;
sewardj00a66b12002-10-12 16:42:35 +00002989 if (VG_(threads)[tid].specifics_ptr == NULL) {
2990 cu->arg = NULL;
2991 } else {
2992 VG_TRACK( pre_mem_read, Vg_CorePThread, & VG_(threads)[tid],
2993 "get_key_destr_and_spec: key",
2994 (Addr)(&VG_(threads)[tid].specifics_ptr[key]),
2995 sizeof(void*) );
2996 cu->arg = VG_(threads)[tid].specifics_ptr[key];
2997 }
2998
njn25e49d8e72002-09-23 09:36:25 +00002999 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00003000 SET_EDX(tid, 0);
3001}
3002
3003
sewardjb48e5002002-05-13 00:16:03 +00003004/* ---------------------------------------------------
3005 SIGNALS
3006 ------------------------------------------------ */
3007
3008/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00003009 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
3010 for OK and 1 for some kind of addressing error, which the
3011 vg_libpthread.c routine turns into return values 0 and EFAULT
3012 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00003013static
3014void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00003015 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00003016 vki_ksigset_t* newmask,
3017 vki_ksigset_t* oldmask )
3018{
3019 Char msg_buf[100];
3020 if (VG_(clo_trace_pthread_level) >= 1) {
3021 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00003022 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
3023 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003024 print_pthread_event(tid, msg_buf);
3025 }
3026
3027 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003028 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003029
njn25e49d8e72002-09-23 09:36:25 +00003030 if (newmask)
3031 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3032 "pthread_sigmask: newmask",
3033 (Addr)newmask, sizeof(vki_ksigset_t));
3034 if (oldmask)
3035 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3036 "pthread_sigmask: oldmask",
3037 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00003038
sewardj018f7622002-05-15 21:13:39 +00003039 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003040
njn25e49d8e72002-09-23 09:36:25 +00003041 if (oldmask)
3042 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00003043
sewardj018f7622002-05-15 21:13:39 +00003044 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00003045 SET_EDX(tid, 0);
3046}
3047
3048
3049static
3050void do_sigwait ( ThreadId tid,
3051 vki_ksigset_t* set,
3052 Int* sig )
3053{
sewardj018f7622002-05-15 21:13:39 +00003054 vki_ksigset_t irrelevant_sigmask;
3055 Char msg_buf[100];
3056
sewardjb48e5002002-05-13 00:16:03 +00003057 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3058 VG_(sprintf)(msg_buf,
3059 "suspend due to sigwait(): set %p, sig %p",
3060 set, sig );
3061 print_pthread_event(tid, msg_buf);
3062 }
3063
3064 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003065 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003066
sewardj018f7622002-05-15 21:13:39 +00003067 /* Change SCSS */
3068 VG_(threads)[tid].sigs_waited_for = *set;
3069 VG_(threads)[tid].status = VgTs_WaitSIG;
3070
3071 VG_(block_all_host_signals)( &irrelevant_sigmask );
3072 VG_(handle_SCSS_change)( False /* lazy update */ );
3073}
3074
3075
3076static
3077void do_pthread_kill ( ThreadId tid, /* me */
3078 ThreadId thread, /* thread to signal */
3079 Int sig )
3080{
3081 Char msg_buf[100];
3082
3083 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3084 VG_(sprintf)(msg_buf,
3085 "pthread_kill thread %d, signo %d",
3086 thread, sig );
3087 print_pthread_event(tid, msg_buf);
3088 }
3089
3090 vg_assert(VG_(is_valid_tid)(tid)
3091 && VG_(threads)[tid].status == VgTs_Runnable);
3092
sewardj4dced352002-06-04 22:54:20 +00003093 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003094 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003095 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003096 SET_EDX(tid, -VKI_ESRCH);
3097 return;
3098 }
3099
3100 if (sig < 1 || sig > VKI_KNSIG) {
3101 SET_EDX(tid, -VKI_EINVAL);
3102 return;
3103 }
3104
3105 VG_(send_signal_to_thread)( thread, sig );
3106 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003107}
3108
3109
sewardj2cb00342002-06-28 01:46:26 +00003110/* -----------------------------------------------------------
3111 FORK HANDLERS.
3112 -------------------------------------------------------- */
3113
3114static
3115void do__set_fhstack_used ( ThreadId tid, Int n )
3116{
3117 Char msg_buf[100];
3118 if (VG_(clo_trace_sched)) {
3119 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3120 print_pthread_event(tid, msg_buf);
3121 }
3122
3123 vg_assert(VG_(is_valid_tid)(tid)
3124 && VG_(threads)[tid].status == VgTs_Runnable);
3125
3126 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3127 vg_fhstack_used = n;
3128 SET_EDX(tid, 0);
3129 } else {
3130 SET_EDX(tid, -1);
3131 }
3132}
3133
3134
3135static
3136void do__get_fhstack_used ( ThreadId tid )
3137{
3138 Int n;
3139 Char msg_buf[100];
3140 if (VG_(clo_trace_sched)) {
3141 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3142 print_pthread_event(tid, msg_buf);
3143 }
3144
3145 vg_assert(VG_(is_valid_tid)(tid)
3146 && VG_(threads)[tid].status == VgTs_Runnable);
3147
3148 n = vg_fhstack_used;
3149 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3150 SET_EDX(tid, n);
3151}
3152
3153static
3154void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3155{
3156 Char msg_buf[100];
3157 if (VG_(clo_trace_sched)) {
3158 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3159 print_pthread_event(tid, msg_buf);
3160 }
3161
3162 vg_assert(VG_(is_valid_tid)(tid)
3163 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003164 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3165 "pthread_atfork: prepare/parent/child",
3166 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003167
njn25e49d8e72002-09-23 09:36:25 +00003168 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003169 SET_EDX(tid, -1);
3170 return;
3171 }
3172
3173 vg_fhstack[n] = *fh;
3174 SET_EDX(tid, 0);
3175}
3176
3177
3178static
3179void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3180 ForkHandlerEntry* fh )
3181{
3182 Char msg_buf[100];
3183 if (VG_(clo_trace_sched)) {
3184 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3185 print_pthread_event(tid, msg_buf);
3186 }
3187
3188 vg_assert(VG_(is_valid_tid)(tid)
3189 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003190 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3191 "fork: prepare/parent/child",
3192 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003193
njn25e49d8e72002-09-23 09:36:25 +00003194 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003195 SET_EDX(tid, -1);
3196 return;
3197 }
3198
3199 *fh = vg_fhstack[n];
3200 SET_EDX(tid, 0);
3201
njn25e49d8e72002-09-23 09:36:25 +00003202 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003203}
3204
3205
sewardje663cb92002-04-12 10:26:32 +00003206/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003207 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003208 ------------------------------------------------------------------ */
3209
sewardj124ca2a2002-06-20 10:19:38 +00003210/* Do a client request for the thread tid. After the request, tid may
3211 or may not still be runnable; if not, the scheduler will have to
3212 choose a new thread to run.
3213*/
sewardje663cb92002-04-12 10:26:32 +00003214static
sewardj124ca2a2002-06-20 10:19:38 +00003215void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003216{
njn25e49d8e72002-09-23 09:36:25 +00003217# define RETURN_WITH(vvv) \
3218 { tst->m_edx = (vvv); \
3219 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003220 }
3221
3222 ThreadState* tst = &VG_(threads)[tid];
3223 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3224 UInt req_no = arg[0];
3225
3226 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003227 switch (req_no) {
3228
sewardj124ca2a2002-06-20 10:19:38 +00003229 case VG_USERREQ__MALLOC:
3230 RETURN_WITH(
3231 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3232 );
3233 break;
3234
3235 case VG_USERREQ__BUILTIN_NEW:
3236 RETURN_WITH(
3237 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3238 );
3239 break;
3240
3241 case VG_USERREQ__BUILTIN_VEC_NEW:
3242 RETURN_WITH(
3243 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3244 );
3245 break;
3246
3247 case VG_USERREQ__FREE:
3248 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3249 RETURN_WITH(0); /* irrelevant */
3250 break;
3251
3252 case VG_USERREQ__BUILTIN_DELETE:
3253 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3254 RETURN_WITH(0); /* irrelevant */
3255 break;
3256
3257 case VG_USERREQ__BUILTIN_VEC_DELETE:
3258 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3259 RETURN_WITH(0); /* irrelevant */
3260 break;
3261
3262 case VG_USERREQ__CALLOC:
3263 RETURN_WITH(
3264 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3265 );
3266 break;
3267
3268 case VG_USERREQ__REALLOC:
3269 RETURN_WITH(
3270 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3271 );
3272 break;
3273
3274 case VG_USERREQ__MEMALIGN:
3275 RETURN_WITH(
3276 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3277 );
3278 break;
3279
3280 case VG_USERREQ__PTHREAD_GET_THREADID:
3281 RETURN_WITH(tid);
3282 break;
3283
3284 case VG_USERREQ__RUNNING_ON_VALGRIND:
3285 RETURN_WITH(1);
3286 break;
3287
3288 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3289 RETURN_WITH(VG_(clo_trace_pthread_level));
3290 break;
3291
3292 case VG_USERREQ__READ_MILLISECOND_TIMER:
3293 RETURN_WITH(VG_(read_millisecond_timer)());
3294 break;
3295
3296 /* Some of these may make thread tid non-runnable, but the
3297 scheduler checks for that on return from this function. */
3298 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3299 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3300 break;
3301
3302 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3303 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3304 break;
3305
3306 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3307 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3308 break;
3309
sewardj00a66b12002-10-12 16:42:35 +00003310 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
3311 do_pthread_getspecific_ptr ( tid );
sewardj124ca2a2002-06-20 10:19:38 +00003312 break;
3313
3314 case VG_USERREQ__SET_CANCELTYPE:
3315 do__set_canceltype ( tid, arg[1] );
3316 break;
3317
3318 case VG_USERREQ__CLEANUP_PUSH:
3319 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3320 break;
3321
3322 case VG_USERREQ__CLEANUP_POP:
3323 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3324 break;
3325
3326 case VG_USERREQ__TESTCANCEL:
3327 do__testcancel ( tid );
3328 break;
3329
3330 case VG_USERREQ__GET_N_SIGS_RETURNED:
3331 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3332 break;
3333
sewardje663cb92002-04-12 10:26:32 +00003334 case VG_USERREQ__PTHREAD_JOIN:
3335 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3336 break;
3337
sewardj3b5d8862002-04-20 13:53:23 +00003338 case VG_USERREQ__PTHREAD_COND_WAIT:
3339 do_pthread_cond_wait( tid,
3340 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003341 (pthread_mutex_t *)(arg[2]),
3342 0xFFFFFFFF /* no timeout */ );
3343 break;
3344
3345 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3346 do_pthread_cond_wait( tid,
3347 (pthread_cond_t *)(arg[1]),
3348 (pthread_mutex_t *)(arg[2]),
3349 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003350 break;
3351
3352 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3353 do_pthread_cond_signal_or_broadcast(
3354 tid,
3355 False, /* signal, not broadcast */
3356 (pthread_cond_t *)(arg[1]) );
3357 break;
3358
3359 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3360 do_pthread_cond_signal_or_broadcast(
3361 tid,
3362 True, /* broadcast, not signal */
3363 (pthread_cond_t *)(arg[1]) );
3364 break;
3365
sewardj00a66b12002-10-12 16:42:35 +00003366 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
3367 do_pthread_key_validate ( tid,
3368 (pthread_key_t)(arg[1]) );
3369 break;
3370
sewardj5f07b662002-04-23 16:52:51 +00003371 case VG_USERREQ__PTHREAD_KEY_CREATE:
3372 do_pthread_key_create ( tid,
3373 (pthread_key_t*)(arg[1]),
3374 (void(*)(void*))(arg[2]) );
3375 break;
3376
3377 case VG_USERREQ__PTHREAD_KEY_DELETE:
3378 do_pthread_key_delete ( tid,
3379 (pthread_key_t)(arg[1]) );
3380 break;
3381
sewardj00a66b12002-10-12 16:42:35 +00003382 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
3383 do_pthread_setspecific_ptr ( tid,
3384 (void**)(arg[1]) );
sewardj5f07b662002-04-23 16:52:51 +00003385 break;
3386
sewardjb48e5002002-05-13 00:16:03 +00003387 case VG_USERREQ__PTHREAD_SIGMASK:
3388 do_pthread_sigmask ( tid,
3389 arg[1],
3390 (vki_ksigset_t*)(arg[2]),
3391 (vki_ksigset_t*)(arg[3]) );
3392 break;
3393
3394 case VG_USERREQ__SIGWAIT:
3395 do_sigwait ( tid,
3396 (vki_ksigset_t*)(arg[1]),
3397 (Int*)(arg[2]) );
3398 break;
3399
sewardj018f7622002-05-15 21:13:39 +00003400 case VG_USERREQ__PTHREAD_KILL:
3401 do_pthread_kill ( tid, arg[1], arg[2] );
3402 break;
3403
sewardjff42d1d2002-05-22 13:17:31 +00003404 case VG_USERREQ__PTHREAD_YIELD:
3405 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003406 /* On return from do_client_request(), the scheduler will
3407 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003408 break;
sewardj018f7622002-05-15 21:13:39 +00003409
sewardj7989d0c2002-05-28 11:00:01 +00003410 case VG_USERREQ__SET_CANCELSTATE:
3411 do__set_cancelstate ( tid, arg[1] );
3412 break;
3413
sewardj7989d0c2002-05-28 11:00:01 +00003414 case VG_USERREQ__SET_OR_GET_DETACH:
3415 do__set_or_get_detach ( tid, arg[1], arg[2] );
3416 break;
3417
3418 case VG_USERREQ__SET_CANCELPEND:
3419 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3420 break;
3421
3422 case VG_USERREQ__WAIT_JOINER:
3423 do__wait_joiner ( tid, (void*)arg[1] );
3424 break;
3425
3426 case VG_USERREQ__QUIT:
3427 do__quit ( tid );
3428 break;
3429
3430 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3431 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3432 (void*)arg[2] );
3433 break;
3434
sewardj870497a2002-05-29 01:06:47 +00003435 case VG_USERREQ__GET_KEY_D_AND_S:
3436 do__get_key_destr_and_spec ( tid,
3437 (pthread_key_t)arg[1],
3438 (CleanupEntry*)arg[2] );
3439 break;
3440
sewardjef037c72002-05-30 00:40:03 +00003441 case VG_USERREQ__NUKE_OTHER_THREADS:
3442 VG_(nuke_all_threads_except) ( tid );
3443 SET_EDX(tid, 0);
3444 break;
3445
sewardj4dced352002-06-04 22:54:20 +00003446 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003447 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003448 SET_EDX(tid, 0);
3449 break;
3450
sewardj2cb00342002-06-28 01:46:26 +00003451 case VG_USERREQ__SET_FHSTACK_USED:
3452 do__set_fhstack_used( tid, (Int)(arg[1]) );
3453 break;
3454
3455 case VG_USERREQ__GET_FHSTACK_USED:
3456 do__get_fhstack_used( tid );
3457 break;
3458
3459 case VG_USERREQ__SET_FHSTACK_ENTRY:
3460 do__set_fhstack_entry( tid, (Int)(arg[1]),
3461 (ForkHandlerEntry*)(arg[2]) );
3462 break;
3463
3464 case VG_USERREQ__GET_FHSTACK_ENTRY:
3465 do__get_fhstack_entry( tid, (Int)(arg[1]),
3466 (ForkHandlerEntry*)(arg[2]) );
3467 break;
3468
sewardj77e466c2002-04-14 02:29:29 +00003469 case VG_USERREQ__SIGNAL_RETURNS:
3470 handle_signal_return(tid);
3471 break;
sewardj54cacf02002-04-12 23:24:59 +00003472
njn25e49d8e72002-09-23 09:36:25 +00003473 /* Requests from the client program */
3474
3475 case VG_USERREQ__DISCARD_TRANSLATIONS:
3476 if (VG_(clo_verbosity) > 2)
3477 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3478 " addr %p, len %d\n",
3479 (void*)arg[1], arg[2] );
3480
3481 VG_(invalidate_translations)( arg[1], arg[2] );
3482
3483 SET_EDX( tid, 0 ); /* return value is meaningless */
3484 break;
3485
sewardje663cb92002-04-12 10:26:32 +00003486 default:
njn25e49d8e72002-09-23 09:36:25 +00003487 if (VG_(needs).client_requests) {
sewardj34042512002-10-22 04:14:35 +00003488 UInt ret;
3489
njn25e49d8e72002-09-23 09:36:25 +00003490 if (VG_(clo_verbosity) > 2)
3491 VG_(printf)("client request: code %d, addr %p, len %d\n",
3492 arg[0], (void*)arg[1], arg[2] );
3493
sewardj34042512002-10-22 04:14:35 +00003494 if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret ))
3495 SET_EDX(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00003496 } else {
sewardj34042512002-10-22 04:14:35 +00003497 static Bool whined = False;
3498
3499 if (!whined) {
3500 VG_(message)(Vg_UserMsg, "Warning:\n"
3501 " unhandled client request: 0x%x (%c%c+%d). Perhaps\n"
3502 " VG_(needs).client_requests should be set?\n",
3503 arg[0], (arg[0] >> 24) & 0xff, (arg[0] >> 16) & 0xff,
3504 arg[0] & 0xffff);
3505 whined = True;
3506 }
njn25e49d8e72002-09-23 09:36:25 +00003507 }
sewardje663cb92002-04-12 10:26:32 +00003508 break;
3509 }
sewardj124ca2a2002-06-20 10:19:38 +00003510
3511# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003512}
3513
3514
sewardj6072c362002-04-19 14:40:57 +00003515/* ---------------------------------------------------------------------
3516 Sanity checking.
3517 ------------------------------------------------------------------ */
3518
3519/* Internal consistency checks on the sched/pthread structures. */
3520static
3521void scheduler_sanity ( void )
3522{
sewardj3b5d8862002-04-20 13:53:23 +00003523 pthread_mutex_t* mx;
3524 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003525 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003526
sewardj6072c362002-04-19 14:40:57 +00003527 /* VG_(printf)("scheduler_sanity\n"); */
3528 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003529 mx = VG_(threads)[i].associated_mx;
3530 cv = VG_(threads)[i].associated_cv;
3531 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003532 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3533 it's actually held by someone, since otherwise this thread
3534 is deadlocked, (4) the mutex's owner is not us, since
3535 otherwise this thread is also deadlocked. The logic in
3536 do_pthread_mutex_lock rejects attempts by a thread to lock
3537 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003538
sewardjbf290b92002-05-01 02:28:01 +00003539 (2) has been seen to fail sometimes. I don't know why.
3540 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003541 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003542 /* 1 */ vg_assert(mx != NULL);
3543 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003544 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003545 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003546 } else
sewardj018f7622002-05-15 21:13:39 +00003547 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003548 vg_assert(cv != NULL);
3549 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003550 } else {
sewardj05553872002-04-20 20:53:17 +00003551 /* Unfortunately these don't hold true when a sighandler is
3552 running. To be fixed. */
3553 /* vg_assert(cv == NULL); */
3554 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003555 }
sewardjbf290b92002-05-01 02:28:01 +00003556
sewardj018f7622002-05-15 21:13:39 +00003557 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003558 Int
sewardj018f7622002-05-15 21:13:39 +00003559 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3560 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003561 if (i > 1 /* not the root thread */
3562 && stack_used
3563 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3564 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003565 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003566 "thread %d: stack used %d, available %d",
3567 i, stack_used, VG_PTHREAD_STACK_MIN );
3568 VG_(message)(Vg_UserMsg,
3569 "Terminating Valgrind. If thread(s) "
3570 "really need more stack, increase");
3571 VG_(message)(Vg_UserMsg,
3572 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3573 VG_(exit)(1);
3574 }
sewardjb48e5002002-05-13 00:16:03 +00003575
sewardj018f7622002-05-15 21:13:39 +00003576 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003577 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003578 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003579 } else {
3580 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003581 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003582 }
3583
sewardjbf290b92002-05-01 02:28:01 +00003584 }
sewardj6072c362002-04-19 14:40:57 +00003585 }
sewardj5f07b662002-04-23 16:52:51 +00003586
3587 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3588 if (!vg_thread_keys[i].inuse)
3589 vg_assert(vg_thread_keys[i].destructor == NULL);
3590 }
sewardj6072c362002-04-19 14:40:57 +00003591}
3592
3593
sewardje663cb92002-04-12 10:26:32 +00003594/*--------------------------------------------------------------------*/
3595/*--- end vg_scheduler.c ---*/
3596/*--------------------------------------------------------------------*/