blob: ea8f35549b7f79b0542347b7f30f9f7ec61a862e [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"
sewardje12a45f2003-03-15 20:03:33 +000032
33/* Sidestep the normal check which disallows using valgrind.h
34 directly. */
35#define __VALGRIND_SOMESKIN_H
njn25e49d8e72002-09-23 09:36:25 +000036#include "valgrind.h" /* for VG_USERREQ__RUNNING_ON_VALGRIND and
37 VG_USERREQ__DISCARD_TRANSLATIONS */
sewardje663cb92002-04-12 10:26:32 +000038
sewardjb60c1ad2002-05-29 20:23:26 +000039/* BORKAGE/ISSUES as of 29 May 02
sewardje663cb92002-04-12 10:26:32 +000040
sewardj77e466c2002-04-14 02:29:29 +000041- Currently, when a signal is run, just the ThreadStatus.status fields
42 are saved in the signal frame, along with the CPU state. Question:
43 should I also save and restore:
44 ThreadStatus.joiner
45 ThreadStatus.waited_on_mid
46 ThreadStatus.awaken_at
47 ThreadStatus.retval
48 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000049
sewardj77e466c2002-04-14 02:29:29 +000050- Signals interrupting read/write and nanosleep: SA_RESTART settings.
51 Read/write correctly return with EINTR when SA_RESTART isn't
52 specified and they are interrupted by a signal. nanosleep just
53 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000054
sewardj705d3cb2002-05-23 13:13:12 +000055- So, what's the deal with signals and mutexes? If a thread is
sewardj6072c362002-04-19 14:40:57 +000056 blocked on a mutex, or for a condition variable for that matter, can
57 signals still be delivered to it? This has serious consequences --
58 deadlocks, etc.
59
sewardj705d3cb2002-05-23 13:13:12 +000060- Signals still not really right. Each thread should have its
61 own pending-set, but there is just one process-wide pending set.
62
sewardjb60c1ad2002-05-29 20:23:26 +000063 TODO for valgrind-1.0:
64
sewardj055fbb82002-05-30 00:40:55 +000065- Update assertion checking in scheduler_sanity().
66
sewardjb60c1ad2002-05-29 20:23:26 +000067 TODO sometime:
68
sewardj645030e2002-06-06 01:27:39 +000069- poll() in the vg_libpthread.c -- should it handle the nanosleep
70 being interrupted by a signal? Ditto accept?
71
sewardjb60c1ad2002-05-29 20:23:26 +000072- Mutex scrubbing - clearup_after_thread_exit: look for threads
73 blocked on mutexes held by the exiting thread, and release them
74 appropriately. (??)
75
76- pthread_atfork
77
sewardje462e202002-04-13 04:09:07 +000078*/
sewardje663cb92002-04-12 10:26:32 +000079
80
81/* ---------------------------------------------------------------------
82 Types and globals for the scheduler.
83 ------------------------------------------------------------------ */
84
85/* type ThreadId is defined in vg_include.h. */
86
87/* struct ThreadState is defined in vg_include.h. */
88
sewardj018f7622002-05-15 21:13:39 +000089/* Globals. A statically allocated array of threads. NOTE: [0] is
90 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000091 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000092ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000093
sewardj2cb00342002-06-28 01:46:26 +000094/* The process' fork-handler stack. */
95static Int vg_fhstack_used = 0;
96static ForkHandlerEntry vg_fhstack[VG_N_FORKHANDLERSTACK];
97
98
sewardj1e8cdc92002-04-18 11:37:52 +000099/* The tid of the thread currently in VG_(baseBlock). */
100static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
101
sewardjb52a1b02002-10-23 21:38:22 +0000102/* The tid either currently in baseBlock, or was in baseBlock before
103 was saved it out; this is only updated when a new thread is loaded
104 into the baseBlock */
105static Int vg_tid_last_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000106
107/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
108jmp_buf VG_(scheduler_jmpbuf);
sewardj872051c2002-07-13 12:12:56 +0000109/* This says whether scheduler_jmpbuf is actually valid. Needed so
110 that our signal handler doesn't longjmp when the buffer isn't
111 actually valid. */
112Bool VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000113/* ... and if so, here's the signal which caused it to do so. */
114Int VG_(longjmpd_on_signal);
115
116
117/* Machinery to keep track of which threads are waiting on which
118 fds. */
119typedef
120 struct {
121 /* The thread which made the request. */
122 ThreadId tid;
123
124 /* The next two fields describe the request. */
125 /* File descriptor waited for. -1 means this slot is not in use */
126 Int fd;
127 /* The syscall number the fd is used in. */
128 Int syscall_no;
129
130 /* False => still waiting for select to tell us the fd is ready
131 to go. True => the fd is ready, but the results have not yet
132 been delivered back to the calling thread. Once the latter
133 happens, this entire record is marked as no longer in use, by
134 making the fd field be -1. */
135 Bool ready;
njn25e49d8e72002-09-23 09:36:25 +0000136
137 /* The result from SK_(pre_blocking_syscall)(); is passed to
138 * SK_(post_blocking_syscall)(). */
139 void* pre_result;
sewardje663cb92002-04-12 10:26:32 +0000140 }
141 VgWaitedOnFd;
142
143static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
144
145
sewardj5f07b662002-04-23 16:52:51 +0000146/* Keeping track of keys. */
147typedef
148 struct {
149 /* Has this key been allocated ? */
150 Bool inuse;
151 /* If .inuse==True, records the address of the associated
152 destructor, or NULL if none. */
153 void (*destructor)(void*);
154 }
155 ThreadKeyState;
156
157/* And our array of thread keys. */
158static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
159
160typedef UInt ThreadKey;
161
162
njn25e49d8e72002-09-23 09:36:25 +0000163UInt VG_(written_shadow_reg);
164
sewardje663cb92002-04-12 10:26:32 +0000165/* Forwards */
sewardj124ca2a2002-06-20 10:19:38 +0000166static void do_client_request ( ThreadId tid );
sewardj6072c362002-04-19 14:40:57 +0000167static void scheduler_sanity ( void );
sewardj124ca2a2002-06-20 10:19:38 +0000168static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
sewardjd140e442002-05-29 01:21:19 +0000169
sewardje663cb92002-04-12 10:26:32 +0000170/* ---------------------------------------------------------------------
171 Helper functions for the scheduler.
172 ------------------------------------------------------------------ */
173
sewardjb48e5002002-05-13 00:16:03 +0000174__inline__
175Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000176{
177 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000178 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000179 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000180 if (VG_(threads)[tid].status == VgTs_Empty) return False;
181 return True;
182}
183
184
185__inline__
186Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
187{
188 /* tid is unsigned, hence no < 0 test. */
189 if (tid == 0) return False;
190 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000191 return True;
192}
193
194
sewardj1e8cdc92002-04-18 11:37:52 +0000195/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000196 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
197 if none do. A small complication is dealing with any currently
198 VG_(baseBlock)-resident thread.
sewardj1e8cdc92002-04-18 11:37:52 +0000199*/
njn43c799e2003-04-08 00:08:52 +0000200ThreadId VG_(first_matching_thread_stack)
njn25e49d8e72002-09-23 09:36:25 +0000201 ( Bool (*p) ( Addr stack_min, Addr stack_max ))
sewardj1e8cdc92002-04-18 11:37:52 +0000202{
203 ThreadId tid, tid_to_skip;
204
205 tid_to_skip = VG_INVALID_THREADID;
206
207 /* First check to see if there's a currently-loaded thread in
208 VG_(baseBlock). */
209 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
210 tid = vg_tid_currently_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000211 if ( p ( VG_(baseBlock)[VGOFF_(m_esp)],
212 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000213 return tid;
214 else
215 tid_to_skip = tid;
216 }
217
sewardj6072c362002-04-19 14:40:57 +0000218 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000219 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardj1e8cdc92002-04-18 11:37:52 +0000220 if (tid == tid_to_skip) continue;
njn25e49d8e72002-09-23 09:36:25 +0000221 if ( p ( VG_(threads)[tid].m_esp,
222 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000223 return tid;
224 }
225 return VG_INVALID_THREADID;
226}
227
228
sewardj15a43e12002-04-17 19:35:12 +0000229/* Print the scheduler status. */
230void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000231{
232 Int i;
233 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000234 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000235 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000236 VG_(printf)("\nThread %d: status = ", i);
sewardj018f7622002-05-15 21:13:39 +0000237 switch (VG_(threads)[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000238 case VgTs_Runnable: VG_(printf)("Runnable"); break;
239 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
sewardj20917d82002-05-28 01:36:45 +0000240 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee(%d)",
241 VG_(threads)[i].joiner_jee_tid);
242 break;
243 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner"); break;
sewardj6072c362002-04-19 14:40:57 +0000244 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
245 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000246 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000247 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000248 default: VG_(printf)("???"); break;
249 }
sewardj3b5d8862002-04-20 13:53:23 +0000250 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000251 VG_(threads)[i].associated_mx,
252 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000253 VG_(pp_ExeContext)(
njn25e49d8e72002-09-23 09:36:25 +0000254 VG_(get_ExeContext2)( VG_(threads)[i].m_eip, VG_(threads)[i].m_ebp,
255 VG_(threads)[i].m_esp,
256 VG_(threads)[i].stack_highest_word)
257 );
sewardje663cb92002-04-12 10:26:32 +0000258 }
259 VG_(printf)("\n");
260}
261
262static
njn25e49d8e72002-09-23 09:36:25 +0000263void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no, void* pre_res )
sewardje663cb92002-04-12 10:26:32 +0000264{
265 Int i;
266
267 vg_assert(fd != -1); /* avoid total chaos */
268
269 for (i = 0; i < VG_N_WAITING_FDS; i++)
270 if (vg_waiting_fds[i].fd == -1)
271 break;
272
273 if (i == VG_N_WAITING_FDS)
njne427a662002-10-02 11:08:25 +0000274 VG_(core_panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
sewardje663cb92002-04-12 10:26:32 +0000275 /*
276 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
277 tid, fd, i);
278 */
279 vg_waiting_fds[i].fd = fd;
280 vg_waiting_fds[i].tid = tid;
281 vg_waiting_fds[i].ready = False;
282 vg_waiting_fds[i].syscall_no = syscall_no;
njn25e49d8e72002-09-23 09:36:25 +0000283 vg_waiting_fds[i].pre_result = pre_res;
sewardje663cb92002-04-12 10:26:32 +0000284}
285
286
287
288static
289void print_sched_event ( ThreadId tid, Char* what )
290{
sewardj45b4b372002-04-16 22:50:32 +0000291 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000292}
293
294
295static
296void print_pthread_event ( ThreadId tid, Char* what )
297{
298 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000299}
300
301
302static
303Char* name_of_sched_event ( UInt event )
304{
305 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000306 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
307 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
308 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
309 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
310 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
311 default: return "??UNKNOWN??";
312 }
313}
314
315
316/* Create a translation of the client basic block beginning at
317 orig_addr, and add it to the translation cache & translation table.
318 This probably doesn't really belong here, but, hey ...
319*/
sewardj1e8cdc92002-04-18 11:37:52 +0000320static
321void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000322{
sewardj22854b92002-11-30 14:00:47 +0000323 Addr trans_addr;
324 Int orig_size, trans_size;
325 UShort jumps[VG_MAX_JUMPS];
326 Int i;
327
328 for(i = 0; i < VG_MAX_JUMPS; i++)
329 jumps[i] = (UShort)-1;
sewardj6c3769f2002-11-29 01:02:45 +0000330
331 /* Make a translation, into temporary storage. */
sewardj018f7622002-05-15 21:13:39 +0000332 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +0000333 orig_addr, &orig_size, &trans_addr, &trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000334
335 /* Copy data at trans_addr into the translation cache. */
sewardje663cb92002-04-12 10:26:32 +0000336 /* Since the .orig_size and .trans_size fields are
337 UShort, be paranoid. */
338 vg_assert(orig_size > 0 && orig_size < 65536);
339 vg_assert(trans_size > 0 && trans_size < 65536);
sewardj6c3769f2002-11-29 01:02:45 +0000340
sewardj22854b92002-11-30 14:00:47 +0000341 VG_(add_to_trans_tab)( orig_addr, orig_size, trans_addr, trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000342
sewardje663cb92002-04-12 10:26:32 +0000343 /* Free the intermediary -- was allocated by VG_(emit_code). */
njn25e49d8e72002-09-23 09:36:25 +0000344 VG_(arena_free)( VG_AR_JITTER, (void*)trans_addr );
sewardje663cb92002-04-12 10:26:32 +0000345}
346
347
348/* Allocate a completely empty ThreadState record. */
349static
350ThreadId vg_alloc_ThreadState ( void )
351{
352 Int i;
sewardj6072c362002-04-19 14:40:57 +0000353 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000354 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000355 return i;
356 }
357 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
358 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000359 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000360 /*NOTREACHED*/
361}
362
njn25e49d8e72002-09-23 09:36:25 +0000363ThreadState* VG_(get_ThreadState)( ThreadId tid )
364{
365 vg_assert(tid >= 0 && tid < VG_N_THREADS);
366 return & VG_(threads)[tid];
367}
sewardje663cb92002-04-12 10:26:32 +0000368
sewardj1e8cdc92002-04-18 11:37:52 +0000369ThreadState* VG_(get_current_thread_state) ( void )
370{
sewardj018f7622002-05-15 21:13:39 +0000371 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
372 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000373}
374
375
376ThreadId VG_(get_current_tid) ( void )
377{
sewardjb52a1b02002-10-23 21:38:22 +0000378 if (!VG_(is_valid_tid)(vg_tid_currently_in_baseBlock))
379 return VG_INVALID_THREADID;
sewardj1e8cdc92002-04-18 11:37:52 +0000380 return vg_tid_currently_in_baseBlock;
381}
382
sewardjb52a1b02002-10-23 21:38:22 +0000383ThreadId VG_(get_current_or_recent_tid) ( void )
njn25e49d8e72002-09-23 09:36:25 +0000384{
sewardjb52a1b02002-10-23 21:38:22 +0000385 vg_assert(vg_tid_currently_in_baseBlock == vg_tid_last_in_baseBlock ||
386 vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
387 vg_assert(VG_(is_valid_tid)(vg_tid_last_in_baseBlock));
388
389 return vg_tid_last_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000390}
391
sewardj7ab2aca2002-10-20 19:40:32 +0000392ThreadId VG_(get_tid_from_ThreadState) (ThreadState* tst)
393{
394 vg_assert(tst >= &VG_(threads)[1] && tst < &VG_(threads)[VG_N_THREADS]);
395 return tst->tid;
396}
397
sewardje663cb92002-04-12 10:26:32 +0000398/* Copy the saved state of a thread into VG_(baseBlock), ready for it
399 to be run. */
400__inline__
401void VG_(load_thread_state) ( ThreadId tid )
402{
403 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000404 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
405
sewardj92a59562002-09-30 00:53:10 +0000406 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
407 VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs;
408 VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss;
409 VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds;
410 VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es;
411 VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs;
412 VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs;
413
sewardj018f7622002-05-15 21:13:39 +0000414 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
415 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
416 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
417 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
418 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
419 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
420 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
421 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
sewardjfa492d42002-12-08 18:20:01 +0000422 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags & ~EFlagD;
423 VG_(baseBlock)[VGOFF_(m_dflag)] = VG_(extractDflag)(VG_(threads)[tid].m_eflags);
sewardj018f7622002-05-15 21:13:39 +0000424 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000425
426 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000427 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000428
njn25e49d8e72002-09-23 09:36:25 +0000429 if (VG_(needs).shadow_regs) {
430 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
431 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
432 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
433 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
434 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
435 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
436 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
437 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
438 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
439 } else {
440 /* Fields shouldn't be used -- check their values haven't changed. */
441 /* Nb: they are written to by some macros like SET_EDX, but they
442 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
443 vg_assert(
444 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
445 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
446 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
447 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
448 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
449 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
450 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
451 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
452 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
453 }
sewardj1e8cdc92002-04-18 11:37:52 +0000454
455 vg_tid_currently_in_baseBlock = tid;
sewardjb52a1b02002-10-23 21:38:22 +0000456 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000457}
458
459
460/* Copy the state of a thread from VG_(baseBlock), presumably after it
461 has been descheduled. For sanity-check purposes, fill the vacated
462 VG_(baseBlock) with garbage so as to make the system more likely to
463 fail quickly if we erroneously continue to poke around inside
464 VG_(baseBlock) without first doing a load_thread_state().
465*/
466__inline__
467void VG_(save_thread_state) ( ThreadId tid )
468{
469 Int i;
470 const UInt junk = 0xDEADBEEF;
471
sewardj1e8cdc92002-04-18 11:37:52 +0000472 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
473
sewardj92a59562002-09-30 00:53:10 +0000474
475 /* We don't copy out the LDT entry, because it can never be changed
476 by the normal actions of the thread, only by the modify_ldt
477 syscall, in which case we will correctly be updating
sewardjfb5e5272002-12-08 23:27:21 +0000478 VG_(threads)[tid].ldt. This printf happens iff the following
479 assertion fails. */
sewardjca340b32002-12-08 22:14:11 +0000480 if ((void*)VG_(threads)[tid].ldt != (void*)VG_(baseBlock)[VGOFF_(ldt)])
481 VG_(printf)("VG_(threads)[%d].ldt=%p VG_(baseBlock)[VGOFF_(ldt)]=%p\n",
sewardjfb5e5272002-12-08 23:27:21 +0000482 tid, (void*)VG_(threads)[tid].ldt,
483 (void*)VG_(baseBlock)[VGOFF_(ldt)]);
sewardjca340b32002-12-08 22:14:11 +0000484
sewardj92a59562002-09-30 00:53:10 +0000485 vg_assert((void*)VG_(threads)[tid].ldt
486 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
487
488 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
489 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
490 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
491 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
492 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
493 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
494
sewardj018f7622002-05-15 21:13:39 +0000495 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
496 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
497 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
498 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
499 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
500 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
501 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
502 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardjfa492d42002-12-08 18:20:01 +0000503 VG_(threads)[tid].m_eflags = VG_(insertDflag)(VG_(baseBlock)[VGOFF_(m_eflags)],
504 VG_(baseBlock)[VGOFF_(m_dflag)]);
sewardj018f7622002-05-15 21:13:39 +0000505 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000506
507 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000508 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000509
njn25e49d8e72002-09-23 09:36:25 +0000510 if (VG_(needs).shadow_regs) {
511 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
512 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
513 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
514 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
515 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
516 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
517 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
518 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
519 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
520 } else {
521 /* Fill with recognisable junk */
522 VG_(threads)[tid].sh_eax =
523 VG_(threads)[tid].sh_ebx =
524 VG_(threads)[tid].sh_ecx =
525 VG_(threads)[tid].sh_edx =
526 VG_(threads)[tid].sh_esi =
527 VG_(threads)[tid].sh_edi =
528 VG_(threads)[tid].sh_ebp =
529 VG_(threads)[tid].sh_esp =
530 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
531 }
sewardje663cb92002-04-12 10:26:32 +0000532
533 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000534 VG_(baseBlock)[VGOFF_(ldt)] = junk;
535 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
536 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
537 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
538 VG_(baseBlock)[VGOFF_(m_es)] = junk;
539 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
540 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
541
sewardje663cb92002-04-12 10:26:32 +0000542 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
543 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
544 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
545 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
546 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
547 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
548 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
549 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
550 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
551 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
552
553 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
554 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000555
556 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000557}
558
559
560/* Run the thread tid for a while, and return a VG_TRC_* value to the
561 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000562static
sewardje663cb92002-04-12 10:26:32 +0000563UInt run_thread_for_a_while ( ThreadId tid )
564{
sewardj7ccc5c22002-04-24 21:39:11 +0000565 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000566 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000567 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000568 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000569 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000570
sewardj671ff542002-05-07 09:25:30 +0000571 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000572 VG_(load_thread_state) ( tid );
573 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
574 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000575 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000576 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000577 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000578 /* We get here if the client didn't take a fault. */
579 } else {
580 /* We get here if the client took a fault, which caused our
581 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000582 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000583 vg_assert(trc == 0);
584 trc = VG_TRC_UNRESUMABLE_SIGNAL;
585 }
sewardj872051c2002-07-13 12:12:56 +0000586
587 vg_assert(!VG_(scheduler_jmpbuf_valid));
588
sewardje663cb92002-04-12 10:26:32 +0000589 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000590 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000591 return trc;
592}
593
594
sewardj20917d82002-05-28 01:36:45 +0000595static
596void mostly_clear_thread_record ( ThreadId tid )
597{
sewardj20917d82002-05-28 01:36:45 +0000598 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000599 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000600 VG_(threads)[tid].tid = tid;
601 VG_(threads)[tid].status = VgTs_Empty;
602 VG_(threads)[tid].associated_mx = NULL;
603 VG_(threads)[tid].associated_cv = NULL;
604 VG_(threads)[tid].awaken_at = 0;
605 VG_(threads)[tid].joinee_retval = NULL;
606 VG_(threads)[tid].joiner_thread_return = NULL;
607 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000608 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000609 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
610 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
611 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000612 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000613 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000614 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
615 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardj00a66b12002-10-12 16:42:35 +0000616 VG_(threads)[tid].specifics_ptr = NULL;
sewardj20917d82002-05-28 01:36:45 +0000617}
618
619
sewardje663cb92002-04-12 10:26:32 +0000620/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000621 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000622 caller takes care to park the client's state is parked in
623 VG_(baseBlock).
624*/
625void VG_(scheduler_init) ( void )
626{
627 Int i;
628 Addr startup_esp;
629 ThreadId tid_main;
630
631 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000632
sewardj6072c362002-04-19 14:40:57 +0000633 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000634 mostly_clear_thread_record(i);
635 VG_(threads)[i].stack_size = 0;
636 VG_(threads)[i].stack_base = (Addr)NULL;
637 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000638 }
639
640 for (i = 0; i < VG_N_WAITING_FDS; i++)
641 vg_waiting_fds[i].fd = -1; /* not in use */
642
sewardj5f07b662002-04-23 16:52:51 +0000643 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
644 vg_thread_keys[i].inuse = False;
645 vg_thread_keys[i].destructor = NULL;
646 }
647
sewardj2cb00342002-06-28 01:46:26 +0000648 vg_fhstack_used = 0;
649
sewardje663cb92002-04-12 10:26:32 +0000650 /* Assert this is thread zero, which has certain magic
651 properties. */
652 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000653 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000654 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000655
656 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000657 vg_tid_currently_in_baseBlock = tid_main;
sewardjb52a1b02002-10-23 21:38:22 +0000658 vg_tid_last_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000659 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000660
sewardj018f7622002-05-15 21:13:39 +0000661 VG_(threads)[tid_main].stack_highest_word
662 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000663
sewardj1e8cdc92002-04-18 11:37:52 +0000664 /* So now ... */
665 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000666
667 /* Not running client code right now. */
668 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000669}
670
671
672/* What if fd isn't a valid fd? */
673static
674void set_fd_nonblocking ( Int fd )
675{
676 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
677 vg_assert(!VG_(is_kerror)(res));
678 res |= VKI_O_NONBLOCK;
679 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
680 vg_assert(!VG_(is_kerror)(res));
681}
682
683static
684void set_fd_blocking ( Int fd )
685{
686 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
687 vg_assert(!VG_(is_kerror)(res));
688 res &= ~VKI_O_NONBLOCK;
689 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
690 vg_assert(!VG_(is_kerror)(res));
691}
692
693static
694Bool fd_is_blockful ( Int fd )
695{
696 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
697 vg_assert(!VG_(is_kerror)(res));
698 return (res & VKI_O_NONBLOCK) ? False : True;
699}
700
sewardj3947e622002-05-23 16:52:11 +0000701static
702Bool fd_is_valid ( Int fd )
703{
704 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
705 return VG_(is_kerror)(res) ? False : True;
706}
707
sewardje663cb92002-04-12 10:26:32 +0000708
709
sewardj6072c362002-04-19 14:40:57 +0000710/* vthread tid is returning from a signal handler; modify its
711 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000712
713/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
714 for read or write, has been interrupted by a signal. Find and
715 clear the relevant vg_waiting_fd[] entry. Most of the code in this
716 procedure is total paranoia, if you look closely. */
sewardj420b9282003-04-03 22:28:00 +0000717
718/* 4 Apr 2003: monty@mysql.com sent a fix, which adds the comparisons
719 against -1, and the following explaination.
720
721 Valgrind uses fd = -1 internally to tell that a file descriptor is
722 not in use, as the following code shows (at end of
723 cleanup_waiting_fd_table()).
724
725 vg_assert(waiters == 1);
726 for (i = 0; i < VG_N_WAITING_FDS; i++)
727 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1)
728 break;
729 vg_assert(i < VG_N_WAITING_FDS);
730 vg_assert(vg_waiting_fds[i].fd != -1);
731 vg_waiting_fds[i].fd = -1; -- not in use
732 ^^^^^^^
733
734 The bug is that valrind is setting fd = -1 for a not used file
735 descriptor but vg_waiting_fds[i].tid is not reset.
736
737 What happens is that on a later call to cleanup_waiting_fd_table()
738 the function will find old files that was waited on before by the
739 same thread, even if they are marked as 'not in use' by the above
740 code.
741
742 I first tried to fix the bug by setting vg_waiting_fds[i].tid to 0
743 at the end of the above function but this didn't fix the bug.
744 (Maybe there is other places in the code where tid is not properly
745 reset). After adding the test for 'fd == -1' to the loops in
746 cleanup_waiting_fd_table() all problems disappeared.
747*/
748
sewardj1ffa8da2002-04-26 22:47:57 +0000749static
750void cleanup_waiting_fd_table ( ThreadId tid )
751{
752 Int i, waiters;
753
sewardjb48e5002002-05-13 00:16:03 +0000754 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000755 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
756 vg_assert(VG_(threads)[tid].m_eax == __NR_read
757 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000758
759 /* Excessively paranoidly ... find the fd this op was waiting
760 for, and mark it as not being waited on. */
761 waiters = 0;
762 for (i = 0; i < VG_N_WAITING_FDS; i++) {
sewardj420b9282003-04-03 22:28:00 +0000763 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1) {
sewardj1ffa8da2002-04-26 22:47:57 +0000764 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000765 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000766 }
767 }
768 vg_assert(waiters == 1);
769 for (i = 0; i < VG_N_WAITING_FDS; i++)
sewardj420b9282003-04-03 22:28:00 +0000770 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1)
sewardj1ffa8da2002-04-26 22:47:57 +0000771 break;
772 vg_assert(i < VG_N_WAITING_FDS);
773 vg_assert(vg_waiting_fds[i].fd != -1);
774 vg_waiting_fds[i].fd = -1; /* not in use */
775}
776
777
sewardj6072c362002-04-19 14:40:57 +0000778static
779void handle_signal_return ( ThreadId tid )
780{
781 Char msg_buf[100];
782 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000783 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000784
sewardjb48e5002002-05-13 00:16:03 +0000785 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000786
sewardj9a2224b2002-06-19 10:17:40 +0000787 /* Increment signal-returned counter. Used only to implement
788 pause(). */
789 VG_(threads)[tid].n_signals_returned++;
790
sewardj6072c362002-04-19 14:40:57 +0000791 restart_blocked_syscalls = VG_(signal_returns)(tid);
792
793 if (restart_blocked_syscalls)
794 /* Easy; we don't have to do anything. */
795 return;
796
sewardj018f7622002-05-15 21:13:39 +0000797 if (VG_(threads)[tid].status == VgTs_WaitFD
798 && (VG_(threads)[tid].m_eax == __NR_read
799 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000800 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000801 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000802 VG_(threads)[tid].m_eax = -VKI_EINTR;
803 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000804
sewardj6072c362002-04-19 14:40:57 +0000805 if (VG_(clo_trace_sched)) {
806 VG_(sprintf)(msg_buf,
807 "read() / write() interrupted by signal; return EINTR" );
808 print_sched_event(tid, msg_buf);
809 }
810 return;
811 }
812
sewardj645030e2002-06-06 01:27:39 +0000813 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000814 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000815 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000816 write the unused time to nanosleep's second param, but that's
817 too much effort ... we just say that 1 nanosecond was not
818 used, and return EINTR. */
819 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
820 if (rem != NULL) {
821 rem->tv_sec = 0;
822 rem->tv_nsec = 1;
823 }
824 SET_EAX(tid, -VKI_EINTR);
825 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000826 return;
827 }
828
sewardj018f7622002-05-15 21:13:39 +0000829 if (VG_(threads)[tid].status == VgTs_WaitFD) {
njne427a662002-10-02 11:08:25 +0000830 VG_(core_panic)("handle_signal_return: unknown interrupted syscall");
sewardj1ffa8da2002-04-26 22:47:57 +0000831 }
832
sewardj6072c362002-04-19 14:40:57 +0000833 /* All other cases? Just return. */
834}
835
836
sewardje663cb92002-04-12 10:26:32 +0000837static
838void sched_do_syscall ( ThreadId tid )
839{
njn25e49d8e72002-09-23 09:36:25 +0000840 UInt saved_eax;
841 UInt res, syscall_no;
842 UInt fd;
843 void* pre_res;
844 Bool orig_fd_blockness;
845 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000846
sewardjb48e5002002-05-13 00:16:03 +0000847 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000848 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000849
sewardj018f7622002-05-15 21:13:39 +0000850 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000851
852 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000853 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000854 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000855 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000856 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000857 t_awaken
858 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000859 + (UInt)1000ULL * (UInt)(req->tv_sec)
860 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000861 VG_(threads)[tid].status = VgTs_Sleeping;
862 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000863 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000864 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000865 t_now, t_awaken-t_now);
866 print_sched_event(tid, msg_buf);
867 }
868 /* Force the scheduler to run something else for a while. */
869 return;
870 }
871
sewardjaec22c02002-04-29 01:58:08 +0000872 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000873 /* We think it's non-blocking. Just do it in the normal way. */
874 VG_(perform_assumed_nonblocking_syscall)(tid);
875 /* The thread is still runnable. */
876 return;
877 }
878
sewardje663cb92002-04-12 10:26:32 +0000879 /* Set the fd to nonblocking, and do the syscall, which will return
880 immediately, in order to lodge a request with the Linux kernel.
881 We later poll for I/O completion using select(). */
882
sewardj018f7622002-05-15 21:13:39 +0000883 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000884
885 /* Deal with error case immediately. */
886 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000887 if (VG_(needs).core_errors)
888 VG_(message)(Vg_UserMsg,
889 "Warning: invalid file descriptor %d in syscall %s",
890 fd, syscall_no == __NR_read ? "read()" : "write()" );
891 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000892 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000893 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000894 /* We're still runnable. */
895 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
896 return;
897 }
898
899 /* From here onwards we know that fd is valid. */
900
sewardje663cb92002-04-12 10:26:32 +0000901 orig_fd_blockness = fd_is_blockful(fd);
902 set_fd_nonblocking(fd);
903 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000904 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000905
906 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000907 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000908 KERNEL_DO_SYSCALL(tid,res);
909
910 /* Restore original blockfulness of the fd. */
911 if (orig_fd_blockness)
912 set_fd_blocking(fd);
913 else
914 set_fd_nonblocking(fd);
915
sewardjaec22c02002-04-29 01:58:08 +0000916 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
917 /* Finish off in the normal way. Don't restore %EAX, since that
918 now (correctly) holds the result of the call. We get here if either:
919 1. The call didn't block, or
920 2. The fd was already in nonblocking mode before we started to
921 mess with it. In this case, we're not expecting to handle
922 the I/O completion -- the client is. So don't file a
923 completion-wait entry.
924 */
njn25e49d8e72002-09-23 09:36:25 +0000925 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000926 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000927 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000928
929 } else {
930
sewardjaec22c02002-04-29 01:58:08 +0000931 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
932
sewardje663cb92002-04-12 10:26:32 +0000933 /* It would have blocked. First, restore %EAX to what it was
934 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000935 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000936 /* Put this fd in a table of fds on which we are waiting for
937 completion. The arguments for select() later are constructed
938 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000939 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
940 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000941 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000942 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000943 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000944 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
945 print_sched_event(tid, msg_buf);
946 }
947
948 }
949}
950
951
952/* Find out which of the fds in vg_waiting_fds are now ready to go, by
953 making enquiries with select(), and mark them as ready. We have to
954 wait for the requesting threads to fall into the the WaitFD state
955 before we can actually finally deliver the results, so this
956 procedure doesn't do that; complete_blocked_syscalls() does it.
957
958 It might seem odd that a thread which has done a blocking syscall
959 is not in WaitFD state; the way this can happen is if it initially
960 becomes WaitFD, but then a signal is delivered to it, so it becomes
961 Runnable for a while. In this case we have to wait for the
962 sighandler to return, whereupon the WaitFD state is resumed, and
963 only at that point can the I/O result be delivered to it. However,
964 this point may be long after the fd is actually ready.
965
966 So, poll_for_ready_fds() merely detects fds which are ready.
967 complete_blocked_syscalls() does the second half of the trick,
968 possibly much later: it delivers the results from ready fds to
969 threads in WaitFD state.
970*/
sewardj9a199dc2002-04-14 13:01:38 +0000971static
sewardje663cb92002-04-12 10:26:32 +0000972void poll_for_ready_fds ( void )
973{
974 vki_ksigset_t saved_procmask;
975 vki_fd_set readfds;
976 vki_fd_set writefds;
977 vki_fd_set exceptfds;
978 struct vki_timeval timeout;
979 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
980 ThreadId tid;
981 Bool rd_ok, wr_ok, ex_ok;
982 Char msg_buf[100];
983
sewardje462e202002-04-13 04:09:07 +0000984 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000985 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000986
sewardje663cb92002-04-12 10:26:32 +0000987 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000988 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000989 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000990 break;
sewardj6072c362002-04-19 14:40:57 +0000991
sewardj5f07b662002-04-23 16:52:51 +0000992 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000993 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000994 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000995 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000996 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000997 continue;
sewardj018f7622002-05-15 21:13:39 +0000998 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +0000999 /* Resume this thread. Set to zero the remaining-time
1000 (second) arg of nanosleep, since it's used up all its
1001 time. */
sewardj018f7622002-05-15 21:13:39 +00001002 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
1003 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +00001004 if (rem != NULL) {
1005 rem->tv_sec = 0;
1006 rem->tv_nsec = 0;
1007 }
1008 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +00001009 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +00001010 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +00001011 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +00001012 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +00001013 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +00001014 t_now);
1015 print_sched_event(tid, msg_buf);
1016 }
sewardje663cb92002-04-12 10:26:32 +00001017 }
1018 }
1019 }
sewardje663cb92002-04-12 10:26:32 +00001020
sewardje462e202002-04-13 04:09:07 +00001021 /* And look for threads waiting on file descriptors which are now
1022 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +00001023 timeout.tv_sec = 0;
1024 timeout.tv_usec = 0;
1025
1026 VKI_FD_ZERO(&readfds);
1027 VKI_FD_ZERO(&writefds);
1028 VKI_FD_ZERO(&exceptfds);
1029 fd_max = -1;
1030 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1031 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1032 continue;
1033 if (vg_waiting_fds[i].ready /* already ready? */)
1034 continue;
1035 fd = vg_waiting_fds[i].fd;
1036 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001037 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001038 if (fd > fd_max)
1039 fd_max = fd;
1040 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001041 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001042 syscall_no = vg_waiting_fds[i].syscall_no;
1043 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001044 case __NR_read:
1045 /* In order to catch timeout events on fds which are
1046 readable and which have been ioctl(TCSETA)'d with a
1047 VTIMEout, we appear to need to ask if the fd is
1048 writable, for some reason. Ask me not why. Since this
1049 is strange and potentially troublesome we only do it if
1050 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001051 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001052 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001053 VKI_FD_SET(fd, &readfds); break;
1054 case __NR_write:
1055 VKI_FD_SET(fd, &writefds); break;
1056 default:
njne427a662002-10-02 11:08:25 +00001057 VG_(core_panic)("poll_for_ready_fds: unexpected syscall");
sewardje663cb92002-04-12 10:26:32 +00001058 /*NOTREACHED*/
1059 break;
1060 }
1061 }
1062
sewardje462e202002-04-13 04:09:07 +00001063 /* Short cut: if no fds are waiting, give up now. */
1064 if (fd_max == -1)
1065 return;
1066
sewardje663cb92002-04-12 10:26:32 +00001067 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1068 getting interrupted. */
1069 VG_(block_all_host_signals)( &saved_procmask );
1070
1071 n_ready = VG_(select)
1072 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1073 if (VG_(is_kerror)(n_ready)) {
1074 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
njne427a662002-10-02 11:08:25 +00001075 VG_(core_panic)("poll_for_ready_fds: select failed?!");
sewardje663cb92002-04-12 10:26:32 +00001076 /*NOTREACHED*/
1077 }
1078
1079 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001080 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001081
1082 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1083
1084 if (n_ready == 0)
1085 return;
1086
1087 /* Inspect all the fds we know about, and handle any completions that
1088 have happened. */
1089 /*
1090 VG_(printf)("\n\n");
1091 for (fd = 0; fd < 100; fd++)
1092 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1093 VG_(printf)("X"); } else { VG_(printf)("."); };
1094 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1095 */
1096
1097 for (fd = 0; fd <= fd_max; fd++) {
1098 rd_ok = VKI_FD_ISSET(fd, &readfds);
1099 wr_ok = VKI_FD_ISSET(fd, &writefds);
1100 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1101
1102 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1103 if (n_ok == 0)
1104 continue;
1105 if (n_ok > 1) {
1106 VG_(printf)("offending fd = %d\n", fd);
njne427a662002-10-02 11:08:25 +00001107 VG_(core_panic)("poll_for_ready_fds: multiple events on fd");
sewardje663cb92002-04-12 10:26:32 +00001108 }
sewardjbc7d8782002-06-30 12:44:54 +00001109
sewardje663cb92002-04-12 10:26:32 +00001110 /* An I/O event completed for fd. Find the thread which
1111 requested this. */
1112 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1113 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1114 continue;
1115 if (vg_waiting_fds[i].fd == fd)
1116 break;
1117 }
1118
1119 /* And a bit more paranoia ... */
1120 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1121
1122 /* Mark the fd as ready. */
1123 vg_assert(! vg_waiting_fds[i].ready);
1124 vg_waiting_fds[i].ready = True;
1125 }
1126}
1127
1128
1129/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001130static
sewardje663cb92002-04-12 10:26:32 +00001131void complete_blocked_syscalls ( void )
1132{
1133 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001134 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001135 ThreadId tid;
1136 Char msg_buf[100];
1137
1138 /* Inspect all the outstanding fds we know about. */
1139
1140 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1141 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1142 continue;
1143 if (! vg_waiting_fds[i].ready)
1144 continue;
1145
1146 fd = vg_waiting_fds[i].fd;
1147 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001148 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001149
1150 /* The thread actually has to be waiting for the I/O event it
1151 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001152 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001153 continue;
1154
1155 /* Ok, actually do it! We can safely use %EAX as the syscall
1156 number, because the speculative call made by
1157 sched_do_syscall() doesn't change %EAX in the case where the
1158 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001159 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001160 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001161
njn25e49d8e72002-09-23 09:36:25 +00001162 pre_res = vg_waiting_fds[i].pre_result;
1163
sewardjbc7d8782002-06-30 12:44:54 +00001164 /* In a rare case pertaining to writing into a pipe, write()
1165 will block when asked to write > 4096 bytes even though the
1166 kernel claims, when asked via select(), that blocking will
1167 not occur for a write on that fd. This can cause deadlocks.
1168 An easy answer is to limit the size of the write to 4096
1169 anyway and hope that the client program's logic can handle
1170 the short write. That shoulds dubious to me, so we don't do
1171 it by default. */
1172 if (syscall_no == __NR_write
1173 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1174 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1175 /* VG_(printf)("truncate write from %d to 4096\n",
1176 VG_(threads)[tid].m_edx ); */
1177 VG_(threads)[tid].m_edx = 4096;
1178 }
1179
sewardje663cb92002-04-12 10:26:32 +00001180 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001181 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001182
1183 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001184 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001185 /* Mark slot as no longer in use. */
1186 vg_waiting_fds[i].fd = -1;
1187 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001188 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001189 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1190 print_sched_event(tid, msg_buf);
1191 }
1192 }
1193}
1194
1195
1196static
sewardj5f07b662002-04-23 16:52:51 +00001197void check_for_pthread_cond_timedwait ( void )
1198{
sewardj51c0aaf2002-04-25 01:32:10 +00001199 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001200 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001201 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001202 continue;
sewardj018f7622002-05-15 21:13:39 +00001203 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001204 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001205 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001206 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001207 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001208 }
sewardj5f07b662002-04-23 16:52:51 +00001209 }
1210}
1211
1212
1213static
sewardje663cb92002-04-12 10:26:32 +00001214void nanosleep_for_a_while ( void )
1215{
1216 Int res;
1217 struct vki_timespec req;
1218 struct vki_timespec rem;
1219 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001220 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001221 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001222 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001223}
1224
1225
1226/* ---------------------------------------------------------------------
1227 The scheduler proper.
1228 ------------------------------------------------------------------ */
1229
1230/* Run user-space threads until either
1231 * Deadlock occurs
1232 * One thread asks to shutdown Valgrind
1233 * The specified number of basic blocks has gone by.
1234*/
1235VgSchedReturnCode VG_(scheduler) ( void )
1236{
1237 ThreadId tid, tid_next;
1238 UInt trc;
1239 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001240 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001241 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001242 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001243
sewardje663cb92002-04-12 10:26:32 +00001244 /* Start with the root thread. tid in general indicates the
1245 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001246 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001247
1248 /* This is the top level scheduler loop. It falls into three
1249 phases. */
1250 while (True) {
1251
sewardj6072c362002-04-19 14:40:57 +00001252 /* ======================= Phase 0 of 3 =======================
1253 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001254 stage1:
sewardj6072c362002-04-19 14:40:57 +00001255 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001256 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001257
sewardje663cb92002-04-12 10:26:32 +00001258 /* ======================= Phase 1 of 3 =======================
1259 Handle I/O completions and signals. This may change the
1260 status of various threads. Then select a new thread to run,
1261 or declare deadlock, or sleep if there are no runnable
1262 threads but some are blocked on I/O. */
1263
sewardje663cb92002-04-12 10:26:32 +00001264 /* Was a debug-stop requested? */
1265 if (VG_(bbs_to_go) == 0)
1266 goto debug_stop;
1267
1268 /* Do the following loop until a runnable thread is found, or
1269 deadlock is detected. */
1270 while (True) {
1271
1272 /* For stats purposes only. */
1273 VG_(num_scheduling_events_MAJOR) ++;
1274
1275 /* See if any I/O operations which we were waiting for have
1276 completed, and, if so, make runnable the relevant waiting
1277 threads. */
1278 poll_for_ready_fds();
1279 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001280 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001281
1282 /* See if there are any signals which need to be delivered. If
1283 so, choose thread(s) to deliver them to, and build signal
1284 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001285
1286 /* Be careful about delivering signals to a thread waiting
1287 for a mutex. In particular, when the handler is running,
1288 that thread is temporarily apparently-not-waiting for the
1289 mutex, so if it is unlocked by another thread whilst the
1290 handler is running, this thread is not informed. When the
1291 handler returns, the thread resumes waiting on the mutex,
1292 even if, as a result, it has missed the unlocking of it.
1293 Potential deadlock. This sounds all very strange, but the
1294 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001295 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001296 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001297 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001298
1299 /* Try and find a thread (tid) to run. */
1300 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001301 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001302 while (True) {
1303 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001304 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001305 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1306 || VG_(threads)[tid_next].status == VgTs_Sleeping
1307 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1308 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1309 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001310 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001311 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001312 break; /* We can run this one. */
1313 if (tid_next == tid)
1314 break; /* been all the way round */
1315 }
1316 tid = tid_next;
1317
sewardj018f7622002-05-15 21:13:39 +00001318 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001319 /* Found a suitable candidate. Fall out of this loop, so
1320 we can advance to stage 2 of the scheduler: actually
1321 running the thread. */
1322 break;
1323 }
1324
1325 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001326 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001327 /* No runnable threads and no prospect of any appearing
1328 even if we wait for an arbitrary length of time. In
1329 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001330 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001331 return VgSrc_Deadlock;
1332 }
1333
1334 /* At least one thread is in a fd-wait state. Delay for a
1335 while, and go round again, in the hope that eventually a
1336 thread becomes runnable. */
1337 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001338 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001339 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001340 }
1341
1342
1343 /* ======================= Phase 2 of 3 =======================
1344 Wahey! We've finally decided that thread tid is runnable, so
1345 we now do that. Run it for as much of a quanta as possible.
1346 Trivial requests are handled and the thread continues. The
1347 aim is not to do too many of Phase 1 since it is expensive. */
1348
1349 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001350 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001351
njn25e49d8e72002-09-23 09:36:25 +00001352 VG_TRACK( thread_run, tid );
1353
sewardje663cb92002-04-12 10:26:32 +00001354 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1355 that it decrements the counter before testing it for zero, so
1356 that if VG_(dispatch_ctr) is set to N you get at most N-1
1357 iterations. Also this means that VG_(dispatch_ctr) must
1358 exceed zero before entering the innerloop. Also also, the
1359 decrement is done before the bb is actually run, so you
1360 always get at least one decrement even if nothing happens.
1361 */
1362 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1363 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1364 else
1365 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1366
1367 /* ... and remember what we asked for. */
1368 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1369
sewardj1e8cdc92002-04-18 11:37:52 +00001370 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001371 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001372
sewardje663cb92002-04-12 10:26:32 +00001373 /* Actually run thread tid. */
1374 while (True) {
1375
sewardj7e87e382002-05-03 19:09:05 +00001376 VG_(last_run_tid) = tid;
1377
sewardje663cb92002-04-12 10:26:32 +00001378 /* For stats purposes only. */
1379 VG_(num_scheduling_events_MINOR) ++;
1380
1381 if (0)
1382 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1383 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001384# if 0
1385 if (VG_(bbs_done) > 31700000 + 0) {
1386 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001387 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001388 NULL,NULL,NULL);
1389 }
sewardj018f7622002-05-15 21:13:39 +00001390 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001391# endif
sewardje663cb92002-04-12 10:26:32 +00001392
1393 trc = run_thread_for_a_while ( tid );
1394
sewardjb3eef6b2002-05-01 00:05:27 +00001395# if 0
sewardj018f7622002-05-15 21:13:39 +00001396 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001397 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001398 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001399 }
1400# endif
1401
sewardje663cb92002-04-12 10:26:32 +00001402 /* Deal quickly with trivial scheduling events, and resume the
1403 thread. */
1404
1405 if (trc == VG_TRC_INNER_FASTMISS) {
1406 vg_assert(VG_(dispatch_ctr) > 0);
1407
1408 /* Trivial event. Miss in the fast-cache. Do a full
1409 lookup for it. */
1410 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001411 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001412 if (trans_addr == (Addr)0) {
1413 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001414 create_translation_for(
1415 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001416 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001417 if (trans_addr == (Addr)0)
njne427a662002-10-02 11:08:25 +00001418 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
sewardje663cb92002-04-12 10:26:32 +00001419 }
1420 continue; /* with this thread */
1421 }
1422
1423 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001424 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1425 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001426
1427 /* Are we really absolutely totally quitting? */
1428 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1429 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1430 VG_(message)(Vg_DebugMsg,
1431 "__libc_freeres() done; really quitting!");
1432 }
1433 return VgSrc_ExitSyscall;
1434 }
1435
sewardj124ca2a2002-06-20 10:19:38 +00001436 do_client_request(tid);
1437 /* Following the request, we try and continue with the
1438 same thread if still runnable. If not, go back to
1439 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001440 if (VG_(threads)[tid].status == VgTs_Runnable
1441 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001442 continue; /* with this thread */
1443 else
1444 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001445 }
1446
sewardj51c0aaf2002-04-25 01:32:10 +00001447 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1448 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001449 to become non-runnable. One special case: spot the
1450 client doing calls to exit() and take this as the cue
1451 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001452# if 0
1453 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001454 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001455 VG_(printf)("\nBEFORE\n");
1456 for (i = 10; i >= -10; i--)
1457 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1458 }
1459# endif
1460
sewardj1fe7b002002-07-16 01:43:15 +00001461 /* Deal with calling __libc_freeres() at exit. When the
1462 client does __NR_exit, it's exiting for good. So we
1463 then run VG_(__libc_freeres_wrapper). That quits by
1464 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1465 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001466 currently running.
1467
1468 If not valgrinding (cachegrinding, etc) don't do this.
1469 __libc_freeres does some invalid frees which crash
1470 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001471
sewardjf3fb92d2003-02-23 03:26:08 +00001472 if (VG_(threads)[tid].m_eax == __NR_exit
1473# if defined(__NR_exit_group)
1474 || VG_(threads)[tid].m_eax == __NR_exit_group
1475# endif
1476 ) {
sewardj858964b2002-10-05 14:15:43 +00001477
1478 /* If __NR_exit, remember the supplied argument. */
njn25e49d8e72002-09-23 09:36:25 +00001479 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1480
sewardj858964b2002-10-05 14:15:43 +00001481 /* Only run __libc_freeres if the skin says it's ok and
1482 it hasn't been overridden with --run-libc-freeres=no
1483 on the command line. */
1484
1485 if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
1486
sewardj00631892002-10-05 15:34:38 +00001487 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001488 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1489 VG_(message)(Vg_DebugMsg,
1490 "Caught __NR_exit; running __libc_freeres()");
1491 }
1492 VG_(nuke_all_threads_except) ( tid );
1493 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1494 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1495 goto stage1; /* party on, dudes (but not for much longer :) */
1496
1497 } else {
1498 /* We won't run __libc_freeres; just exit now. */
sewardj00631892002-10-05 15:34:38 +00001499 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001500 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1501 VG_(message)(Vg_DebugMsg,
1502 "Caught __NR_exit; quitting");
1503 }
1504 return VgSrc_ExitSyscall;
1505 }
1506
sewardjade9d0d2002-07-26 10:52:48 +00001507 }
1508
sewardj858964b2002-10-05 14:15:43 +00001509 /* We've dealt with __NR_exit at this point. */
sewardjf3fb92d2003-02-23 03:26:08 +00001510 { Bool b
1511 = VG_(threads)[tid].m_eax != __NR_exit
1512# if defined(__NR_exit_group)
1513 && VG_(threads)[tid].m_eax != __NR_exit_group
1514# endif
1515 ;
1516 vg_assert(b);
1517 }
sewardj7e87e382002-05-03 19:09:05 +00001518
sewardj83798bf2002-05-24 00:11:16 +00001519 /* Trap syscalls to __NR_sched_yield and just have this
1520 thread yield instead. Not essential, just an
1521 optimisation. */
1522 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1523 SET_EAX(tid, 0); /* syscall returns with success */
1524 goto stage1; /* find a new thread to run */
1525 }
1526
sewardj51c0aaf2002-04-25 01:32:10 +00001527 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001528
1529# if 0
1530 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001531 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001532 VG_(printf)("AFTER\n");
1533 for (i = 10; i >= -10; i--)
1534 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1535 }
1536# endif
1537
sewardj77f0fc12002-07-12 01:23:03 +00001538 if (VG_(threads)[tid].status == VgTs_Runnable) {
1539 /* Better do a signal check, since if in a tight loop
1540 with a slow syscall it may be a very long time
1541 before we get back to the main signal check in Stage 1. */
1542 sigs_delivered = VG_(deliver_signals)();
1543 if (sigs_delivered)
1544 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001545 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001546 } else {
1547 goto stage1;
1548 }
sewardj51c0aaf2002-04-25 01:32:10 +00001549 }
1550
sewardjd7fd4d22002-04-24 01:57:27 +00001551 /* It's an event we can't quickly deal with. Give up running
1552 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001553 break;
1554 }
1555
1556 /* ======================= Phase 3 of 3 =======================
1557 Handle non-trivial thread requests, mostly pthread stuff. */
1558
1559 /* Ok, we've fallen out of the dispatcher for a
1560 non-completely-trivial reason. First, update basic-block
1561 counters. */
1562
1563 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1564 vg_assert(done_this_time >= 0);
1565 VG_(bbs_to_go) -= (ULong)done_this_time;
1566 VG_(bbs_done) += (ULong)done_this_time;
1567
1568 if (0 && trc != VG_TRC_INNER_FASTMISS)
1569 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1570 tid, done_this_time, (Int)trc );
1571
1572 if (0 && trc != VG_TRC_INNER_FASTMISS)
njne0205ff2003-04-08 00:56:14 +00001573 VG_(message)(Vg_DebugMsg, "thread %d: %llu bbs, event %s",
sewardje663cb92002-04-12 10:26:32 +00001574 tid, VG_(bbs_done),
1575 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001576
sewardje663cb92002-04-12 10:26:32 +00001577 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001578 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001579
1580 switch (trc) {
1581
sewardje663cb92002-04-12 10:26:32 +00001582 case VG_TRC_INNER_COUNTERZERO:
1583 /* Timeslice is out. Let a new thread be scheduled,
1584 simply by doing nothing, causing us to arrive back at
1585 Phase 1. */
1586 if (VG_(bbs_to_go) == 0) {
1587 goto debug_stop;
1588 }
1589 vg_assert(VG_(dispatch_ctr) == 0);
1590 break;
1591
1592 case VG_TRC_UNRESUMABLE_SIGNAL:
1593 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1594 away. Again, do nothing, so we wind up back at Phase
1595 1, whereupon the signal will be "delivered". */
1596 break;
1597
sewardje663cb92002-04-12 10:26:32 +00001598 default:
1599 VG_(printf)("\ntrc = %d\n", trc);
njne427a662002-10-02 11:08:25 +00001600 VG_(core_panic)("VG_(scheduler), phase 3: "
1601 "unexpected thread return code");
sewardje663cb92002-04-12 10:26:32 +00001602 /* NOTREACHED */
1603 break;
1604
1605 } /* switch (trc) */
1606
1607 /* That completes Phase 3 of 3. Return now to the top of the
1608 main scheduler loop, to Phase 1 of 3. */
1609
1610 } /* top-level scheduler loop */
1611
1612
1613 /* NOTREACHED */
njne427a662002-10-02 11:08:25 +00001614 VG_(core_panic)("scheduler: post-main-loop ?!");
sewardje663cb92002-04-12 10:26:32 +00001615 /* NOTREACHED */
1616
1617 debug_stop:
1618 /* If we exited because of a debug stop, print the translation
1619 of the last block executed -- by translating it again, and
1620 throwing away the result. */
1621 VG_(printf)(
1622 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001623 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +00001624 VG_(threads)[tid].m_eip, NULL, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001625 VG_(printf)("\n");
1626 VG_(printf)(
1627 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1628
1629 return VgSrc_BbsDone;
1630}
1631
1632
1633/* ---------------------------------------------------------------------
1634 The pthread implementation.
1635 ------------------------------------------------------------------ */
1636
1637#include <pthread.h>
1638#include <errno.h>
1639
sewardjbf290b92002-05-01 02:28:01 +00001640#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001641 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001642
1643/* /usr/include/bits/pthreadtypes.h:
1644 typedef unsigned long int pthread_t;
1645*/
1646
sewardje663cb92002-04-12 10:26:32 +00001647
sewardj604ec3c2002-04-18 22:38:41 +00001648/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001649 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001650 -------------------------------------------------------- */
1651
sewardj20917d82002-05-28 01:36:45 +00001652/* We've decided to action a cancellation on tid. Make it jump to
1653 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1654 as the arg. */
1655static
1656void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1657{
1658 Char msg_buf[100];
1659 vg_assert(VG_(is_valid_tid)(tid));
sewardjdadc8d02002-12-08 23:24:18 +00001660
sewardj20917d82002-05-28 01:36:45 +00001661 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1662 handler -- which is really thread_exit_wrapper() in
1663 vg_libpthread.c. */
1664 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
sewardj4bdd9962002-12-26 11:51:50 +00001665
1666 /* Push a suitable arg, and mark it as readable. */
sewardj20917d82002-05-28 01:36:45 +00001667 VG_(threads)[tid].m_esp -= 4;
1668 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
sewardj4bdd9962002-12-26 11:51:50 +00001669 VG_TRACK( post_mem_write, VG_(threads)[tid].m_esp, sizeof(void*) );
1670
1671 /* Push a bogus return address. It will not return, but we still
1672 need to have it so that the arg is at the correct stack offset.
1673 Don't mark as readable; any attempt to read this is and internal
1674 valgrind bug since thread_exit_wrapper should not return. */
1675 VG_(threads)[tid].m_esp -= 4;
1676 * (UInt*)(VG_(threads)[tid].m_esp) = 0xBEADDEEF;
1677
1678 /* .cancel_pend will hold &thread_exit_wrapper */
sewardj20917d82002-05-28 01:36:45 +00001679 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
sewardjdadc8d02002-12-08 23:24:18 +00001680
1681 /* Clear out the waited-for-signals set, if needed, so as not to
1682 cause the sanity checker to bomb before
1683 cleanup_after_thread_exited() really cleans up properly for this
1684 thread. */
1685 if (VG_(threads)[tid].status == VgTs_WaitSIG) {
1686 VG_(ksigemptyset)( & VG_(threads)[tid].sigs_waited_for );
1687 }
1688
sewardj20917d82002-05-28 01:36:45 +00001689 VG_(threads)[tid].status = VgTs_Runnable;
sewardjdadc8d02002-12-08 23:24:18 +00001690
sewardj20917d82002-05-28 01:36:45 +00001691 /* Make sure we aren't cancelled again whilst handling this
1692 cancellation. */
1693 VG_(threads)[tid].cancel_st = False;
1694 if (VG_(clo_trace_sched)) {
1695 VG_(sprintf)(msg_buf,
1696 "jump to cancellation handler (hdlr = %p)",
1697 VG_(threads)[tid].cancel_pend);
1698 print_sched_event(tid, msg_buf);
1699 }
1700}
1701
1702
1703
sewardjb48e5002002-05-13 00:16:03 +00001704/* Release resources and generally clean up once a thread has finally
1705 disappeared. */
1706static
1707void cleanup_after_thread_exited ( ThreadId tid )
1708{
sewardj89f20fd2002-06-30 10:57:30 +00001709 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001710 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001711 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1712 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001713 /* Its stack is now off-limits */
1714 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1715 VG_(threads)[tid].stack_size );
1716
sewardjb48e5002002-05-13 00:16:03 +00001717 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001718 thread, and get rid of signal handlers specifically arranged for
1719 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001720 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001721 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001722
1723 /* Clean up the waiting_fd table */
1724 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1725 if (vg_waiting_fds[i].tid == tid) {
1726 vg_waiting_fds[i].fd = -1; /* not in use */
1727 }
1728 }
sewardj92a59562002-09-30 00:53:10 +00001729
1730 /* Deallocate its LDT, if it ever had one. */
1731 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1732 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001733}
1734
1735
sewardj20917d82002-05-28 01:36:45 +00001736/* Look for matching pairs of threads waiting for joiners and threads
1737 waiting for joinees. For each such pair copy the return value of
1738 the joinee into the joiner, let the joiner resume and discard the
1739 joinee. */
1740static
1741void maybe_rendezvous_joiners_and_joinees ( void )
1742{
1743 Char msg_buf[100];
1744 void** thread_return;
1745 ThreadId jnr, jee;
1746
1747 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1748 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1749 continue;
1750 jee = VG_(threads)[jnr].joiner_jee_tid;
1751 if (jee == VG_INVALID_THREADID)
1752 continue;
1753 vg_assert(VG_(is_valid_tid)(jee));
1754 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1755 continue;
1756 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1757 joined by ... well, any thread. So let's do it! */
1758
1759 /* Copy return value to where joiner wants it. */
1760 thread_return = VG_(threads)[jnr].joiner_thread_return;
1761 if (thread_return != NULL) {
1762 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001763 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1764 "pthread_join: thread_return",
1765 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001766
sewardj20917d82002-05-28 01:36:45 +00001767 *thread_return = VG_(threads)[jee].joinee_retval;
1768 /* Not really right, since it makes the thread's return value
1769 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001770 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001771 }
1772
1773 /* Joinee is discarded */
1774 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1775 cleanup_after_thread_exited ( jee );
sewardjc4a810d2002-11-13 22:25:51 +00001776 if (VG_(clo_trace_sched)) {
1777 VG_(sprintf)(msg_buf,
1778 "rendezvous with joinee %d. %d resumes, %d exits.",
1779 jee, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001780 print_sched_event(jnr, msg_buf);
1781 }
sewardjc4a810d2002-11-13 22:25:51 +00001782
1783 VG_TRACK( post_thread_join, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001784
1785 /* joiner returns with success */
1786 VG_(threads)[jnr].status = VgTs_Runnable;
1787 SET_EDX(jnr, 0);
1788 }
1789}
1790
1791
sewardjccef2e62002-05-29 19:26:32 +00001792/* Nuke all threads other than tid. POSIX specifies that this should
1793 happen in __NR_exec, and after a __NR_fork() when I am the child,
1794 as POSIX requires. */
1795void VG_(nuke_all_threads_except) ( ThreadId me )
1796{
1797 ThreadId tid;
1798 for (tid = 1; tid < VG_N_THREADS; tid++) {
1799 if (tid == me
1800 || VG_(threads)[tid].status == VgTs_Empty)
1801 continue;
sewardjef037c72002-05-30 00:40:03 +00001802 if (0)
1803 VG_(printf)(
1804 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001805 VG_(threads)[tid].status = VgTs_Empty;
1806 cleanup_after_thread_exited( tid );
1807 }
1808}
1809
1810
sewardj20917d82002-05-28 01:36:45 +00001811/* -----------------------------------------------------------
1812 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1813 -------------------------------------------------------- */
1814
sewardje663cb92002-04-12 10:26:32 +00001815static
sewardj8ad94e12002-05-29 00:10:20 +00001816void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1817{
1818 Int sp;
1819 Char msg_buf[100];
1820 vg_assert(VG_(is_valid_tid)(tid));
1821 sp = VG_(threads)[tid].custack_used;
1822 if (VG_(clo_trace_sched)) {
1823 VG_(sprintf)(msg_buf,
1824 "cleanup_push (fn %p, arg %p) -> slot %d",
1825 cu->fn, cu->arg, sp);
1826 print_sched_event(tid, msg_buf);
1827 }
1828 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1829 if (sp == VG_N_CLEANUPSTACK)
njne427a662002-10-02 11:08:25 +00001830 VG_(core_panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
sewardj8ad94e12002-05-29 00:10:20 +00001831 " Increase and recompile.");
1832 VG_(threads)[tid].custack[sp] = *cu;
1833 sp++;
1834 VG_(threads)[tid].custack_used = sp;
1835 SET_EDX(tid, 0);
1836}
1837
1838
1839static
1840void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1841{
1842 Int sp;
1843 Char msg_buf[100];
1844 vg_assert(VG_(is_valid_tid)(tid));
1845 sp = VG_(threads)[tid].custack_used;
1846 if (VG_(clo_trace_sched)) {
njn36650922002-10-04 09:18:09 +00001847 VG_(sprintf)(msg_buf, "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001848 print_sched_event(tid, msg_buf);
1849 }
1850 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1851 if (sp == 0) {
1852 SET_EDX(tid, -1);
1853 return;
1854 }
1855 sp--;
njn36650922002-10-04 09:18:09 +00001856 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
1857 "cleanup pop", (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001858 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001859 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001860 VG_(threads)[tid].custack_used = sp;
1861 SET_EDX(tid, 0);
1862}
1863
1864
1865static
sewardjff42d1d2002-05-22 13:17:31 +00001866void do_pthread_yield ( ThreadId tid )
1867{
1868 Char msg_buf[100];
1869 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001870 if (VG_(clo_trace_sched)) {
1871 VG_(sprintf)(msg_buf, "yield");
1872 print_sched_event(tid, msg_buf);
1873 }
1874 SET_EDX(tid, 0);
1875}
1876
1877
1878static
sewardj20917d82002-05-28 01:36:45 +00001879void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001880{
sewardj7989d0c2002-05-28 11:00:01 +00001881 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001882 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001883 if (VG_(clo_trace_sched)) {
1884 VG_(sprintf)(msg_buf, "testcancel");
1885 print_sched_event(tid, msg_buf);
1886 }
sewardj20917d82002-05-28 01:36:45 +00001887 if (/* is there a cancellation pending on this thread? */
1888 VG_(threads)[tid].cancel_pend != NULL
1889 && /* is this thread accepting cancellations? */
1890 VG_(threads)[tid].cancel_st) {
1891 /* Ok, let's do the cancellation. */
1892 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001893 } else {
sewardj20917d82002-05-28 01:36:45 +00001894 /* No, we keep going. */
1895 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001896 }
sewardje663cb92002-04-12 10:26:32 +00001897}
1898
1899
1900static
sewardj20917d82002-05-28 01:36:45 +00001901void do__set_cancelstate ( ThreadId tid, Int state )
1902{
1903 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001904 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001905 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001906 if (VG_(clo_trace_sched)) {
1907 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1908 state==PTHREAD_CANCEL_ENABLE
1909 ? "ENABLE"
1910 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1911 print_sched_event(tid, msg_buf);
1912 }
sewardj20917d82002-05-28 01:36:45 +00001913 old_st = VG_(threads)[tid].cancel_st;
1914 if (state == PTHREAD_CANCEL_ENABLE) {
1915 VG_(threads)[tid].cancel_st = True;
1916 } else
1917 if (state == PTHREAD_CANCEL_DISABLE) {
1918 VG_(threads)[tid].cancel_st = False;
1919 } else {
njne427a662002-10-02 11:08:25 +00001920 VG_(core_panic)("do__set_cancelstate");
sewardj20917d82002-05-28 01:36:45 +00001921 }
1922 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1923 : PTHREAD_CANCEL_DISABLE);
1924}
1925
1926
1927static
1928void do__set_canceltype ( ThreadId tid, Int type )
1929{
1930 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001931 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001932 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001933 if (VG_(clo_trace_sched)) {
1934 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1935 type==PTHREAD_CANCEL_ASYNCHRONOUS
1936 ? "ASYNCHRONOUS"
1937 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1938 print_sched_event(tid, msg_buf);
1939 }
sewardj20917d82002-05-28 01:36:45 +00001940 old_ty = VG_(threads)[tid].cancel_ty;
1941 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1942 VG_(threads)[tid].cancel_ty = False;
1943 } else
1944 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001945 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001946 } else {
njne427a662002-10-02 11:08:25 +00001947 VG_(core_panic)("do__set_canceltype");
sewardj20917d82002-05-28 01:36:45 +00001948 }
1949 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1950 : PTHREAD_CANCEL_ASYNCHRONOUS);
1951}
1952
1953
sewardj7989d0c2002-05-28 11:00:01 +00001954/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001955static
sewardj7989d0c2002-05-28 11:00:01 +00001956void do__set_or_get_detach ( ThreadId tid,
1957 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001958{
sewardj7989d0c2002-05-28 11:00:01 +00001959 ThreadId i;
1960 Char msg_buf[100];
1961 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1962 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001963 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001964 if (VG_(clo_trace_sched)) {
1965 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1966 what==0 ? "not-detached" : (
1967 what==1 ? "detached" : (
1968 what==2 ? "fetch old value" : "???")),
1969 det );
1970 print_sched_event(tid, msg_buf);
1971 }
1972
1973 if (!VG_(is_valid_tid)(det)) {
1974 SET_EDX(tid, -1);
1975 return;
1976 }
1977
sewardj20917d82002-05-28 01:36:45 +00001978 switch (what) {
1979 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001980 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001981 return;
sewardj7989d0c2002-05-28 11:00:01 +00001982 case 1: /* set detached. If someone is in a join-wait for det,
1983 do not detach. */
1984 for (i = 1; i < VG_N_THREADS; i++) {
1985 if (VG_(threads)[i].status == VgTs_WaitJoinee
1986 && VG_(threads)[i].joiner_jee_tid == det) {
1987 SET_EDX(tid, 0);
1988 if (VG_(clo_trace_sched)) {
1989 VG_(sprintf)(msg_buf,
njn9b6d34e2002-10-15 08:48:08 +00001990 "tid %d not detached because %d in join-wait for it",
sewardj7989d0c2002-05-28 11:00:01 +00001991 det, i);
1992 print_sched_event(tid, msg_buf);
1993 }
1994 return;
1995 }
1996 }
1997 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001998 SET_EDX(tid, 0);
1999 return;
2000 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00002001 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00002002 SET_EDX(tid, 0);
2003 return;
2004 default:
njne427a662002-10-02 11:08:25 +00002005 VG_(core_panic)("do__set_or_get_detach");
sewardj20917d82002-05-28 01:36:45 +00002006 }
2007}
2008
2009
2010static
2011void do__set_cancelpend ( ThreadId tid,
2012 ThreadId cee,
2013 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00002014{
2015 Char msg_buf[100];
2016
sewardj20917d82002-05-28 01:36:45 +00002017 vg_assert(VG_(is_valid_tid)(tid));
2018 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2019
sewardj7989d0c2002-05-28 11:00:01 +00002020 if (!VG_(is_valid_tid)(cee)) {
2021 if (VG_(clo_trace_sched)) {
2022 VG_(sprintf)(msg_buf,
2023 "set_cancelpend for invalid tid %d", cee);
2024 print_sched_event(tid, msg_buf);
2025 }
njn25e49d8e72002-09-23 09:36:25 +00002026 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002027 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00002028 SET_EDX(tid, -VKI_ESRCH);
2029 return;
2030 }
sewardj20917d82002-05-28 01:36:45 +00002031
2032 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
2033
2034 if (VG_(clo_trace_sched)) {
2035 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002036 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00002037 cancelpend_hdlr, tid);
2038 print_sched_event(cee, msg_buf);
2039 }
2040
2041 /* Thread doing the cancelling returns with success. */
2042 SET_EDX(tid, 0);
2043
2044 /* Perhaps we can nuke the cancellee right now? */
2045 do__testcancel(cee);
2046}
2047
2048
2049static
2050void do_pthread_join ( ThreadId tid,
2051 ThreadId jee, void** thread_return )
2052{
2053 Char msg_buf[100];
2054 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00002055 /* jee, the joinee, is the thread specified as an arg in thread
2056 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00002057 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00002058 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002059
2060 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002061 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002062 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002063 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002064 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002065 return;
2066 }
2067
sewardj20917d82002-05-28 01:36:45 +00002068 /* Flush any completed pairs, so as to make sure what we're looking
2069 at is up-to-date. */
2070 maybe_rendezvous_joiners_and_joinees();
2071
2072 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002073 if (jee < 0
2074 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002075 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002076 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002077 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002078 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002079 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002080 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002081 return;
2082 }
2083
sewardj20917d82002-05-28 01:36:45 +00002084 /* Is anyone else already in a join-wait for jee? */
2085 for (i = 1; i < VG_N_THREADS; i++) {
2086 if (i == tid) continue;
2087 if (VG_(threads)[i].status == VgTs_WaitJoinee
2088 && VG_(threads)[i].joiner_jee_tid == jee) {
2089 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002090 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002091 "pthread_join: another thread already "
2092 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002093 SET_EDX(tid, EINVAL);
2094 VG_(threads)[tid].status = VgTs_Runnable;
2095 return;
2096 }
sewardje663cb92002-04-12 10:26:32 +00002097 }
2098
sewardj20917d82002-05-28 01:36:45 +00002099 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002100 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002101 VG_(threads)[tid].joiner_thread_return = thread_return;
2102 VG_(threads)[tid].joiner_jee_tid = jee;
2103
2104 /* Look for matching joiners and joinees and do the right thing. */
2105 maybe_rendezvous_joiners_and_joinees();
2106
2107 /* Return value is irrelevant since this this thread becomes
2108 non-runnable. maybe_resume_joiner() will cause it to return the
2109 right value when it resumes. */
2110
sewardj8937c812002-04-12 20:12:20 +00002111 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002112 VG_(sprintf)(msg_buf,
2113 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002114 print_sched_event(tid, msg_buf);
2115 }
sewardje663cb92002-04-12 10:26:32 +00002116}
2117
2118
sewardj20917d82002-05-28 01:36:45 +00002119/* ( void* ): calling thread waits for joiner and returns the void* to
2120 it. This is one of two ways in which a thread can finally exit --
2121 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002122static
sewardj20917d82002-05-28 01:36:45 +00002123void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002124{
sewardj20917d82002-05-28 01:36:45 +00002125 Char msg_buf[100];
2126 vg_assert(VG_(is_valid_tid)(tid));
2127 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2128 if (VG_(clo_trace_sched)) {
2129 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002130 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002131 print_sched_event(tid, msg_buf);
2132 }
2133 VG_(threads)[tid].status = VgTs_WaitJoiner;
2134 VG_(threads)[tid].joinee_retval = retval;
2135 maybe_rendezvous_joiners_and_joinees();
2136}
2137
2138
2139/* ( no-args ): calling thread disappears from the system forever.
2140 Reclaim resources. */
2141static
2142void do__quit ( ThreadId tid )
2143{
2144 Char msg_buf[100];
2145 vg_assert(VG_(is_valid_tid)(tid));
2146 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2147 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2148 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002149 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002150 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002151 print_sched_event(tid, msg_buf);
2152 }
2153 /* Return value is irrelevant; this thread will not get
2154 rescheduled. */
2155}
2156
2157
2158/* Should never be entered. If it is, will be on the simulated
2159 CPU. */
2160static
2161void do__apply_in_new_thread_bogusRA ( void )
2162{
njne427a662002-10-02 11:08:25 +00002163 VG_(core_panic)("do__apply_in_new_thread_bogusRA");
sewardj20917d82002-05-28 01:36:45 +00002164}
2165
2166/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2167 MUST NOT return -- ever. Eventually it will do either __QUIT or
2168 __WAIT_JOINER. Return the child tid to the parent. */
2169static
2170void do__apply_in_new_thread ( ThreadId parent_tid,
2171 void* (*fn)(void *),
2172 void* arg )
2173{
sewardje663cb92002-04-12 10:26:32 +00002174 Addr new_stack;
2175 UInt new_stk_szb;
2176 ThreadId tid;
2177 Char msg_buf[100];
2178
2179 /* Paranoia ... */
2180 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2181
sewardj018f7622002-05-15 21:13:39 +00002182 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002183
sewardj1e8cdc92002-04-18 11:37:52 +00002184 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002185
2186 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002187 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002188 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002189
sewardjc4a810d2002-11-13 22:25:51 +00002190 /* do this early, before the child gets any memory writes */
2191 VG_TRACK ( post_thread_create, parent_tid, tid );
2192
sewardjf6374322002-11-13 22:35:55 +00002193 /* Create new thread with default attrs:
2194 deferred cancellation, not detached
2195 */
2196 mostly_clear_thread_record(tid);
2197 VG_(threads)[tid].status = VgTs_Runnable;
2198
sewardje663cb92002-04-12 10:26:32 +00002199 /* Copy the parent's CPU state into the child's, in a roundabout
2200 way (via baseBlock). */
2201 VG_(load_thread_state)(parent_tid);
sewardjca340b32002-12-08 22:14:11 +00002202
2203 /* We inherit our parent's LDT. */
2204 if (VG_(threads)[parent_tid].ldt == NULL) {
2205 /* We hope this is the common case. */
2206 VG_(baseBlock)[VGOFF_(ldt)] = 0;
2207 } else {
2208 /* No luck .. we have to take a copy of the parent's. */
2209 VG_(threads)[tid].ldt
2210 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2211 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
2212 }
2213
sewardje663cb92002-04-12 10:26:32 +00002214 VG_(save_thread_state)(tid);
sewardjf6374322002-11-13 22:35:55 +00002215 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +00002216
2217 /* Consider allocating the child a stack, if the one it already has
2218 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002219 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002220
sewardj018f7622002-05-15 21:13:39 +00002221 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002222 /* Again, for good measure :) We definitely don't want to be
2223 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002224 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002225 /* for now, we don't handle the case of anything other than
2226 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002227 vg_assert(VG_(threads)[tid].stack_size == 0);
2228 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002229 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2230 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002231 VG_(threads)[tid].stack_base = new_stack;
2232 VG_(threads)[tid].stack_size = new_stk_szb;
2233 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002234 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002235 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002236 }
sewardj1e8cdc92002-04-18 11:37:52 +00002237
njn25e49d8e72002-09-23 09:36:25 +00002238 /* Having got memory to hold the thread's stack:
2239 - set %esp as base + size
2240 - mark everything below %esp inaccessible
2241 - mark redzone at stack end inaccessible
2242 */
2243 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2244 + VG_(threads)[tid].stack_size
2245 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002246
njn25e49d8e72002-09-23 09:36:25 +00002247 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2248 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2249 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2250 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002251
njn25e49d8e72002-09-23 09:36:25 +00002252 /* push two args */
2253 VG_(threads)[tid].m_esp -= 8;
2254 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2255 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2256 "new thread: stack",
2257 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2258
2259 /* push arg and (bogus) return address */
2260 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002261 * (UInt*)(VG_(threads)[tid].m_esp)
2262 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002263
njn25e49d8e72002-09-23 09:36:25 +00002264 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002265
2266 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002267 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002268
sewardj8937c812002-04-12 20:12:20 +00002269 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002270 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002271 print_sched_event(tid, msg_buf);
2272 }
2273
sewardj018f7622002-05-15 21:13:39 +00002274 /* We inherit our parent's signal mask. */
2275 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002276 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002277
sewardj20917d82002-05-28 01:36:45 +00002278 /* return child's tid to parent */
2279 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002280}
2281
2282
sewardj604ec3c2002-04-18 22:38:41 +00002283/* -----------------------------------------------------------
2284 MUTEXes
2285 -------------------------------------------------------- */
2286
sewardj604ec3c2002-04-18 22:38:41 +00002287/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002288 typedef struct
2289 {
2290 int __m_reserved; -- Reserved for future use
2291 int __m_count; -- Depth of recursive locking
2292 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2293 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2294 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2295 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002296
sewardj6072c362002-04-19 14:40:57 +00002297 #define PTHREAD_MUTEX_INITIALIZER \
2298 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2299 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2300 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2301 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2302 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2303 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2304 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002305
sewardj6072c362002-04-19 14:40:57 +00002306 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002307
sewardj6072c362002-04-19 14:40:57 +00002308 __m_kind never changes and indicates whether or not it is recursive.
2309
2310 __m_count indicates the lock count; if 0, the mutex is not owned by
2311 anybody.
2312
2313 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2314 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2315 statically initialised mutexes correctly appear
2316 to belong to nobody.
2317
2318 In summary, a not-in-use mutex is distinguised by having __m_owner
2319 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2320 conditions holds, the other should too.
2321
2322 There is no linked list of threads waiting for this mutex. Instead
2323 a thread in WaitMX state points at the mutex with its waited_on_mx
2324 field. This makes _unlock() inefficient, but simple to implement the
2325 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002326
sewardj604ec3c2002-04-18 22:38:41 +00002327 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002328 deals with that for us.
2329*/
sewardje663cb92002-04-12 10:26:32 +00002330
sewardj3b5d8862002-04-20 13:53:23 +00002331/* Helper fns ... */
2332static
2333void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2334 Char* caller )
2335{
2336 Int i;
2337 Char msg_buf[100];
2338
2339 /* Find some arbitrary thread waiting on this mutex, and make it
2340 runnable. If none are waiting, mark the mutex as not held. */
2341 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002342 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002343 continue;
sewardj018f7622002-05-15 21:13:39 +00002344 if (VG_(threads)[i].status == VgTs_WaitMX
2345 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002346 break;
2347 }
2348
sewardj0af43bc2002-10-22 04:30:35 +00002349 VG_TRACK( post_mutex_unlock, (ThreadId)mutex->__m_owner, mutex );
2350
sewardj3b5d8862002-04-20 13:53:23 +00002351 vg_assert(i <= VG_N_THREADS);
2352 if (i == VG_N_THREADS) {
2353 /* Nobody else is waiting on it. */
2354 mutex->__m_count = 0;
2355 mutex->__m_owner = VG_INVALID_THREADID;
2356 } else {
2357 /* Notionally transfer the hold to thread i, whose
2358 pthread_mutex_lock() call now returns with 0 (success). */
2359 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002360 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002361 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002362 VG_(threads)[i].status = VgTs_Runnable;
2363 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002364 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002365
sewardj0af43bc2002-10-22 04:30:35 +00002366 VG_TRACK( post_mutex_lock, (ThreadId)i, mutex);
2367
sewardj3b5d8862002-04-20 13:53:23 +00002368 if (VG_(clo_trace_pthread_level) >= 1) {
2369 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2370 caller, mutex );
2371 print_pthread_event(i, msg_buf);
2372 }
2373 }
2374}
2375
sewardje663cb92002-04-12 10:26:32 +00002376
2377static
sewardj30671ff2002-04-21 00:13:57 +00002378void do_pthread_mutex_lock( ThreadId tid,
2379 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002380 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002381{
sewardj30671ff2002-04-21 00:13:57 +00002382 Char msg_buf[100];
2383 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002384 = is_trylock ? "pthread_mutex_trylock"
2385 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002386
sewardj604ec3c2002-04-18 22:38:41 +00002387 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002388 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002389 print_pthread_event(tid, msg_buf);
2390 }
2391
2392 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002393 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002394 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002395
2396 /* POSIX doesn't mandate this, but for sanity ... */
2397 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002398 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002399 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002400 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002401 return;
2402 }
2403
sewardj604ec3c2002-04-18 22:38:41 +00002404 /* More paranoia ... */
2405 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002406# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002407 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002408 case PTHREAD_MUTEX_ADAPTIVE_NP:
2409# endif
sewardja1679dd2002-05-10 22:31:40 +00002410# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002411 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002412# endif
sewardj604ec3c2002-04-18 22:38:41 +00002413 case PTHREAD_MUTEX_RECURSIVE_NP:
2414 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002415 if (mutex->__m_count >= 0) break;
2416 /* else fall thru */
2417 default:
njn25e49d8e72002-09-23 09:36:25 +00002418 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002419 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002420 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002421 return;
sewardje663cb92002-04-12 10:26:32 +00002422 }
2423
sewardj604ec3c2002-04-18 22:38:41 +00002424 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002425
sewardjb48e5002002-05-13 00:16:03 +00002426 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002427
2428 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002429 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002430 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002431 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002432 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002433 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002434 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002435 if (0)
2436 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2437 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002438 return;
2439 } else {
sewardj30671ff2002-04-21 00:13:57 +00002440 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002441 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002442 else
sewardjc3bd5f52002-05-01 03:24:23 +00002443 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002444 return;
2445 }
2446 } else {
sewardj6072c362002-04-19 14:40:57 +00002447 /* Someone else has it; we have to wait. Mark ourselves
2448 thusly. */
sewardj05553872002-04-20 20:53:17 +00002449 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002450 if (is_trylock) {
2451 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002452 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002453 } else {
sewardjdca84112002-11-13 22:29:34 +00002454 VG_TRACK ( pre_mutex_lock, tid, mutex );
2455
sewardj018f7622002-05-15 21:13:39 +00002456 VG_(threads)[tid].status = VgTs_WaitMX;
2457 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002458 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002459 if (VG_(clo_trace_pthread_level) >= 1) {
2460 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2461 caller, mutex );
2462 print_pthread_event(tid, msg_buf);
2463 }
2464 }
sewardje663cb92002-04-12 10:26:32 +00002465 return;
2466 }
sewardjf8f819e2002-04-17 23:21:37 +00002467
sewardje663cb92002-04-12 10:26:32 +00002468 } else {
sewardj6072c362002-04-19 14:40:57 +00002469 /* Nobody owns it. Sanity check ... */
2470 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjdca84112002-11-13 22:29:34 +00002471
2472 VG_TRACK ( pre_mutex_lock, tid, mutex );
2473
sewardjf8f819e2002-04-17 23:21:37 +00002474 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002475 mutex->__m_count = 1;
2476 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002477
2478 VG_TRACK( post_mutex_lock, tid, mutex);
2479
sewardje663cb92002-04-12 10:26:32 +00002480 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002481 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002482 }
sewardjf8f819e2002-04-17 23:21:37 +00002483
sewardje663cb92002-04-12 10:26:32 +00002484}
2485
2486
2487static
2488void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002489 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002490{
sewardj3b5d8862002-04-20 13:53:23 +00002491 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002492
sewardj45b4b372002-04-16 22:50:32 +00002493 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002494 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002495 print_pthread_event(tid, msg_buf);
2496 }
2497
sewardj604ec3c2002-04-18 22:38:41 +00002498 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002499 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002500 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002501
2502 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002503 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002504 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002505 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002506 return;
2507 }
2508
sewardjd8acdf22002-11-13 21:57:52 +00002509 /* If this was locked before the dawn of time, pretend it was
2510 locked now so that it balances with unlocks */
2511 if (mutex->__m_kind & VG_PTHREAD_PREHISTORY) {
2512 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
sewardjdca84112002-11-13 22:29:34 +00002513 VG_TRACK( pre_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
sewardjd8acdf22002-11-13 21:57:52 +00002514 VG_TRACK( post_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
2515 }
2516
sewardj604ec3c2002-04-18 22:38:41 +00002517 /* More paranoia ... */
2518 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002519# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002520 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002521 case PTHREAD_MUTEX_ADAPTIVE_NP:
2522# endif
sewardja1679dd2002-05-10 22:31:40 +00002523# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002524 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002525# endif
sewardj604ec3c2002-04-18 22:38:41 +00002526 case PTHREAD_MUTEX_RECURSIVE_NP:
2527 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002528 if (mutex->__m_count >= 0) break;
2529 /* else fall thru */
2530 default:
njn25e49d8e72002-09-23 09:36:25 +00002531 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002532 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002533 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002534 return;
2535 }
sewardje663cb92002-04-12 10:26:32 +00002536
2537 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002538 if (mutex->__m_count == 0) {
2539 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002540 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002541 "pthread_mutex_unlock: mutex is not locked");
2542 SET_EDX(tid, EPERM);
2543 return;
2544 }
2545
2546 if ((ThreadId)mutex->__m_owner != tid) {
2547 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002548 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002549 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002550 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002551 return;
2552 }
2553
sewardjf8f819e2002-04-17 23:21:37 +00002554 /* If it's a multiply-locked recursive mutex, just decrement the
2555 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002556 if (mutex->__m_count > 1) {
2557 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2558 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002559 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002560 return;
2561 }
2562
sewardj604ec3c2002-04-18 22:38:41 +00002563 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002564 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002565 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002566 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002567
sewardj3b5d8862002-04-20 13:53:23 +00002568 /* Release at max one thread waiting on this mutex. */
2569 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002570
sewardj3b5d8862002-04-20 13:53:23 +00002571 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002572 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002573}
2574
2575
sewardj6072c362002-04-19 14:40:57 +00002576/* -----------------------------------------------------------
2577 CONDITION VARIABLES
2578 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002579
sewardj6072c362002-04-19 14:40:57 +00002580/* The relevant native types are as follows:
2581 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002582
sewardj6072c362002-04-19 14:40:57 +00002583 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2584 typedef struct
2585 {
2586 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2587 _pthread_descr __c_waiting; -- Threads waiting on this condition
2588 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002589
sewardj6072c362002-04-19 14:40:57 +00002590 -- Attribute for conditionally variables.
2591 typedef struct
2592 {
2593 int __dummy;
2594 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002595
sewardj6072c362002-04-19 14:40:57 +00002596 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002597
sewardj3b5d8862002-04-20 13:53:23 +00002598 We don't use any fields of pthread_cond_t for anything at all.
2599 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002600
2601 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002602 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002603
sewardj77e466c2002-04-14 02:29:29 +00002604
sewardj5f07b662002-04-23 16:52:51 +00002605static
2606void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2607{
2608 Char msg_buf[100];
2609 pthread_mutex_t* mx;
2610 pthread_cond_t* cv;
2611
sewardjb48e5002002-05-13 00:16:03 +00002612 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002613 && VG_(threads)[tid].status == VgTs_WaitCV
2614 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2615 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002616 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002617 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002618 vg_assert(cv != NULL);
2619
2620 if (mx->__m_owner == VG_INVALID_THREADID) {
2621 /* Currently unheld; hand it out to thread tid. */
2622 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002623 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002624 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002625 VG_(threads)[tid].associated_cv = NULL;
2626 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002627 mx->__m_owner = (_pthread_descr)tid;
2628 mx->__m_count = 1;
2629
sewardj0af43bc2002-10-22 04:30:35 +00002630 VG_TRACK( post_mutex_lock, tid, mx );
2631
sewardj5f07b662002-04-23 16:52:51 +00002632 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002633 VG_(sprintf)(msg_buf,
2634 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2635 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002636 print_pthread_event(tid, msg_buf);
2637 }
2638 } else {
2639 /* Currently held. Make thread tid be blocked on it. */
2640 vg_assert(mx->__m_count > 0);
sewardjdca84112002-11-13 22:29:34 +00002641 VG_TRACK( pre_mutex_lock, tid, mx );
2642
sewardj018f7622002-05-15 21:13:39 +00002643 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002644 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002645 VG_(threads)[tid].associated_cv = NULL;
2646 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002647 if (VG_(clo_trace_pthread_level) >= 1) {
2648 VG_(sprintf)(msg_buf,
2649 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2650 cv, mx );
2651 print_pthread_event(tid, msg_buf);
2652 }
2653
2654 }
2655}
2656
2657
sewardj3b5d8862002-04-20 13:53:23 +00002658static
2659void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2660 Int n_to_release,
2661 Char* caller )
2662{
2663 Int i;
2664 Char msg_buf[100];
2665 pthread_mutex_t* mx;
2666
2667 while (True) {
2668 if (n_to_release == 0)
2669 return;
2670
2671 /* Find a thread waiting on this CV. */
2672 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002673 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002674 continue;
sewardj018f7622002-05-15 21:13:39 +00002675 if (VG_(threads)[i].status == VgTs_WaitCV
2676 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002677 break;
2678 }
2679 vg_assert(i <= VG_N_THREADS);
2680
2681 if (i == VG_N_THREADS) {
2682 /* Nobody else is waiting on it. */
2683 return;
2684 }
2685
sewardj018f7622002-05-15 21:13:39 +00002686 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002687 vg_assert(mx != NULL);
2688
sewardjdca84112002-11-13 22:29:34 +00002689 VG_TRACK( pre_mutex_lock, i, mx );
2690
sewardj3b5d8862002-04-20 13:53:23 +00002691 if (mx->__m_owner == VG_INVALID_THREADID) {
2692 /* Currently unheld; hand it out to thread i. */
2693 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002694 VG_(threads)[i].status = VgTs_Runnable;
2695 VG_(threads)[i].associated_cv = NULL;
2696 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002697 mx->__m_owner = (_pthread_descr)i;
2698 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002699 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002700
sewardj0af43bc2002-10-22 04:30:35 +00002701 VG_TRACK( post_mutex_lock, i, mx );
2702
sewardj3b5d8862002-04-20 13:53:23 +00002703 if (VG_(clo_trace_pthread_level) >= 1) {
2704 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2705 caller, cond, mx );
2706 print_pthread_event(i, msg_buf);
2707 }
2708
2709 } else {
2710 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002711 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002712 VG_(threads)[i].status = VgTs_WaitMX;
2713 VG_(threads)[i].associated_cv = NULL;
2714 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002715 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002716
2717 if (VG_(clo_trace_pthread_level) >= 1) {
2718 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2719 caller, cond, mx );
2720 print_pthread_event(i, msg_buf);
2721 }
2722
2723 }
2724
2725 n_to_release--;
2726 }
2727}
2728
2729
2730static
2731void do_pthread_cond_wait ( ThreadId tid,
2732 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002733 pthread_mutex_t *mutex,
2734 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002735{
2736 Char msg_buf[100];
2737
sewardj5f07b662002-04-23 16:52:51 +00002738 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2739 ms_end is the ending millisecond. */
2740
sewardj3b5d8862002-04-20 13:53:23 +00002741 /* pre: mutex should be a valid mutex and owned by tid. */
2742 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002743 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2744 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002745 print_pthread_event(tid, msg_buf);
2746 }
2747
2748 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002749 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002750 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002751
2752 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002753 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002754 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002755 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002756 return;
2757 }
2758
2759 /* More paranoia ... */
2760 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002761# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002762 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002763 case PTHREAD_MUTEX_ADAPTIVE_NP:
2764# endif
sewardja1679dd2002-05-10 22:31:40 +00002765# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002766 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002767# endif
sewardj3b5d8862002-04-20 13:53:23 +00002768 case PTHREAD_MUTEX_RECURSIVE_NP:
2769 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002770 if (mutex->__m_count >= 0) break;
2771 /* else fall thru */
2772 default:
njn25e49d8e72002-09-23 09:36:25 +00002773 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002774 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002775 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002776 return;
2777 }
2778
2779 /* Barf if we don't currently hold the mutex. */
2780 if (mutex->__m_count == 0 /* nobody holds it */
2781 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002782 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002783 "pthread_cond_wait/timedwait: mutex is unlocked "
2784 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002785 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002786 return;
2787 }
2788
2789 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002790 VG_(threads)[tid].status = VgTs_WaitCV;
2791 VG_(threads)[tid].associated_cv = cond;
2792 VG_(threads)[tid].associated_mx = mutex;
2793 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002794
2795 if (VG_(clo_trace_pthread_level) >= 1) {
2796 VG_(sprintf)(msg_buf,
2797 "pthread_cond_wait cv %p, mx %p: BLOCK",
2798 cond, mutex );
2799 print_pthread_event(tid, msg_buf);
2800 }
2801
2802 /* Release the mutex. */
2803 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2804}
2805
2806
2807static
2808void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2809 Bool broadcast,
2810 pthread_cond_t *cond )
2811{
2812 Char msg_buf[100];
2813 Char* caller
2814 = broadcast ? "pthread_cond_broadcast"
2815 : "pthread_cond_signal ";
2816
2817 if (VG_(clo_trace_pthread_level) >= 2) {
2818 VG_(sprintf)(msg_buf, "%s cv %p ...",
2819 caller, cond );
2820 print_pthread_event(tid, msg_buf);
2821 }
2822
2823 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002824 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002825 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002826
2827 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002828 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002829 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002830 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002831 return;
2832 }
2833
2834 release_N_threads_waiting_on_cond (
2835 cond,
2836 broadcast ? VG_N_THREADS : 1,
2837 caller
2838 );
2839
sewardjc3bd5f52002-05-01 03:24:23 +00002840 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002841}
2842
sewardj77e466c2002-04-14 02:29:29 +00002843
sewardj5f07b662002-04-23 16:52:51 +00002844/* -----------------------------------------------------------
2845 THREAD SPECIFIC DATA
2846 -------------------------------------------------------- */
2847
2848static __inline__
2849Bool is_valid_key ( ThreadKey k )
2850{
2851 /* k unsigned; hence no < 0 check */
2852 if (k >= VG_N_THREAD_KEYS) return False;
2853 if (!vg_thread_keys[k].inuse) return False;
2854 return True;
2855}
2856
sewardj00a66b12002-10-12 16:42:35 +00002857
2858/* Return in %EDX a value of 1 if the key is valid, else 0. */
2859static
2860void do_pthread_key_validate ( ThreadId tid,
2861 pthread_key_t key )
2862{
2863 Char msg_buf[100];
2864
2865 if (VG_(clo_trace_pthread_level) >= 1) {
2866 VG_(sprintf)(msg_buf, "pthread_key_validate key %p",
2867 key );
2868 print_pthread_event(tid, msg_buf);
2869 }
2870
2871 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
2872 vg_assert(VG_(is_valid_tid)(tid)
2873 && VG_(threads)[tid].status == VgTs_Runnable);
2874
2875 if (is_valid_key((ThreadKey)key)) {
2876 SET_EDX(tid, 1);
2877 } else {
2878 SET_EDX(tid, 0);
2879 }
2880}
2881
2882
sewardj5f07b662002-04-23 16:52:51 +00002883static
2884void do_pthread_key_create ( ThreadId tid,
2885 pthread_key_t* key,
2886 void (*destructor)(void*) )
2887{
2888 Int i;
2889 Char msg_buf[100];
2890
2891 if (VG_(clo_trace_pthread_level) >= 1) {
2892 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2893 key, destructor );
2894 print_pthread_event(tid, msg_buf);
2895 }
2896
2897 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002898 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002899 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002900
2901 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2902 if (!vg_thread_keys[i].inuse)
2903 break;
2904
2905 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002906 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002907 return;
2908 */
njne427a662002-10-02 11:08:25 +00002909 VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2910 " increase and recompile");
sewardj5f07b662002-04-23 16:52:51 +00002911 }
2912
sewardj870497a2002-05-29 01:06:47 +00002913 vg_thread_keys[i].inuse = True;
2914 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002915
sewardj5a3798b2002-06-04 23:24:22 +00002916 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002917 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2918 "pthread_key_create: key",
2919 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002920 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002921 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002922
2923 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002924}
2925
2926
2927static
2928void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2929{
2930 Char msg_buf[100];
2931 if (VG_(clo_trace_pthread_level) >= 1) {
2932 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2933 key );
2934 print_pthread_event(tid, msg_buf);
2935 }
2936
sewardjb48e5002002-05-13 00:16:03 +00002937 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002938 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002939
2940 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002941 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002942 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002943 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002944 return;
2945 }
2946
2947 vg_thread_keys[key].inuse = False;
sewardj648b3152002-12-09 19:07:59 +00002948 vg_thread_keys[key].destructor = NULL;
sewardj00a66b12002-10-12 16:42:35 +00002949 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002950}
2951
2952
sewardj00a66b12002-10-12 16:42:35 +00002953/* Get the .specific_ptr for a thread. Return 1 if the thread-slot
2954 isn't in use, so that client-space can scan all thread slots. 1
2955 cannot be confused with NULL or a legitimately-aligned specific_ptr
2956 value. */
sewardj5f07b662002-04-23 16:52:51 +00002957static
sewardj00a66b12002-10-12 16:42:35 +00002958void do_pthread_getspecific_ptr ( ThreadId tid )
sewardj5f07b662002-04-23 16:52:51 +00002959{
sewardj00a66b12002-10-12 16:42:35 +00002960 void** specifics_ptr;
2961 Char msg_buf[100];
2962
sewardj5f07b662002-04-23 16:52:51 +00002963 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002964 VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
sewardj5f07b662002-04-23 16:52:51 +00002965 print_pthread_event(tid, msg_buf);
2966 }
2967
sewardj00a66b12002-10-12 16:42:35 +00002968 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardj5f07b662002-04-23 16:52:51 +00002969
sewardj00a66b12002-10-12 16:42:35 +00002970 if (VG_(threads)[tid].status == VgTs_Empty) {
2971 SET_EDX(tid, 1);
sewardj5f07b662002-04-23 16:52:51 +00002972 return;
2973 }
2974
sewardj00a66b12002-10-12 16:42:35 +00002975 specifics_ptr = VG_(threads)[tid].specifics_ptr;
2976 vg_assert(specifics_ptr == NULL
2977 || IS_ALIGNED4_ADDR(specifics_ptr));
2978
2979 SET_EDX(tid, (UInt)specifics_ptr);
sewardj5f07b662002-04-23 16:52:51 +00002980}
2981
2982
2983static
sewardj00a66b12002-10-12 16:42:35 +00002984void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
sewardj5f07b662002-04-23 16:52:51 +00002985{
2986 Char msg_buf[100];
2987 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002988 VG_(sprintf)(msg_buf, "pthread_setspecific_ptr ptr %p",
2989 ptr );
sewardj5f07b662002-04-23 16:52:51 +00002990 print_pthread_event(tid, msg_buf);
2991 }
2992
sewardjb48e5002002-05-13 00:16:03 +00002993 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002994 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002995
sewardj00a66b12002-10-12 16:42:35 +00002996 VG_(threads)[tid].specifics_ptr = ptr;
sewardjc3bd5f52002-05-01 03:24:23 +00002997 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002998}
2999
3000
sewardj870497a2002-05-29 01:06:47 +00003001/* Helper for calling destructors at thread exit. If key is valid,
3002 copy the thread's specific value into cu->arg and put the *key*'s
3003 destructor fn address in cu->fn. Then return 0 to the caller.
3004 Otherwise return non-zero to the caller. */
3005static
3006void do__get_key_destr_and_spec ( ThreadId tid,
3007 pthread_key_t key,
3008 CleanupEntry* cu )
3009{
3010 Char msg_buf[100];
3011 if (VG_(clo_trace_pthread_level) >= 1) {
3012 VG_(sprintf)(msg_buf,
3013 "get_key_destr_and_arg (key = %d)", key );
3014 print_pthread_event(tid, msg_buf);
3015 }
3016 vg_assert(VG_(is_valid_tid)(tid));
3017 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00003018
sewardj870497a2002-05-29 01:06:47 +00003019 if (!vg_thread_keys[key].inuse) {
3020 SET_EDX(tid, -1);
3021 return;
3022 }
njn36650922002-10-04 09:18:09 +00003023 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
sewardj00a66b12002-10-12 16:42:35 +00003024 "get_key_destr_and_spec: cu", (Addr)cu,
njn36650922002-10-04 09:18:09 +00003025 sizeof(CleanupEntry) );
sewardj00a66b12002-10-12 16:42:35 +00003026
sewardj870497a2002-05-29 01:06:47 +00003027 cu->fn = vg_thread_keys[key].destructor;
sewardj00a66b12002-10-12 16:42:35 +00003028 if (VG_(threads)[tid].specifics_ptr == NULL) {
3029 cu->arg = NULL;
3030 } else {
3031 VG_TRACK( pre_mem_read, Vg_CorePThread, & VG_(threads)[tid],
3032 "get_key_destr_and_spec: key",
3033 (Addr)(&VG_(threads)[tid].specifics_ptr[key]),
3034 sizeof(void*) );
3035 cu->arg = VG_(threads)[tid].specifics_ptr[key];
3036 }
3037
njn25e49d8e72002-09-23 09:36:25 +00003038 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00003039 SET_EDX(tid, 0);
3040}
3041
3042
sewardjb48e5002002-05-13 00:16:03 +00003043/* ---------------------------------------------------
3044 SIGNALS
3045 ------------------------------------------------ */
3046
3047/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00003048 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
3049 for OK and 1 for some kind of addressing error, which the
3050 vg_libpthread.c routine turns into return values 0 and EFAULT
3051 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00003052static
3053void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00003054 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00003055 vki_ksigset_t* newmask,
3056 vki_ksigset_t* oldmask )
3057{
3058 Char msg_buf[100];
3059 if (VG_(clo_trace_pthread_level) >= 1) {
3060 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00003061 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
3062 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003063 print_pthread_event(tid, msg_buf);
3064 }
3065
3066 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003067 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003068
njn25e49d8e72002-09-23 09:36:25 +00003069 if (newmask)
3070 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3071 "pthread_sigmask: newmask",
3072 (Addr)newmask, sizeof(vki_ksigset_t));
3073 if (oldmask)
3074 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3075 "pthread_sigmask: oldmask",
3076 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00003077
sewardj018f7622002-05-15 21:13:39 +00003078 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003079
njn25e49d8e72002-09-23 09:36:25 +00003080 if (oldmask)
3081 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00003082
sewardj018f7622002-05-15 21:13:39 +00003083 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00003084 SET_EDX(tid, 0);
3085}
3086
3087
3088static
3089void do_sigwait ( ThreadId tid,
3090 vki_ksigset_t* set,
3091 Int* sig )
3092{
sewardj018f7622002-05-15 21:13:39 +00003093 vki_ksigset_t irrelevant_sigmask;
3094 Char msg_buf[100];
3095
sewardjb48e5002002-05-13 00:16:03 +00003096 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3097 VG_(sprintf)(msg_buf,
3098 "suspend due to sigwait(): set %p, sig %p",
3099 set, sig );
3100 print_pthread_event(tid, msg_buf);
3101 }
3102
3103 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003104 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003105
sewardj018f7622002-05-15 21:13:39 +00003106 /* Change SCSS */
3107 VG_(threads)[tid].sigs_waited_for = *set;
3108 VG_(threads)[tid].status = VgTs_WaitSIG;
3109
3110 VG_(block_all_host_signals)( &irrelevant_sigmask );
3111 VG_(handle_SCSS_change)( False /* lazy update */ );
3112}
3113
3114
3115static
3116void do_pthread_kill ( ThreadId tid, /* me */
3117 ThreadId thread, /* thread to signal */
3118 Int sig )
3119{
3120 Char msg_buf[100];
3121
3122 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3123 VG_(sprintf)(msg_buf,
3124 "pthread_kill thread %d, signo %d",
3125 thread, sig );
3126 print_pthread_event(tid, msg_buf);
3127 }
3128
3129 vg_assert(VG_(is_valid_tid)(tid)
3130 && VG_(threads)[tid].status == VgTs_Runnable);
3131
sewardj4dced352002-06-04 22:54:20 +00003132 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003133 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003134 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003135 SET_EDX(tid, -VKI_ESRCH);
3136 return;
3137 }
3138
3139 if (sig < 1 || sig > VKI_KNSIG) {
3140 SET_EDX(tid, -VKI_EINVAL);
3141 return;
3142 }
3143
3144 VG_(send_signal_to_thread)( thread, sig );
3145 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003146}
3147
3148
sewardj2cb00342002-06-28 01:46:26 +00003149/* -----------------------------------------------------------
3150 FORK HANDLERS.
3151 -------------------------------------------------------- */
3152
3153static
3154void do__set_fhstack_used ( ThreadId tid, Int n )
3155{
3156 Char msg_buf[100];
3157 if (VG_(clo_trace_sched)) {
3158 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3159 print_pthread_event(tid, msg_buf);
3160 }
3161
3162 vg_assert(VG_(is_valid_tid)(tid)
3163 && VG_(threads)[tid].status == VgTs_Runnable);
3164
3165 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3166 vg_fhstack_used = n;
3167 SET_EDX(tid, 0);
3168 } else {
3169 SET_EDX(tid, -1);
3170 }
3171}
3172
3173
3174static
3175void do__get_fhstack_used ( ThreadId tid )
3176{
3177 Int n;
3178 Char msg_buf[100];
3179 if (VG_(clo_trace_sched)) {
3180 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3181 print_pthread_event(tid, msg_buf);
3182 }
3183
3184 vg_assert(VG_(is_valid_tid)(tid)
3185 && VG_(threads)[tid].status == VgTs_Runnable);
3186
3187 n = vg_fhstack_used;
3188 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3189 SET_EDX(tid, n);
3190}
3191
3192static
3193void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3194{
3195 Char msg_buf[100];
3196 if (VG_(clo_trace_sched)) {
3197 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3198 print_pthread_event(tid, msg_buf);
3199 }
3200
3201 vg_assert(VG_(is_valid_tid)(tid)
3202 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003203 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3204 "pthread_atfork: prepare/parent/child",
3205 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003206
njn25e49d8e72002-09-23 09:36:25 +00003207 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003208 SET_EDX(tid, -1);
3209 return;
3210 }
3211
3212 vg_fhstack[n] = *fh;
3213 SET_EDX(tid, 0);
3214}
3215
3216
3217static
3218void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3219 ForkHandlerEntry* fh )
3220{
3221 Char msg_buf[100];
3222 if (VG_(clo_trace_sched)) {
3223 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3224 print_pthread_event(tid, msg_buf);
3225 }
3226
3227 vg_assert(VG_(is_valid_tid)(tid)
3228 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003229 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3230 "fork: prepare/parent/child",
3231 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003232
njn25e49d8e72002-09-23 09:36:25 +00003233 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003234 SET_EDX(tid, -1);
3235 return;
3236 }
3237
3238 *fh = vg_fhstack[n];
3239 SET_EDX(tid, 0);
3240
njn25e49d8e72002-09-23 09:36:25 +00003241 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003242}
3243
3244
sewardje663cb92002-04-12 10:26:32 +00003245/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003246 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003247 ------------------------------------------------------------------ */
3248
sewardj124ca2a2002-06-20 10:19:38 +00003249/* Do a client request for the thread tid. After the request, tid may
3250 or may not still be runnable; if not, the scheduler will have to
3251 choose a new thread to run.
3252*/
sewardje663cb92002-04-12 10:26:32 +00003253static
sewardj124ca2a2002-06-20 10:19:38 +00003254void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003255{
njn25e49d8e72002-09-23 09:36:25 +00003256# define RETURN_WITH(vvv) \
3257 { tst->m_edx = (vvv); \
3258 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003259 }
3260
3261 ThreadState* tst = &VG_(threads)[tid];
3262 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3263 UInt req_no = arg[0];
3264
3265 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003266 switch (req_no) {
3267
sewardj124ca2a2002-06-20 10:19:38 +00003268 case VG_USERREQ__MALLOC:
3269 RETURN_WITH(
3270 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3271 );
3272 break;
3273
3274 case VG_USERREQ__BUILTIN_NEW:
3275 RETURN_WITH(
3276 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3277 );
3278 break;
3279
3280 case VG_USERREQ__BUILTIN_VEC_NEW:
3281 RETURN_WITH(
3282 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3283 );
3284 break;
3285
3286 case VG_USERREQ__FREE:
3287 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3288 RETURN_WITH(0); /* irrelevant */
3289 break;
3290
3291 case VG_USERREQ__BUILTIN_DELETE:
3292 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3293 RETURN_WITH(0); /* irrelevant */
3294 break;
3295
3296 case VG_USERREQ__BUILTIN_VEC_DELETE:
3297 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3298 RETURN_WITH(0); /* irrelevant */
3299 break;
3300
3301 case VG_USERREQ__CALLOC:
3302 RETURN_WITH(
3303 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3304 );
3305 break;
3306
3307 case VG_USERREQ__REALLOC:
3308 RETURN_WITH(
3309 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3310 );
3311 break;
3312
3313 case VG_USERREQ__MEMALIGN:
3314 RETURN_WITH(
3315 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3316 );
3317 break;
3318
3319 case VG_USERREQ__PTHREAD_GET_THREADID:
3320 RETURN_WITH(tid);
3321 break;
3322
3323 case VG_USERREQ__RUNNING_ON_VALGRIND:
3324 RETURN_WITH(1);
3325 break;
3326
3327 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3328 RETURN_WITH(VG_(clo_trace_pthread_level));
3329 break;
3330
3331 case VG_USERREQ__READ_MILLISECOND_TIMER:
3332 RETURN_WITH(VG_(read_millisecond_timer)());
3333 break;
3334
3335 /* Some of these may make thread tid non-runnable, but the
3336 scheduler checks for that on return from this function. */
3337 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3338 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3339 break;
3340
3341 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3342 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3343 break;
3344
3345 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3346 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3347 break;
3348
sewardj00a66b12002-10-12 16:42:35 +00003349 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
3350 do_pthread_getspecific_ptr ( tid );
sewardj124ca2a2002-06-20 10:19:38 +00003351 break;
3352
3353 case VG_USERREQ__SET_CANCELTYPE:
3354 do__set_canceltype ( tid, arg[1] );
3355 break;
3356
3357 case VG_USERREQ__CLEANUP_PUSH:
3358 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3359 break;
3360
3361 case VG_USERREQ__CLEANUP_POP:
3362 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3363 break;
3364
3365 case VG_USERREQ__TESTCANCEL:
3366 do__testcancel ( tid );
3367 break;
3368
3369 case VG_USERREQ__GET_N_SIGS_RETURNED:
3370 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3371 break;
3372
sewardje663cb92002-04-12 10:26:32 +00003373 case VG_USERREQ__PTHREAD_JOIN:
3374 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3375 break;
3376
sewardj3b5d8862002-04-20 13:53:23 +00003377 case VG_USERREQ__PTHREAD_COND_WAIT:
3378 do_pthread_cond_wait( tid,
3379 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003380 (pthread_mutex_t *)(arg[2]),
3381 0xFFFFFFFF /* no timeout */ );
3382 break;
3383
3384 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3385 do_pthread_cond_wait( tid,
3386 (pthread_cond_t *)(arg[1]),
3387 (pthread_mutex_t *)(arg[2]),
3388 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003389 break;
3390
3391 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3392 do_pthread_cond_signal_or_broadcast(
3393 tid,
3394 False, /* signal, not broadcast */
3395 (pthread_cond_t *)(arg[1]) );
3396 break;
3397
3398 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3399 do_pthread_cond_signal_or_broadcast(
3400 tid,
3401 True, /* broadcast, not signal */
3402 (pthread_cond_t *)(arg[1]) );
3403 break;
3404
sewardj00a66b12002-10-12 16:42:35 +00003405 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
3406 do_pthread_key_validate ( tid,
3407 (pthread_key_t)(arg[1]) );
3408 break;
3409
sewardj5f07b662002-04-23 16:52:51 +00003410 case VG_USERREQ__PTHREAD_KEY_CREATE:
3411 do_pthread_key_create ( tid,
3412 (pthread_key_t*)(arg[1]),
3413 (void(*)(void*))(arg[2]) );
3414 break;
3415
3416 case VG_USERREQ__PTHREAD_KEY_DELETE:
3417 do_pthread_key_delete ( tid,
3418 (pthread_key_t)(arg[1]) );
3419 break;
3420
sewardj00a66b12002-10-12 16:42:35 +00003421 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
3422 do_pthread_setspecific_ptr ( tid,
3423 (void**)(arg[1]) );
sewardj5f07b662002-04-23 16:52:51 +00003424 break;
3425
sewardjb48e5002002-05-13 00:16:03 +00003426 case VG_USERREQ__PTHREAD_SIGMASK:
3427 do_pthread_sigmask ( tid,
3428 arg[1],
3429 (vki_ksigset_t*)(arg[2]),
3430 (vki_ksigset_t*)(arg[3]) );
3431 break;
3432
3433 case VG_USERREQ__SIGWAIT:
3434 do_sigwait ( tid,
3435 (vki_ksigset_t*)(arg[1]),
3436 (Int*)(arg[2]) );
3437 break;
3438
sewardj018f7622002-05-15 21:13:39 +00003439 case VG_USERREQ__PTHREAD_KILL:
3440 do_pthread_kill ( tid, arg[1], arg[2] );
3441 break;
3442
sewardjff42d1d2002-05-22 13:17:31 +00003443 case VG_USERREQ__PTHREAD_YIELD:
3444 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003445 /* On return from do_client_request(), the scheduler will
3446 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003447 break;
sewardj018f7622002-05-15 21:13:39 +00003448
sewardj7989d0c2002-05-28 11:00:01 +00003449 case VG_USERREQ__SET_CANCELSTATE:
3450 do__set_cancelstate ( tid, arg[1] );
3451 break;
3452
sewardj7989d0c2002-05-28 11:00:01 +00003453 case VG_USERREQ__SET_OR_GET_DETACH:
3454 do__set_or_get_detach ( tid, arg[1], arg[2] );
3455 break;
3456
3457 case VG_USERREQ__SET_CANCELPEND:
3458 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3459 break;
3460
3461 case VG_USERREQ__WAIT_JOINER:
3462 do__wait_joiner ( tid, (void*)arg[1] );
3463 break;
3464
3465 case VG_USERREQ__QUIT:
3466 do__quit ( tid );
3467 break;
3468
3469 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3470 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3471 (void*)arg[2] );
3472 break;
3473
sewardj870497a2002-05-29 01:06:47 +00003474 case VG_USERREQ__GET_KEY_D_AND_S:
3475 do__get_key_destr_and_spec ( tid,
3476 (pthread_key_t)arg[1],
3477 (CleanupEntry*)arg[2] );
3478 break;
3479
sewardjef037c72002-05-30 00:40:03 +00003480 case VG_USERREQ__NUKE_OTHER_THREADS:
3481 VG_(nuke_all_threads_except) ( tid );
3482 SET_EDX(tid, 0);
3483 break;
3484
sewardj4dced352002-06-04 22:54:20 +00003485 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003486 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003487 SET_EDX(tid, 0);
3488 break;
3489
sewardj2cb00342002-06-28 01:46:26 +00003490 case VG_USERREQ__SET_FHSTACK_USED:
3491 do__set_fhstack_used( tid, (Int)(arg[1]) );
3492 break;
3493
3494 case VG_USERREQ__GET_FHSTACK_USED:
3495 do__get_fhstack_used( tid );
3496 break;
3497
3498 case VG_USERREQ__SET_FHSTACK_ENTRY:
3499 do__set_fhstack_entry( tid, (Int)(arg[1]),
3500 (ForkHandlerEntry*)(arg[2]) );
3501 break;
3502
3503 case VG_USERREQ__GET_FHSTACK_ENTRY:
3504 do__get_fhstack_entry( tid, (Int)(arg[1]),
3505 (ForkHandlerEntry*)(arg[2]) );
3506 break;
3507
sewardj77e466c2002-04-14 02:29:29 +00003508 case VG_USERREQ__SIGNAL_RETURNS:
3509 handle_signal_return(tid);
3510 break;
sewardj69a72a52002-11-03 13:41:41 +00003511
3512 case VG_USERREQ__LOGMESSAGE:
3513 VG_(message)(Vg_UserMsg, "%s", (Char*)(arg[1]));
3514 break;
sewardj54cacf02002-04-12 23:24:59 +00003515
njn25e49d8e72002-09-23 09:36:25 +00003516 /* Requests from the client program */
3517
3518 case VG_USERREQ__DISCARD_TRANSLATIONS:
3519 if (VG_(clo_verbosity) > 2)
3520 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3521 " addr %p, len %d\n",
3522 (void*)arg[1], arg[2] );
3523
3524 VG_(invalidate_translations)( arg[1], arg[2] );
3525
3526 SET_EDX( tid, 0 ); /* return value is meaningless */
3527 break;
3528
sewardje663cb92002-04-12 10:26:32 +00003529 default:
njn25e49d8e72002-09-23 09:36:25 +00003530 if (VG_(needs).client_requests) {
sewardj34042512002-10-22 04:14:35 +00003531 UInt ret;
3532
njn25e49d8e72002-09-23 09:36:25 +00003533 if (VG_(clo_verbosity) > 2)
3534 VG_(printf)("client request: code %d, addr %p, len %d\n",
3535 arg[0], (void*)arg[1], arg[2] );
3536
sewardj34042512002-10-22 04:14:35 +00003537 if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret ))
3538 SET_EDX(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00003539 } else {
sewardj34042512002-10-22 04:14:35 +00003540 static Bool whined = False;
3541
3542 if (!whined) {
3543 VG_(message)(Vg_UserMsg, "Warning:\n"
3544 " unhandled client request: 0x%x (%c%c+%d). Perhaps\n"
3545 " VG_(needs).client_requests should be set?\n",
3546 arg[0], (arg[0] >> 24) & 0xff, (arg[0] >> 16) & 0xff,
3547 arg[0] & 0xffff);
3548 whined = True;
3549 }
njn25e49d8e72002-09-23 09:36:25 +00003550 }
sewardje663cb92002-04-12 10:26:32 +00003551 break;
3552 }
sewardj124ca2a2002-06-20 10:19:38 +00003553
3554# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003555}
3556
3557
sewardj6072c362002-04-19 14:40:57 +00003558/* ---------------------------------------------------------------------
3559 Sanity checking.
3560 ------------------------------------------------------------------ */
3561
3562/* Internal consistency checks on the sched/pthread structures. */
3563static
3564void scheduler_sanity ( void )
3565{
sewardj3b5d8862002-04-20 13:53:23 +00003566 pthread_mutex_t* mx;
3567 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003568 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003569
sewardj6072c362002-04-19 14:40:57 +00003570 /* VG_(printf)("scheduler_sanity\n"); */
3571 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003572 mx = VG_(threads)[i].associated_mx;
3573 cv = VG_(threads)[i].associated_cv;
3574 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003575 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3576 it's actually held by someone, since otherwise this thread
3577 is deadlocked, (4) the mutex's owner is not us, since
3578 otherwise this thread is also deadlocked. The logic in
3579 do_pthread_mutex_lock rejects attempts by a thread to lock
3580 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003581
sewardjbf290b92002-05-01 02:28:01 +00003582 (2) has been seen to fail sometimes. I don't know why.
3583 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003584 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003585 /* 1 */ vg_assert(mx != NULL);
3586 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003587 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003588 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003589 } else
sewardj018f7622002-05-15 21:13:39 +00003590 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003591 vg_assert(cv != NULL);
3592 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003593 } else {
sewardj05553872002-04-20 20:53:17 +00003594 /* Unfortunately these don't hold true when a sighandler is
3595 running. To be fixed. */
3596 /* vg_assert(cv == NULL); */
3597 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003598 }
sewardjbf290b92002-05-01 02:28:01 +00003599
sewardj018f7622002-05-15 21:13:39 +00003600 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003601 Int
sewardj018f7622002-05-15 21:13:39 +00003602 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3603 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003604 if (i > 1 /* not the root thread */
3605 && stack_used
3606 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3607 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003608 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003609 "thread %d: stack used %d, available %d",
3610 i, stack_used, VG_PTHREAD_STACK_MIN );
3611 VG_(message)(Vg_UserMsg,
3612 "Terminating Valgrind. If thread(s) "
3613 "really need more stack, increase");
3614 VG_(message)(Vg_UserMsg,
3615 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3616 VG_(exit)(1);
3617 }
sewardjb48e5002002-05-13 00:16:03 +00003618
sewardj018f7622002-05-15 21:13:39 +00003619 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003620 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003621 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003622 } else {
3623 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003624 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003625 }
3626
sewardjbf290b92002-05-01 02:28:01 +00003627 }
sewardj6072c362002-04-19 14:40:57 +00003628 }
sewardj5f07b662002-04-23 16:52:51 +00003629
3630 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3631 if (!vg_thread_keys[i].inuse)
3632 vg_assert(vg_thread_keys[i].destructor == NULL);
3633 }
sewardj6072c362002-04-19 14:40:57 +00003634}
3635
3636
sewardje663cb92002-04-12 10:26:32 +00003637/*--------------------------------------------------------------------*/
3638/*--- end vg_scheduler.c ---*/
3639/*--------------------------------------------------------------------*/