blob: 04c4933cac95150d738a42ea652bfd9c063a2980 [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
njn0e1b5142003-04-15 14:58:06 +000010 Copyright (C) 2000-2003 Julian Seward
sewardje663cb92002-04-12 10:26:32 +000011 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
njn47363ab2003-04-21 13:24:40 +000037 VG_USERREQ__DISCARD_TRANSLATIONS, and others */
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). */
njn1be61612003-05-14 14:04:39 +0000100static ThreadId vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardj1e8cdc92002-04-18 11:37:52 +0000101
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 */
njn1be61612003-05-14 14:04:39 +0000105static ThreadId 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;
sewardjb91ae7f2003-04-29 23:50:00 +0000422 VG_(baseBlock)[VGOFF_(m_eflags)]
423 = VG_(threads)[tid].m_eflags & ~EFlagD;
424 VG_(baseBlock)[VGOFF_(m_dflag)]
425 = VG_(extractDflag)(VG_(threads)[tid].m_eflags);
sewardj018f7622002-05-15 21:13:39 +0000426 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000427
sewardjb91ae7f2003-04-29 23:50:00 +0000428 for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
429 VG_(baseBlock)[VGOFF_(m_ssestate) + i]
430 = VG_(threads)[tid].m_sse[i];
sewardje663cb92002-04-12 10:26:32 +0000431
njn25e49d8e72002-09-23 09:36:25 +0000432 if (VG_(needs).shadow_regs) {
433 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
434 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
435 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
436 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
437 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
438 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
439 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
440 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
441 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
442 } else {
443 /* Fields shouldn't be used -- check their values haven't changed. */
444 /* Nb: they are written to by some macros like SET_EDX, but they
445 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
446 vg_assert(
447 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
448 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
449 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
450 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
451 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
452 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
453 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
454 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
455 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
456 }
sewardj1e8cdc92002-04-18 11:37:52 +0000457
458 vg_tid_currently_in_baseBlock = tid;
sewardjb52a1b02002-10-23 21:38:22 +0000459 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000460}
461
462
463/* Copy the state of a thread from VG_(baseBlock), presumably after it
464 has been descheduled. For sanity-check purposes, fill the vacated
465 VG_(baseBlock) with garbage so as to make the system more likely to
466 fail quickly if we erroneously continue to poke around inside
467 VG_(baseBlock) without first doing a load_thread_state().
468*/
469__inline__
470void VG_(save_thread_state) ( ThreadId tid )
471{
472 Int i;
473 const UInt junk = 0xDEADBEEF;
474
sewardj1e8cdc92002-04-18 11:37:52 +0000475 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
476
sewardj92a59562002-09-30 00:53:10 +0000477
478 /* We don't copy out the LDT entry, because it can never be changed
479 by the normal actions of the thread, only by the modify_ldt
480 syscall, in which case we will correctly be updating
sewardjfb5e5272002-12-08 23:27:21 +0000481 VG_(threads)[tid].ldt. This printf happens iff the following
482 assertion fails. */
sewardjca340b32002-12-08 22:14:11 +0000483 if ((void*)VG_(threads)[tid].ldt != (void*)VG_(baseBlock)[VGOFF_(ldt)])
484 VG_(printf)("VG_(threads)[%d].ldt=%p VG_(baseBlock)[VGOFF_(ldt)]=%p\n",
sewardjfb5e5272002-12-08 23:27:21 +0000485 tid, (void*)VG_(threads)[tid].ldt,
486 (void*)VG_(baseBlock)[VGOFF_(ldt)]);
sewardjca340b32002-12-08 22:14:11 +0000487
sewardj92a59562002-09-30 00:53:10 +0000488 vg_assert((void*)VG_(threads)[tid].ldt
489 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
490
491 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
492 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
493 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
494 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
495 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
496 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
497
sewardj018f7622002-05-15 21:13:39 +0000498 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
499 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
500 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
501 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
502 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
503 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
504 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
505 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardjb91ae7f2003-04-29 23:50:00 +0000506 VG_(threads)[tid].m_eflags
507 = VG_(insertDflag)(VG_(baseBlock)[VGOFF_(m_eflags)],
508 VG_(baseBlock)[VGOFF_(m_dflag)]);
sewardj018f7622002-05-15 21:13:39 +0000509 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000510
sewardjb91ae7f2003-04-29 23:50:00 +0000511 for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
512 VG_(threads)[tid].m_sse[i]
513 = VG_(baseBlock)[VGOFF_(m_ssestate) + i];
sewardje663cb92002-04-12 10:26:32 +0000514
njn25e49d8e72002-09-23 09:36:25 +0000515 if (VG_(needs).shadow_regs) {
516 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
517 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
518 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
519 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
520 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
521 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
522 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
523 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
524 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
525 } else {
526 /* Fill with recognisable junk */
527 VG_(threads)[tid].sh_eax =
528 VG_(threads)[tid].sh_ebx =
529 VG_(threads)[tid].sh_ecx =
530 VG_(threads)[tid].sh_edx =
531 VG_(threads)[tid].sh_esi =
532 VG_(threads)[tid].sh_edi =
533 VG_(threads)[tid].sh_ebp =
534 VG_(threads)[tid].sh_esp =
535 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
536 }
sewardje663cb92002-04-12 10:26:32 +0000537
538 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000539 VG_(baseBlock)[VGOFF_(ldt)] = junk;
540 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
541 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
542 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
543 VG_(baseBlock)[VGOFF_(m_es)] = junk;
544 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
545 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
546
sewardje663cb92002-04-12 10:26:32 +0000547 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
548 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
549 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
550 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
551 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
552 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
553 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
554 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
555 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
556 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
557
sewardjb91ae7f2003-04-29 23:50:00 +0000558 for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
559 VG_(baseBlock)[VGOFF_(m_ssestate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000560
561 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000562}
563
564
565/* Run the thread tid for a while, and return a VG_TRC_* value to the
566 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000567static
sewardje663cb92002-04-12 10:26:32 +0000568UInt run_thread_for_a_while ( ThreadId tid )
569{
sewardj7ccc5c22002-04-24 21:39:11 +0000570 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000571 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000572 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000573 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000574 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000575
sewardj671ff542002-05-07 09:25:30 +0000576 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000577 VG_(load_thread_state) ( tid );
578 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
579 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000580 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000581 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000582 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000583 /* We get here if the client didn't take a fault. */
584 } else {
585 /* We get here if the client took a fault, which caused our
586 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000587 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000588 vg_assert(trc == 0);
589 trc = VG_TRC_UNRESUMABLE_SIGNAL;
590 }
sewardj872051c2002-07-13 12:12:56 +0000591
592 vg_assert(!VG_(scheduler_jmpbuf_valid));
593
sewardje663cb92002-04-12 10:26:32 +0000594 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000595 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000596 return trc;
597}
598
599
sewardj20917d82002-05-28 01:36:45 +0000600static
601void mostly_clear_thread_record ( ThreadId tid )
602{
sewardj20917d82002-05-28 01:36:45 +0000603 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000604 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000605 VG_(threads)[tid].tid = tid;
606 VG_(threads)[tid].status = VgTs_Empty;
607 VG_(threads)[tid].associated_mx = NULL;
608 VG_(threads)[tid].associated_cv = NULL;
609 VG_(threads)[tid].awaken_at = 0;
610 VG_(threads)[tid].joinee_retval = NULL;
611 VG_(threads)[tid].joiner_thread_return = NULL;
612 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000613 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000614 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
615 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
616 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000617 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000618 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000619 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
620 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardj00a66b12002-10-12 16:42:35 +0000621 VG_(threads)[tid].specifics_ptr = NULL;
sewardj20917d82002-05-28 01:36:45 +0000622}
623
624
sewardje663cb92002-04-12 10:26:32 +0000625/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000626 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000627 caller takes care to park the client's state is parked in
628 VG_(baseBlock).
629*/
630void VG_(scheduler_init) ( void )
631{
632 Int i;
sewardje663cb92002-04-12 10:26:32 +0000633 ThreadId tid_main;
634
sewardj6072c362002-04-19 14:40:57 +0000635 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000636 mostly_clear_thread_record(i);
637 VG_(threads)[i].stack_size = 0;
638 VG_(threads)[i].stack_base = (Addr)NULL;
639 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000640 }
641
642 for (i = 0; i < VG_N_WAITING_FDS; i++)
643 vg_waiting_fds[i].fd = -1; /* not in use */
644
sewardj5f07b662002-04-23 16:52:51 +0000645 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
646 vg_thread_keys[i].inuse = False;
647 vg_thread_keys[i].destructor = NULL;
648 }
649
sewardj2cb00342002-06-28 01:46:26 +0000650 vg_fhstack_used = 0;
651
sewardje663cb92002-04-12 10:26:32 +0000652 /* Assert this is thread zero, which has certain magic
653 properties. */
654 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000655 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000656 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000657
658 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000659 vg_tid_currently_in_baseBlock = tid_main;
sewardjb52a1b02002-10-23 21:38:22 +0000660 vg_tid_last_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000661 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000662
sewardj018f7622002-05-15 21:13:39 +0000663 VG_(threads)[tid_main].stack_highest_word
sewardj49e630d2003-04-23 21:18:52 +0000664 = VG_(foundstack_start) + VG_(foundstack_size) - 4;
665 VG_(threads)[tid_main].stack_base = VG_(foundstack_start);
666 VG_(threads)[tid_main].stack_size = VG_(foundstack_size);
sewardjbf290b92002-05-01 02:28:01 +0000667
sewardj1e8cdc92002-04-18 11:37:52 +0000668 /* So now ... */
669 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000670
671 /* Not running client code right now. */
672 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000673}
674
675
676/* What if fd isn't a valid fd? */
677static
678void set_fd_nonblocking ( Int fd )
679{
680 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
681 vg_assert(!VG_(is_kerror)(res));
682 res |= VKI_O_NONBLOCK;
683 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
684 vg_assert(!VG_(is_kerror)(res));
685}
686
687static
688void set_fd_blocking ( Int fd )
689{
690 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
691 vg_assert(!VG_(is_kerror)(res));
692 res &= ~VKI_O_NONBLOCK;
693 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
694 vg_assert(!VG_(is_kerror)(res));
695}
696
697static
698Bool fd_is_blockful ( Int fd )
699{
700 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
701 vg_assert(!VG_(is_kerror)(res));
702 return (res & VKI_O_NONBLOCK) ? False : True;
703}
704
sewardj3947e622002-05-23 16:52:11 +0000705static
706Bool fd_is_valid ( Int fd )
707{
708 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
709 return VG_(is_kerror)(res) ? False : True;
710}
711
sewardje663cb92002-04-12 10:26:32 +0000712
713
sewardj6072c362002-04-19 14:40:57 +0000714/* vthread tid is returning from a signal handler; modify its
715 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000716
717/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
718 for read or write, has been interrupted by a signal. Find and
719 clear the relevant vg_waiting_fd[] entry. Most of the code in this
720 procedure is total paranoia, if you look closely. */
sewardj420b9282003-04-03 22:28:00 +0000721
722/* 4 Apr 2003: monty@mysql.com sent a fix, which adds the comparisons
723 against -1, and the following explaination.
724
725 Valgrind uses fd = -1 internally to tell that a file descriptor is
726 not in use, as the following code shows (at end of
727 cleanup_waiting_fd_table()).
728
729 vg_assert(waiters == 1);
730 for (i = 0; i < VG_N_WAITING_FDS; i++)
731 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1)
732 break;
733 vg_assert(i < VG_N_WAITING_FDS);
734 vg_assert(vg_waiting_fds[i].fd != -1);
735 vg_waiting_fds[i].fd = -1; -- not in use
736 ^^^^^^^
737
738 The bug is that valrind is setting fd = -1 for a not used file
739 descriptor but vg_waiting_fds[i].tid is not reset.
740
741 What happens is that on a later call to cleanup_waiting_fd_table()
742 the function will find old files that was waited on before by the
743 same thread, even if they are marked as 'not in use' by the above
744 code.
745
746 I first tried to fix the bug by setting vg_waiting_fds[i].tid to 0
747 at the end of the above function but this didn't fix the bug.
748 (Maybe there is other places in the code where tid is not properly
749 reset). After adding the test for 'fd == -1' to the loops in
750 cleanup_waiting_fd_table() all problems disappeared.
751*/
752
sewardj1ffa8da2002-04-26 22:47:57 +0000753static
754void cleanup_waiting_fd_table ( ThreadId tid )
755{
756 Int i, waiters;
757
sewardjb48e5002002-05-13 00:16:03 +0000758 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000759 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
760 vg_assert(VG_(threads)[tid].m_eax == __NR_read
761 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000762
763 /* Excessively paranoidly ... find the fd this op was waiting
764 for, and mark it as not being waited on. */
765 waiters = 0;
766 for (i = 0; i < VG_N_WAITING_FDS; i++) {
sewardj420b9282003-04-03 22:28:00 +0000767 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1) {
sewardj1ffa8da2002-04-26 22:47:57 +0000768 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000769 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000770 }
771 }
772 vg_assert(waiters == 1);
773 for (i = 0; i < VG_N_WAITING_FDS; i++)
sewardj420b9282003-04-03 22:28:00 +0000774 if (vg_waiting_fds[i].tid == tid && vg_waiting_fds[i].fd != -1)
sewardj1ffa8da2002-04-26 22:47:57 +0000775 break;
776 vg_assert(i < VG_N_WAITING_FDS);
777 vg_assert(vg_waiting_fds[i].fd != -1);
778 vg_waiting_fds[i].fd = -1; /* not in use */
779}
780
781
sewardj6072c362002-04-19 14:40:57 +0000782static
783void handle_signal_return ( ThreadId tid )
784{
785 Char msg_buf[100];
786 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000787 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000788
sewardjb48e5002002-05-13 00:16:03 +0000789 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000790
sewardj9a2224b2002-06-19 10:17:40 +0000791 /* Increment signal-returned counter. Used only to implement
792 pause(). */
793 VG_(threads)[tid].n_signals_returned++;
794
sewardj6072c362002-04-19 14:40:57 +0000795 restart_blocked_syscalls = VG_(signal_returns)(tid);
796
797 if (restart_blocked_syscalls)
798 /* Easy; we don't have to do anything. */
799 return;
800
sewardj018f7622002-05-15 21:13:39 +0000801 if (VG_(threads)[tid].status == VgTs_WaitFD
802 && (VG_(threads)[tid].m_eax == __NR_read
803 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000804 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000805 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000806 VG_(threads)[tid].m_eax = -VKI_EINTR;
807 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000808
sewardj6072c362002-04-19 14:40:57 +0000809 if (VG_(clo_trace_sched)) {
810 VG_(sprintf)(msg_buf,
811 "read() / write() interrupted by signal; return EINTR" );
812 print_sched_event(tid, msg_buf);
813 }
814 return;
815 }
816
sewardj645030e2002-06-06 01:27:39 +0000817 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000818 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000819 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000820 write the unused time to nanosleep's second param, but that's
821 too much effort ... we just say that 1 nanosecond was not
822 used, and return EINTR. */
823 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
824 if (rem != NULL) {
825 rem->tv_sec = 0;
826 rem->tv_nsec = 1;
827 }
828 SET_EAX(tid, -VKI_EINTR);
829 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000830 return;
831 }
832
sewardj018f7622002-05-15 21:13:39 +0000833 if (VG_(threads)[tid].status == VgTs_WaitFD) {
njne427a662002-10-02 11:08:25 +0000834 VG_(core_panic)("handle_signal_return: unknown interrupted syscall");
sewardj1ffa8da2002-04-26 22:47:57 +0000835 }
836
sewardj6072c362002-04-19 14:40:57 +0000837 /* All other cases? Just return. */
838}
839
840
sewardje663cb92002-04-12 10:26:32 +0000841static
842void sched_do_syscall ( ThreadId tid )
843{
njn25e49d8e72002-09-23 09:36:25 +0000844 UInt saved_eax;
njn1be61612003-05-14 14:04:39 +0000845 Int res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +0000846 UInt fd;
847 void* pre_res;
848 Bool orig_fd_blockness;
849 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000850
sewardjb48e5002002-05-13 00:16:03 +0000851 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000852 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000853
sewardj018f7622002-05-15 21:13:39 +0000854 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000855
856 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000857 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000858 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000859 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000860 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000861 t_awaken
862 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000863 + (UInt)1000ULL * (UInt)(req->tv_sec)
864 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000865 VG_(threads)[tid].status = VgTs_Sleeping;
866 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000867 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000868 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000869 t_now, t_awaken-t_now);
870 print_sched_event(tid, msg_buf);
871 }
872 /* Force the scheduler to run something else for a while. */
873 return;
874 }
875
sewardjaec22c02002-04-29 01:58:08 +0000876 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000877 /* We think it's non-blocking. Just do it in the normal way. */
878 VG_(perform_assumed_nonblocking_syscall)(tid);
879 /* The thread is still runnable. */
880 return;
881 }
882
sewardje663cb92002-04-12 10:26:32 +0000883 /* Set the fd to nonblocking, and do the syscall, which will return
884 immediately, in order to lodge a request with the Linux kernel.
885 We later poll for I/O completion using select(). */
886
sewardj018f7622002-05-15 21:13:39 +0000887 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000888
889 /* Deal with error case immediately. */
890 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000891 if (VG_(needs).core_errors)
892 VG_(message)(Vg_UserMsg,
893 "Warning: invalid file descriptor %d in syscall %s",
894 fd, syscall_no == __NR_read ? "read()" : "write()" );
895 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000896 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000897 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000898 /* We're still runnable. */
899 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
900 return;
901 }
902
903 /* From here onwards we know that fd is valid. */
904
sewardje663cb92002-04-12 10:26:32 +0000905 orig_fd_blockness = fd_is_blockful(fd);
906 set_fd_nonblocking(fd);
907 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000908 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000909
910 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000911 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000912 KERNEL_DO_SYSCALL(tid,res);
913
914 /* Restore original blockfulness of the fd. */
915 if (orig_fd_blockness)
916 set_fd_blocking(fd);
917 else
918 set_fd_nonblocking(fd);
919
sewardjaec22c02002-04-29 01:58:08 +0000920 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
921 /* Finish off in the normal way. Don't restore %EAX, since that
922 now (correctly) holds the result of the call. We get here if either:
923 1. The call didn't block, or
924 2. The fd was already in nonblocking mode before we started to
925 mess with it. In this case, we're not expecting to handle
926 the I/O completion -- the client is. So don't file a
927 completion-wait entry.
928 */
njn25e49d8e72002-09-23 09:36:25 +0000929 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000930 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000931 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000932
933 } else {
934
sewardjaec22c02002-04-29 01:58:08 +0000935 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
936
sewardje663cb92002-04-12 10:26:32 +0000937 /* It would have blocked. First, restore %EAX to what it was
938 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000939 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000940 /* Put this fd in a table of fds on which we are waiting for
941 completion. The arguments for select() later are constructed
942 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000943 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
944 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000945 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000946 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000947 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000948 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
949 print_sched_event(tid, msg_buf);
950 }
951
952 }
953}
954
955
956/* Find out which of the fds in vg_waiting_fds are now ready to go, by
957 making enquiries with select(), and mark them as ready. We have to
958 wait for the requesting threads to fall into the the WaitFD state
959 before we can actually finally deliver the results, so this
960 procedure doesn't do that; complete_blocked_syscalls() does it.
961
962 It might seem odd that a thread which has done a blocking syscall
963 is not in WaitFD state; the way this can happen is if it initially
964 becomes WaitFD, but then a signal is delivered to it, so it becomes
965 Runnable for a while. In this case we have to wait for the
966 sighandler to return, whereupon the WaitFD state is resumed, and
967 only at that point can the I/O result be delivered to it. However,
968 this point may be long after the fd is actually ready.
969
970 So, poll_for_ready_fds() merely detects fds which are ready.
971 complete_blocked_syscalls() does the second half of the trick,
972 possibly much later: it delivers the results from ready fds to
973 threads in WaitFD state.
974*/
sewardj9a199dc2002-04-14 13:01:38 +0000975static
sewardje663cb92002-04-12 10:26:32 +0000976void poll_for_ready_fds ( void )
977{
978 vki_ksigset_t saved_procmask;
979 vki_fd_set readfds;
980 vki_fd_set writefds;
981 vki_fd_set exceptfds;
982 struct vki_timeval timeout;
983 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
984 ThreadId tid;
985 Bool rd_ok, wr_ok, ex_ok;
986 Char msg_buf[100];
987
sewardje462e202002-04-13 04:09:07 +0000988 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000989 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000990
sewardje663cb92002-04-12 10:26:32 +0000991 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000992 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000993 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000994 break;
sewardj6072c362002-04-19 14:40:57 +0000995
sewardj5f07b662002-04-23 16:52:51 +0000996 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000997 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000998 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000999 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00001000 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +00001001 continue;
sewardj018f7622002-05-15 21:13:39 +00001002 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +00001003 /* Resume this thread. Set to zero the remaining-time
1004 (second) arg of nanosleep, since it's used up all its
1005 time. */
sewardj018f7622002-05-15 21:13:39 +00001006 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
1007 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +00001008 if (rem != NULL) {
1009 rem->tv_sec = 0;
1010 rem->tv_nsec = 0;
1011 }
1012 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +00001013 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +00001014 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +00001015 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +00001016 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +00001017 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +00001018 t_now);
1019 print_sched_event(tid, msg_buf);
1020 }
sewardje663cb92002-04-12 10:26:32 +00001021 }
1022 }
1023 }
sewardje663cb92002-04-12 10:26:32 +00001024
sewardje462e202002-04-13 04:09:07 +00001025 /* And look for threads waiting on file descriptors which are now
1026 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +00001027 timeout.tv_sec = 0;
1028 timeout.tv_usec = 0;
1029
1030 VKI_FD_ZERO(&readfds);
1031 VKI_FD_ZERO(&writefds);
1032 VKI_FD_ZERO(&exceptfds);
1033 fd_max = -1;
1034 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1035 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1036 continue;
1037 if (vg_waiting_fds[i].ready /* already ready? */)
1038 continue;
1039 fd = vg_waiting_fds[i].fd;
1040 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001041 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001042 if (fd > fd_max)
1043 fd_max = fd;
1044 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001045 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001046 syscall_no = vg_waiting_fds[i].syscall_no;
1047 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001048 case __NR_read:
1049 /* In order to catch timeout events on fds which are
1050 readable and which have been ioctl(TCSETA)'d with a
1051 VTIMEout, we appear to need to ask if the fd is
1052 writable, for some reason. Ask me not why. Since this
1053 is strange and potentially troublesome we only do it if
1054 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001055 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001056 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001057 VKI_FD_SET(fd, &readfds); break;
1058 case __NR_write:
1059 VKI_FD_SET(fd, &writefds); break;
1060 default:
njne427a662002-10-02 11:08:25 +00001061 VG_(core_panic)("poll_for_ready_fds: unexpected syscall");
sewardje663cb92002-04-12 10:26:32 +00001062 /*NOTREACHED*/
1063 break;
1064 }
1065 }
1066
sewardje462e202002-04-13 04:09:07 +00001067 /* Short cut: if no fds are waiting, give up now. */
1068 if (fd_max == -1)
1069 return;
1070
sewardje663cb92002-04-12 10:26:32 +00001071 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1072 getting interrupted. */
1073 VG_(block_all_host_signals)( &saved_procmask );
1074
1075 n_ready = VG_(select)
1076 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1077 if (VG_(is_kerror)(n_ready)) {
1078 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
njne427a662002-10-02 11:08:25 +00001079 VG_(core_panic)("poll_for_ready_fds: select failed?!");
sewardje663cb92002-04-12 10:26:32 +00001080 /*NOTREACHED*/
1081 }
1082
1083 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001084 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001085
1086 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1087
1088 if (n_ready == 0)
1089 return;
1090
1091 /* Inspect all the fds we know about, and handle any completions that
1092 have happened. */
1093 /*
1094 VG_(printf)("\n\n");
1095 for (fd = 0; fd < 100; fd++)
1096 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1097 VG_(printf)("X"); } else { VG_(printf)("."); };
1098 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1099 */
1100
1101 for (fd = 0; fd <= fd_max; fd++) {
1102 rd_ok = VKI_FD_ISSET(fd, &readfds);
1103 wr_ok = VKI_FD_ISSET(fd, &writefds);
1104 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1105
1106 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1107 if (n_ok == 0)
1108 continue;
1109 if (n_ok > 1) {
1110 VG_(printf)("offending fd = %d\n", fd);
njne427a662002-10-02 11:08:25 +00001111 VG_(core_panic)("poll_for_ready_fds: multiple events on fd");
sewardje663cb92002-04-12 10:26:32 +00001112 }
sewardjbc7d8782002-06-30 12:44:54 +00001113
sewardje663cb92002-04-12 10:26:32 +00001114 /* An I/O event completed for fd. Find the thread which
1115 requested this. */
1116 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1117 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1118 continue;
1119 if (vg_waiting_fds[i].fd == fd)
1120 break;
1121 }
1122
1123 /* And a bit more paranoia ... */
1124 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1125
1126 /* Mark the fd as ready. */
1127 vg_assert(! vg_waiting_fds[i].ready);
1128 vg_waiting_fds[i].ready = True;
1129 }
1130}
1131
1132
1133/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001134static
sewardje663cb92002-04-12 10:26:32 +00001135void complete_blocked_syscalls ( void )
1136{
1137 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001138 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001139 ThreadId tid;
1140 Char msg_buf[100];
1141
1142 /* Inspect all the outstanding fds we know about. */
1143
1144 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1145 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1146 continue;
1147 if (! vg_waiting_fds[i].ready)
1148 continue;
1149
1150 fd = vg_waiting_fds[i].fd;
1151 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001152 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001153
1154 /* The thread actually has to be waiting for the I/O event it
1155 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001156 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001157 continue;
1158
1159 /* Ok, actually do it! We can safely use %EAX as the syscall
1160 number, because the speculative call made by
1161 sched_do_syscall() doesn't change %EAX in the case where the
1162 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001163 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001164 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001165
njn25e49d8e72002-09-23 09:36:25 +00001166 pre_res = vg_waiting_fds[i].pre_result;
1167
sewardjbc7d8782002-06-30 12:44:54 +00001168 /* In a rare case pertaining to writing into a pipe, write()
1169 will block when asked to write > 4096 bytes even though the
1170 kernel claims, when asked via select(), that blocking will
1171 not occur for a write on that fd. This can cause deadlocks.
1172 An easy answer is to limit the size of the write to 4096
1173 anyway and hope that the client program's logic can handle
1174 the short write. That shoulds dubious to me, so we don't do
1175 it by default. */
1176 if (syscall_no == __NR_write
1177 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1178 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1179 /* VG_(printf)("truncate write from %d to 4096\n",
1180 VG_(threads)[tid].m_edx ); */
1181 VG_(threads)[tid].m_edx = 4096;
1182 }
1183
sewardje663cb92002-04-12 10:26:32 +00001184 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001185 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001186
1187 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001188 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001189 /* Mark slot as no longer in use. */
1190 vg_waiting_fds[i].fd = -1;
1191 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001192 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001193 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1194 print_sched_event(tid, msg_buf);
1195 }
1196 }
1197}
1198
1199
1200static
sewardj5f07b662002-04-23 16:52:51 +00001201void check_for_pthread_cond_timedwait ( void )
1202{
sewardj51c0aaf2002-04-25 01:32:10 +00001203 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001204 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001205 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001206 continue;
sewardj018f7622002-05-15 21:13:39 +00001207 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001208 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001209 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001210 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001211 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001212 }
sewardj5f07b662002-04-23 16:52:51 +00001213 }
1214}
1215
1216
1217static
sewardje663cb92002-04-12 10:26:32 +00001218void nanosleep_for_a_while ( void )
1219{
1220 Int res;
1221 struct vki_timespec req;
1222 struct vki_timespec rem;
1223 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001224 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001225 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001226 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001227}
1228
1229
1230/* ---------------------------------------------------------------------
1231 The scheduler proper.
1232 ------------------------------------------------------------------ */
1233
1234/* Run user-space threads until either
1235 * Deadlock occurs
1236 * One thread asks to shutdown Valgrind
1237 * The specified number of basic blocks has gone by.
1238*/
1239VgSchedReturnCode VG_(scheduler) ( void )
1240{
1241 ThreadId tid, tid_next;
1242 UInt trc;
1243 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001244 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001245 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001246 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001247
sewardje663cb92002-04-12 10:26:32 +00001248 /* Start with the root thread. tid in general indicates the
1249 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001250 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001251
1252 /* This is the top level scheduler loop. It falls into three
1253 phases. */
1254 while (True) {
1255
sewardj6072c362002-04-19 14:40:57 +00001256 /* ======================= Phase 0 of 3 =======================
1257 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001258 stage1:
sewardj6072c362002-04-19 14:40:57 +00001259 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001260 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001261
sewardje663cb92002-04-12 10:26:32 +00001262 /* ======================= Phase 1 of 3 =======================
1263 Handle I/O completions and signals. This may change the
1264 status of various threads. Then select a new thread to run,
1265 or declare deadlock, or sleep if there are no runnable
1266 threads but some are blocked on I/O. */
1267
sewardje663cb92002-04-12 10:26:32 +00001268 /* Was a debug-stop requested? */
1269 if (VG_(bbs_to_go) == 0)
1270 goto debug_stop;
1271
1272 /* Do the following loop until a runnable thread is found, or
1273 deadlock is detected. */
1274 while (True) {
1275
1276 /* For stats purposes only. */
1277 VG_(num_scheduling_events_MAJOR) ++;
1278
1279 /* See if any I/O operations which we were waiting for have
1280 completed, and, if so, make runnable the relevant waiting
1281 threads. */
1282 poll_for_ready_fds();
1283 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001284 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001285
1286 /* See if there are any signals which need to be delivered. If
1287 so, choose thread(s) to deliver them to, and build signal
1288 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001289
1290 /* Be careful about delivering signals to a thread waiting
1291 for a mutex. In particular, when the handler is running,
1292 that thread is temporarily apparently-not-waiting for the
1293 mutex, so if it is unlocked by another thread whilst the
1294 handler is running, this thread is not informed. When the
1295 handler returns, the thread resumes waiting on the mutex,
1296 even if, as a result, it has missed the unlocking of it.
1297 Potential deadlock. This sounds all very strange, but the
1298 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001299 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001300 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001301 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001302
1303 /* Try and find a thread (tid) to run. */
1304 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001305 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001306 while (True) {
1307 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001308 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001309 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1310 || VG_(threads)[tid_next].status == VgTs_Sleeping
1311 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1312 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1313 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001314 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001315 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001316 break; /* We can run this one. */
1317 if (tid_next == tid)
1318 break; /* been all the way round */
1319 }
1320 tid = tid_next;
1321
sewardj018f7622002-05-15 21:13:39 +00001322 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001323 /* Found a suitable candidate. Fall out of this loop, so
1324 we can advance to stage 2 of the scheduler: actually
1325 running the thread. */
1326 break;
1327 }
1328
1329 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001330 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001331 /* No runnable threads and no prospect of any appearing
1332 even if we wait for an arbitrary length of time. In
1333 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001334 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001335 return VgSrc_Deadlock;
1336 }
1337
1338 /* At least one thread is in a fd-wait state. Delay for a
1339 while, and go round again, in the hope that eventually a
1340 thread becomes runnable. */
1341 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001342 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001343 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001344 }
1345
1346
1347 /* ======================= Phase 2 of 3 =======================
1348 Wahey! We've finally decided that thread tid is runnable, so
1349 we now do that. Run it for as much of a quanta as possible.
1350 Trivial requests are handled and the thread continues. The
1351 aim is not to do too many of Phase 1 since it is expensive. */
1352
1353 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001354 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001355
njn25e49d8e72002-09-23 09:36:25 +00001356 VG_TRACK( thread_run, tid );
1357
sewardje663cb92002-04-12 10:26:32 +00001358 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1359 that it decrements the counter before testing it for zero, so
1360 that if VG_(dispatch_ctr) is set to N you get at most N-1
1361 iterations. Also this means that VG_(dispatch_ctr) must
1362 exceed zero before entering the innerloop. Also also, the
1363 decrement is done before the bb is actually run, so you
1364 always get at least one decrement even if nothing happens.
1365 */
1366 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1367 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1368 else
1369 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1370
1371 /* ... and remember what we asked for. */
1372 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1373
sewardj1e8cdc92002-04-18 11:37:52 +00001374 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001375 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001376
sewardje663cb92002-04-12 10:26:32 +00001377 /* Actually run thread tid. */
1378 while (True) {
1379
sewardj7e87e382002-05-03 19:09:05 +00001380 VG_(last_run_tid) = tid;
1381
sewardje663cb92002-04-12 10:26:32 +00001382 /* For stats purposes only. */
1383 VG_(num_scheduling_events_MINOR) ++;
1384
1385 if (0)
1386 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1387 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001388# if 0
1389 if (VG_(bbs_done) > 31700000 + 0) {
1390 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001391 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001392 NULL,NULL,NULL);
1393 }
sewardj018f7622002-05-15 21:13:39 +00001394 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001395# endif
sewardje663cb92002-04-12 10:26:32 +00001396
1397 trc = run_thread_for_a_while ( tid );
1398
sewardjb3eef6b2002-05-01 00:05:27 +00001399# if 0
sewardj018f7622002-05-15 21:13:39 +00001400 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001401 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001402 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001403 }
1404# endif
1405
sewardje663cb92002-04-12 10:26:32 +00001406 /* Deal quickly with trivial scheduling events, and resume the
1407 thread. */
1408
1409 if (trc == VG_TRC_INNER_FASTMISS) {
1410 vg_assert(VG_(dispatch_ctr) > 0);
1411
1412 /* Trivial event. Miss in the fast-cache. Do a full
1413 lookup for it. */
1414 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001415 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001416 if (trans_addr == (Addr)0) {
1417 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001418 create_translation_for(
1419 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001420 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001421 if (trans_addr == (Addr)0)
njne427a662002-10-02 11:08:25 +00001422 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
sewardje663cb92002-04-12 10:26:32 +00001423 }
1424 continue; /* with this thread */
1425 }
1426
1427 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001428 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1429 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001430
1431 /* Are we really absolutely totally quitting? */
1432 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1433 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1434 VG_(message)(Vg_DebugMsg,
1435 "__libc_freeres() done; really quitting!");
1436 }
1437 return VgSrc_ExitSyscall;
1438 }
1439
sewardj124ca2a2002-06-20 10:19:38 +00001440 do_client_request(tid);
1441 /* Following the request, we try and continue with the
1442 same thread if still runnable. If not, go back to
1443 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001444 if (VG_(threads)[tid].status == VgTs_Runnable
1445 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001446 continue; /* with this thread */
1447 else
1448 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001449 }
1450
sewardj51c0aaf2002-04-25 01:32:10 +00001451 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1452 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001453 to become non-runnable. One special case: spot the
1454 client doing calls to exit() and take this as the cue
1455 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001456# if 0
1457 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001458 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001459 VG_(printf)("\nBEFORE\n");
1460 for (i = 10; i >= -10; i--)
1461 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1462 }
1463# endif
1464
sewardj1fe7b002002-07-16 01:43:15 +00001465 /* Deal with calling __libc_freeres() at exit. When the
1466 client does __NR_exit, it's exiting for good. So we
1467 then run VG_(__libc_freeres_wrapper). That quits by
1468 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1469 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001470 currently running.
1471
1472 If not valgrinding (cachegrinding, etc) don't do this.
1473 __libc_freeres does some invalid frees which crash
1474 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001475
sewardjf3fb92d2003-02-23 03:26:08 +00001476 if (VG_(threads)[tid].m_eax == __NR_exit
1477# if defined(__NR_exit_group)
1478 || VG_(threads)[tid].m_eax == __NR_exit_group
1479# endif
1480 ) {
sewardj858964b2002-10-05 14:15:43 +00001481
1482 /* If __NR_exit, remember the supplied argument. */
njn25e49d8e72002-09-23 09:36:25 +00001483 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1484
sewardj858964b2002-10-05 14:15:43 +00001485 /* Only run __libc_freeres if the skin says it's ok and
1486 it hasn't been overridden with --run-libc-freeres=no
1487 on the command line. */
1488
1489 if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
1490
sewardj00631892002-10-05 15:34:38 +00001491 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001492 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1493 VG_(message)(Vg_DebugMsg,
1494 "Caught __NR_exit; running __libc_freeres()");
1495 }
1496 VG_(nuke_all_threads_except) ( tid );
1497 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1498 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1499 goto stage1; /* party on, dudes (but not for much longer :) */
1500
1501 } else {
1502 /* We won't run __libc_freeres; just exit now. */
sewardj00631892002-10-05 15:34:38 +00001503 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001504 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1505 VG_(message)(Vg_DebugMsg,
1506 "Caught __NR_exit; quitting");
1507 }
1508 return VgSrc_ExitSyscall;
1509 }
1510
sewardjade9d0d2002-07-26 10:52:48 +00001511 }
1512
sewardj858964b2002-10-05 14:15:43 +00001513 /* We've dealt with __NR_exit at this point. */
sewardjf3fb92d2003-02-23 03:26:08 +00001514 { Bool b
1515 = VG_(threads)[tid].m_eax != __NR_exit
1516# if defined(__NR_exit_group)
1517 && VG_(threads)[tid].m_eax != __NR_exit_group
1518# endif
1519 ;
1520 vg_assert(b);
1521 }
sewardj7e87e382002-05-03 19:09:05 +00001522
sewardj83798bf2002-05-24 00:11:16 +00001523 /* Trap syscalls to __NR_sched_yield and just have this
1524 thread yield instead. Not essential, just an
1525 optimisation. */
1526 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1527 SET_EAX(tid, 0); /* syscall returns with success */
1528 goto stage1; /* find a new thread to run */
1529 }
1530
sewardj51c0aaf2002-04-25 01:32:10 +00001531 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001532
1533# if 0
1534 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001535 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001536 VG_(printf)("AFTER\n");
1537 for (i = 10; i >= -10; i--)
1538 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1539 }
1540# endif
1541
sewardj77f0fc12002-07-12 01:23:03 +00001542 if (VG_(threads)[tid].status == VgTs_Runnable) {
1543 /* Better do a signal check, since if in a tight loop
1544 with a slow syscall it may be a very long time
1545 before we get back to the main signal check in Stage 1. */
1546 sigs_delivered = VG_(deliver_signals)();
1547 if (sigs_delivered)
1548 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001549 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001550 } else {
1551 goto stage1;
1552 }
sewardj51c0aaf2002-04-25 01:32:10 +00001553 }
1554
sewardjd7fd4d22002-04-24 01:57:27 +00001555 /* It's an event we can't quickly deal with. Give up running
1556 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001557 break;
1558 }
1559
1560 /* ======================= Phase 3 of 3 =======================
1561 Handle non-trivial thread requests, mostly pthread stuff. */
1562
1563 /* Ok, we've fallen out of the dispatcher for a
1564 non-completely-trivial reason. First, update basic-block
1565 counters. */
1566
1567 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1568 vg_assert(done_this_time >= 0);
1569 VG_(bbs_to_go) -= (ULong)done_this_time;
1570 VG_(bbs_done) += (ULong)done_this_time;
1571
1572 if (0 && trc != VG_TRC_INNER_FASTMISS)
1573 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1574 tid, done_this_time, (Int)trc );
1575
1576 if (0 && trc != VG_TRC_INNER_FASTMISS)
njne0205ff2003-04-08 00:56:14 +00001577 VG_(message)(Vg_DebugMsg, "thread %d: %llu bbs, event %s",
sewardje663cb92002-04-12 10:26:32 +00001578 tid, VG_(bbs_done),
1579 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001580
sewardje663cb92002-04-12 10:26:32 +00001581 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001582 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001583
1584 switch (trc) {
1585
sewardje663cb92002-04-12 10:26:32 +00001586 case VG_TRC_INNER_COUNTERZERO:
1587 /* Timeslice is out. Let a new thread be scheduled,
1588 simply by doing nothing, causing us to arrive back at
1589 Phase 1. */
1590 if (VG_(bbs_to_go) == 0) {
1591 goto debug_stop;
1592 }
1593 vg_assert(VG_(dispatch_ctr) == 0);
1594 break;
1595
1596 case VG_TRC_UNRESUMABLE_SIGNAL:
1597 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1598 away. Again, do nothing, so we wind up back at Phase
1599 1, whereupon the signal will be "delivered". */
1600 break;
1601
sewardje663cb92002-04-12 10:26:32 +00001602 default:
1603 VG_(printf)("\ntrc = %d\n", trc);
njne427a662002-10-02 11:08:25 +00001604 VG_(core_panic)("VG_(scheduler), phase 3: "
1605 "unexpected thread return code");
sewardje663cb92002-04-12 10:26:32 +00001606 /* NOTREACHED */
1607 break;
1608
1609 } /* switch (trc) */
1610
1611 /* That completes Phase 3 of 3. Return now to the top of the
1612 main scheduler loop, to Phase 1 of 3. */
1613
1614 } /* top-level scheduler loop */
1615
1616
1617 /* NOTREACHED */
njne427a662002-10-02 11:08:25 +00001618 VG_(core_panic)("scheduler: post-main-loop ?!");
sewardje663cb92002-04-12 10:26:32 +00001619 /* NOTREACHED */
1620
1621 debug_stop:
1622 /* If we exited because of a debug stop, print the translation
1623 of the last block executed -- by translating it again, and
1624 throwing away the result. */
1625 VG_(printf)(
1626 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001627 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +00001628 VG_(threads)[tid].m_eip, NULL, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001629 VG_(printf)("\n");
1630 VG_(printf)(
1631 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1632
1633 return VgSrc_BbsDone;
1634}
1635
1636
1637/* ---------------------------------------------------------------------
1638 The pthread implementation.
1639 ------------------------------------------------------------------ */
1640
1641#include <pthread.h>
1642#include <errno.h>
1643
sewardjbf290b92002-05-01 02:28:01 +00001644#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001645 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001646
1647/* /usr/include/bits/pthreadtypes.h:
1648 typedef unsigned long int pthread_t;
1649*/
1650
sewardje663cb92002-04-12 10:26:32 +00001651
sewardj604ec3c2002-04-18 22:38:41 +00001652/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001653 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001654 -------------------------------------------------------- */
1655
sewardj20917d82002-05-28 01:36:45 +00001656/* We've decided to action a cancellation on tid. Make it jump to
1657 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1658 as the arg. */
1659static
1660void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1661{
1662 Char msg_buf[100];
1663 vg_assert(VG_(is_valid_tid)(tid));
sewardjdadc8d02002-12-08 23:24:18 +00001664
sewardj20917d82002-05-28 01:36:45 +00001665 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1666 handler -- which is really thread_exit_wrapper() in
1667 vg_libpthread.c. */
1668 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
sewardj4bdd9962002-12-26 11:51:50 +00001669
1670 /* Push a suitable arg, and mark it as readable. */
sewardj20917d82002-05-28 01:36:45 +00001671 VG_(threads)[tid].m_esp -= 4;
1672 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
sewardj4bdd9962002-12-26 11:51:50 +00001673 VG_TRACK( post_mem_write, VG_(threads)[tid].m_esp, sizeof(void*) );
1674
1675 /* Push a bogus return address. It will not return, but we still
1676 need to have it so that the arg is at the correct stack offset.
1677 Don't mark as readable; any attempt to read this is and internal
1678 valgrind bug since thread_exit_wrapper should not return. */
1679 VG_(threads)[tid].m_esp -= 4;
1680 * (UInt*)(VG_(threads)[tid].m_esp) = 0xBEADDEEF;
1681
1682 /* .cancel_pend will hold &thread_exit_wrapper */
sewardj20917d82002-05-28 01:36:45 +00001683 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
sewardjdadc8d02002-12-08 23:24:18 +00001684
1685 /* Clear out the waited-for-signals set, if needed, so as not to
1686 cause the sanity checker to bomb before
1687 cleanup_after_thread_exited() really cleans up properly for this
1688 thread. */
1689 if (VG_(threads)[tid].status == VgTs_WaitSIG) {
1690 VG_(ksigemptyset)( & VG_(threads)[tid].sigs_waited_for );
1691 }
1692
sewardj20917d82002-05-28 01:36:45 +00001693 VG_(threads)[tid].status = VgTs_Runnable;
sewardjdadc8d02002-12-08 23:24:18 +00001694
sewardj20917d82002-05-28 01:36:45 +00001695 /* Make sure we aren't cancelled again whilst handling this
1696 cancellation. */
1697 VG_(threads)[tid].cancel_st = False;
1698 if (VG_(clo_trace_sched)) {
1699 VG_(sprintf)(msg_buf,
1700 "jump to cancellation handler (hdlr = %p)",
1701 VG_(threads)[tid].cancel_pend);
1702 print_sched_event(tid, msg_buf);
1703 }
1704}
1705
1706
1707
sewardjb48e5002002-05-13 00:16:03 +00001708/* Release resources and generally clean up once a thread has finally
1709 disappeared. */
1710static
1711void cleanup_after_thread_exited ( ThreadId tid )
1712{
sewardj89f20fd2002-06-30 10:57:30 +00001713 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001714 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001715 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1716 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001717 /* Its stack is now off-limits */
1718 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1719 VG_(threads)[tid].stack_size );
1720
sewardjb48e5002002-05-13 00:16:03 +00001721 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001722 thread, and get rid of signal handlers specifically arranged for
1723 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001724 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001725 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001726
1727 /* Clean up the waiting_fd table */
1728 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1729 if (vg_waiting_fds[i].tid == tid) {
1730 vg_waiting_fds[i].fd = -1; /* not in use */
1731 }
1732 }
sewardj92a59562002-09-30 00:53:10 +00001733
1734 /* Deallocate its LDT, if it ever had one. */
1735 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1736 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001737}
1738
1739
sewardj20917d82002-05-28 01:36:45 +00001740/* Look for matching pairs of threads waiting for joiners and threads
1741 waiting for joinees. For each such pair copy the return value of
1742 the joinee into the joiner, let the joiner resume and discard the
1743 joinee. */
1744static
1745void maybe_rendezvous_joiners_and_joinees ( void )
1746{
1747 Char msg_buf[100];
1748 void** thread_return;
1749 ThreadId jnr, jee;
1750
1751 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1752 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1753 continue;
1754 jee = VG_(threads)[jnr].joiner_jee_tid;
1755 if (jee == VG_INVALID_THREADID)
1756 continue;
1757 vg_assert(VG_(is_valid_tid)(jee));
1758 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1759 continue;
1760 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1761 joined by ... well, any thread. So let's do it! */
1762
1763 /* Copy return value to where joiner wants it. */
1764 thread_return = VG_(threads)[jnr].joiner_thread_return;
1765 if (thread_return != NULL) {
1766 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001767 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1768 "pthread_join: thread_return",
1769 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001770
sewardj20917d82002-05-28 01:36:45 +00001771 *thread_return = VG_(threads)[jee].joinee_retval;
1772 /* Not really right, since it makes the thread's return value
1773 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001774 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001775 }
1776
1777 /* Joinee is discarded */
1778 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1779 cleanup_after_thread_exited ( jee );
sewardjc4a810d2002-11-13 22:25:51 +00001780 if (VG_(clo_trace_sched)) {
1781 VG_(sprintf)(msg_buf,
1782 "rendezvous with joinee %d. %d resumes, %d exits.",
1783 jee, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001784 print_sched_event(jnr, msg_buf);
1785 }
sewardjc4a810d2002-11-13 22:25:51 +00001786
1787 VG_TRACK( post_thread_join, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001788
1789 /* joiner returns with success */
1790 VG_(threads)[jnr].status = VgTs_Runnable;
1791 SET_EDX(jnr, 0);
1792 }
1793}
1794
1795
sewardjccef2e62002-05-29 19:26:32 +00001796/* Nuke all threads other than tid. POSIX specifies that this should
1797 happen in __NR_exec, and after a __NR_fork() when I am the child,
1798 as POSIX requires. */
1799void VG_(nuke_all_threads_except) ( ThreadId me )
1800{
1801 ThreadId tid;
1802 for (tid = 1; tid < VG_N_THREADS; tid++) {
1803 if (tid == me
1804 || VG_(threads)[tid].status == VgTs_Empty)
1805 continue;
sewardjef037c72002-05-30 00:40:03 +00001806 if (0)
1807 VG_(printf)(
1808 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001809 VG_(threads)[tid].status = VgTs_Empty;
1810 cleanup_after_thread_exited( tid );
1811 }
1812}
1813
1814
sewardj20917d82002-05-28 01:36:45 +00001815/* -----------------------------------------------------------
1816 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1817 -------------------------------------------------------- */
1818
sewardje663cb92002-04-12 10:26:32 +00001819static
sewardj8ad94e12002-05-29 00:10:20 +00001820void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1821{
1822 Int sp;
1823 Char msg_buf[100];
1824 vg_assert(VG_(is_valid_tid)(tid));
1825 sp = VG_(threads)[tid].custack_used;
1826 if (VG_(clo_trace_sched)) {
1827 VG_(sprintf)(msg_buf,
1828 "cleanup_push (fn %p, arg %p) -> slot %d",
1829 cu->fn, cu->arg, sp);
1830 print_sched_event(tid, msg_buf);
1831 }
1832 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1833 if (sp == VG_N_CLEANUPSTACK)
njne427a662002-10-02 11:08:25 +00001834 VG_(core_panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
sewardj8ad94e12002-05-29 00:10:20 +00001835 " Increase and recompile.");
1836 VG_(threads)[tid].custack[sp] = *cu;
1837 sp++;
1838 VG_(threads)[tid].custack_used = sp;
1839 SET_EDX(tid, 0);
1840}
1841
1842
1843static
1844void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1845{
1846 Int sp;
1847 Char msg_buf[100];
1848 vg_assert(VG_(is_valid_tid)(tid));
1849 sp = VG_(threads)[tid].custack_used;
1850 if (VG_(clo_trace_sched)) {
njn36650922002-10-04 09:18:09 +00001851 VG_(sprintf)(msg_buf, "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001852 print_sched_event(tid, msg_buf);
1853 }
1854 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1855 if (sp == 0) {
1856 SET_EDX(tid, -1);
1857 return;
1858 }
1859 sp--;
njn36650922002-10-04 09:18:09 +00001860 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
1861 "cleanup pop", (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001862 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001863 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001864 VG_(threads)[tid].custack_used = sp;
1865 SET_EDX(tid, 0);
1866}
1867
1868
1869static
sewardjff42d1d2002-05-22 13:17:31 +00001870void do_pthread_yield ( ThreadId tid )
1871{
1872 Char msg_buf[100];
1873 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001874 if (VG_(clo_trace_sched)) {
1875 VG_(sprintf)(msg_buf, "yield");
1876 print_sched_event(tid, msg_buf);
1877 }
1878 SET_EDX(tid, 0);
1879}
1880
1881
1882static
sewardj20917d82002-05-28 01:36:45 +00001883void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001884{
sewardj7989d0c2002-05-28 11:00:01 +00001885 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001886 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001887 if (VG_(clo_trace_sched)) {
1888 VG_(sprintf)(msg_buf, "testcancel");
1889 print_sched_event(tid, msg_buf);
1890 }
sewardj20917d82002-05-28 01:36:45 +00001891 if (/* is there a cancellation pending on this thread? */
1892 VG_(threads)[tid].cancel_pend != NULL
1893 && /* is this thread accepting cancellations? */
1894 VG_(threads)[tid].cancel_st) {
1895 /* Ok, let's do the cancellation. */
1896 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001897 } else {
sewardj20917d82002-05-28 01:36:45 +00001898 /* No, we keep going. */
1899 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001900 }
sewardje663cb92002-04-12 10:26:32 +00001901}
1902
1903
1904static
sewardj20917d82002-05-28 01:36:45 +00001905void do__set_cancelstate ( ThreadId tid, Int state )
1906{
1907 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001908 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001909 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001910 if (VG_(clo_trace_sched)) {
1911 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1912 state==PTHREAD_CANCEL_ENABLE
1913 ? "ENABLE"
1914 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1915 print_sched_event(tid, msg_buf);
1916 }
sewardj20917d82002-05-28 01:36:45 +00001917 old_st = VG_(threads)[tid].cancel_st;
1918 if (state == PTHREAD_CANCEL_ENABLE) {
1919 VG_(threads)[tid].cancel_st = True;
1920 } else
1921 if (state == PTHREAD_CANCEL_DISABLE) {
1922 VG_(threads)[tid].cancel_st = False;
1923 } else {
njne427a662002-10-02 11:08:25 +00001924 VG_(core_panic)("do__set_cancelstate");
sewardj20917d82002-05-28 01:36:45 +00001925 }
1926 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1927 : PTHREAD_CANCEL_DISABLE);
1928}
1929
1930
1931static
1932void do__set_canceltype ( ThreadId tid, Int type )
1933{
1934 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001935 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001936 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001937 if (VG_(clo_trace_sched)) {
1938 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1939 type==PTHREAD_CANCEL_ASYNCHRONOUS
1940 ? "ASYNCHRONOUS"
1941 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1942 print_sched_event(tid, msg_buf);
1943 }
sewardj20917d82002-05-28 01:36:45 +00001944 old_ty = VG_(threads)[tid].cancel_ty;
1945 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1946 VG_(threads)[tid].cancel_ty = False;
1947 } else
1948 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001949 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001950 } else {
njne427a662002-10-02 11:08:25 +00001951 VG_(core_panic)("do__set_canceltype");
sewardj20917d82002-05-28 01:36:45 +00001952 }
1953 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1954 : PTHREAD_CANCEL_ASYNCHRONOUS);
1955}
1956
1957
sewardj7989d0c2002-05-28 11:00:01 +00001958/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001959static
sewardj7989d0c2002-05-28 11:00:01 +00001960void do__set_or_get_detach ( ThreadId tid,
1961 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001962{
sewardj7989d0c2002-05-28 11:00:01 +00001963 ThreadId i;
1964 Char msg_buf[100];
1965 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1966 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001967 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001968 if (VG_(clo_trace_sched)) {
1969 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1970 what==0 ? "not-detached" : (
1971 what==1 ? "detached" : (
1972 what==2 ? "fetch old value" : "???")),
1973 det );
1974 print_sched_event(tid, msg_buf);
1975 }
1976
1977 if (!VG_(is_valid_tid)(det)) {
1978 SET_EDX(tid, -1);
1979 return;
1980 }
1981
sewardj20917d82002-05-28 01:36:45 +00001982 switch (what) {
1983 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001984 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001985 return;
sewardj7989d0c2002-05-28 11:00:01 +00001986 case 1: /* set detached. If someone is in a join-wait for det,
1987 do not detach. */
1988 for (i = 1; i < VG_N_THREADS; i++) {
1989 if (VG_(threads)[i].status == VgTs_WaitJoinee
1990 && VG_(threads)[i].joiner_jee_tid == det) {
1991 SET_EDX(tid, 0);
1992 if (VG_(clo_trace_sched)) {
1993 VG_(sprintf)(msg_buf,
njn9b6d34e2002-10-15 08:48:08 +00001994 "tid %d not detached because %d in join-wait for it",
sewardj7989d0c2002-05-28 11:00:01 +00001995 det, i);
1996 print_sched_event(tid, msg_buf);
1997 }
1998 return;
1999 }
2000 }
2001 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00002002 SET_EDX(tid, 0);
2003 return;
2004 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00002005 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00002006 SET_EDX(tid, 0);
2007 return;
2008 default:
njne427a662002-10-02 11:08:25 +00002009 VG_(core_panic)("do__set_or_get_detach");
sewardj20917d82002-05-28 01:36:45 +00002010 }
2011}
2012
2013
2014static
2015void do__set_cancelpend ( ThreadId tid,
2016 ThreadId cee,
2017 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00002018{
2019 Char msg_buf[100];
2020
sewardj20917d82002-05-28 01:36:45 +00002021 vg_assert(VG_(is_valid_tid)(tid));
2022 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2023
sewardj7989d0c2002-05-28 11:00:01 +00002024 if (!VG_(is_valid_tid)(cee)) {
2025 if (VG_(clo_trace_sched)) {
2026 VG_(sprintf)(msg_buf,
2027 "set_cancelpend for invalid tid %d", cee);
2028 print_sched_event(tid, msg_buf);
2029 }
njn25e49d8e72002-09-23 09:36:25 +00002030 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002031 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00002032 SET_EDX(tid, -VKI_ESRCH);
2033 return;
2034 }
sewardj20917d82002-05-28 01:36:45 +00002035
2036 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
2037
2038 if (VG_(clo_trace_sched)) {
2039 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002040 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00002041 cancelpend_hdlr, tid);
2042 print_sched_event(cee, msg_buf);
2043 }
2044
2045 /* Thread doing the cancelling returns with success. */
2046 SET_EDX(tid, 0);
2047
2048 /* Perhaps we can nuke the cancellee right now? */
2049 do__testcancel(cee);
2050}
2051
2052
2053static
2054void do_pthread_join ( ThreadId tid,
2055 ThreadId jee, void** thread_return )
2056{
2057 Char msg_buf[100];
2058 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00002059 /* jee, the joinee, is the thread specified as an arg in thread
2060 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00002061 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00002062 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002063
2064 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002065 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002066 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002067 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002068 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002069 return;
2070 }
2071
sewardj20917d82002-05-28 01:36:45 +00002072 /* Flush any completed pairs, so as to make sure what we're looking
2073 at is up-to-date. */
2074 maybe_rendezvous_joiners_and_joinees();
2075
2076 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002077 if (jee < 0
2078 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002079 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002080 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002081 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002082 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002083 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002084 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002085 return;
2086 }
2087
sewardj20917d82002-05-28 01:36:45 +00002088 /* Is anyone else already in a join-wait for jee? */
2089 for (i = 1; i < VG_N_THREADS; i++) {
2090 if (i == tid) continue;
2091 if (VG_(threads)[i].status == VgTs_WaitJoinee
2092 && VG_(threads)[i].joiner_jee_tid == jee) {
2093 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002094 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002095 "pthread_join: another thread already "
2096 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002097 SET_EDX(tid, EINVAL);
2098 VG_(threads)[tid].status = VgTs_Runnable;
2099 return;
2100 }
sewardje663cb92002-04-12 10:26:32 +00002101 }
2102
sewardj20917d82002-05-28 01:36:45 +00002103 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002104 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002105 VG_(threads)[tid].joiner_thread_return = thread_return;
2106 VG_(threads)[tid].joiner_jee_tid = jee;
2107
2108 /* Look for matching joiners and joinees and do the right thing. */
2109 maybe_rendezvous_joiners_and_joinees();
2110
2111 /* Return value is irrelevant since this this thread becomes
2112 non-runnable. maybe_resume_joiner() will cause it to return the
2113 right value when it resumes. */
2114
sewardj8937c812002-04-12 20:12:20 +00002115 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002116 VG_(sprintf)(msg_buf,
2117 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002118 print_sched_event(tid, msg_buf);
2119 }
sewardje663cb92002-04-12 10:26:32 +00002120}
2121
2122
sewardj20917d82002-05-28 01:36:45 +00002123/* ( void* ): calling thread waits for joiner and returns the void* to
2124 it. This is one of two ways in which a thread can finally exit --
2125 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002126static
sewardj20917d82002-05-28 01:36:45 +00002127void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002128{
sewardj20917d82002-05-28 01:36:45 +00002129 Char msg_buf[100];
2130 vg_assert(VG_(is_valid_tid)(tid));
2131 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2132 if (VG_(clo_trace_sched)) {
2133 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002134 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002135 print_sched_event(tid, msg_buf);
2136 }
2137 VG_(threads)[tid].status = VgTs_WaitJoiner;
2138 VG_(threads)[tid].joinee_retval = retval;
2139 maybe_rendezvous_joiners_and_joinees();
2140}
2141
2142
2143/* ( no-args ): calling thread disappears from the system forever.
2144 Reclaim resources. */
2145static
2146void do__quit ( ThreadId tid )
2147{
2148 Char msg_buf[100];
2149 vg_assert(VG_(is_valid_tid)(tid));
2150 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2151 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2152 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002153 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002154 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002155 print_sched_event(tid, msg_buf);
2156 }
2157 /* Return value is irrelevant; this thread will not get
2158 rescheduled. */
2159}
2160
2161
2162/* Should never be entered. If it is, will be on the simulated
2163 CPU. */
2164static
2165void do__apply_in_new_thread_bogusRA ( void )
2166{
njne427a662002-10-02 11:08:25 +00002167 VG_(core_panic)("do__apply_in_new_thread_bogusRA");
sewardj20917d82002-05-28 01:36:45 +00002168}
2169
2170/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2171 MUST NOT return -- ever. Eventually it will do either __QUIT or
2172 __WAIT_JOINER. Return the child tid to the parent. */
2173static
2174void do__apply_in_new_thread ( ThreadId parent_tid,
2175 void* (*fn)(void *),
2176 void* arg )
2177{
sewardje663cb92002-04-12 10:26:32 +00002178 Addr new_stack;
2179 UInt new_stk_szb;
2180 ThreadId tid;
2181 Char msg_buf[100];
2182
2183 /* Paranoia ... */
2184 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2185
sewardj018f7622002-05-15 21:13:39 +00002186 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002187
sewardj1e8cdc92002-04-18 11:37:52 +00002188 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002189
2190 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002191 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002192 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002193
sewardjc4a810d2002-11-13 22:25:51 +00002194 /* do this early, before the child gets any memory writes */
2195 VG_TRACK ( post_thread_create, parent_tid, tid );
2196
sewardjf6374322002-11-13 22:35:55 +00002197 /* Create new thread with default attrs:
2198 deferred cancellation, not detached
2199 */
2200 mostly_clear_thread_record(tid);
2201 VG_(threads)[tid].status = VgTs_Runnable;
2202
sewardje663cb92002-04-12 10:26:32 +00002203 /* Copy the parent's CPU state into the child's, in a roundabout
2204 way (via baseBlock). */
2205 VG_(load_thread_state)(parent_tid);
sewardjca340b32002-12-08 22:14:11 +00002206
2207 /* We inherit our parent's LDT. */
2208 if (VG_(threads)[parent_tid].ldt == NULL) {
2209 /* We hope this is the common case. */
2210 VG_(baseBlock)[VGOFF_(ldt)] = 0;
2211 } else {
2212 /* No luck .. we have to take a copy of the parent's. */
2213 VG_(threads)[tid].ldt
2214 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2215 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
2216 }
2217
sewardje663cb92002-04-12 10:26:32 +00002218 VG_(save_thread_state)(tid);
sewardjf6374322002-11-13 22:35:55 +00002219 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +00002220
2221 /* Consider allocating the child a stack, if the one it already has
2222 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002223 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002224
sewardj018f7622002-05-15 21:13:39 +00002225 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002226 /* Again, for good measure :) We definitely don't want to be
2227 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002228 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002229 /* for now, we don't handle the case of anything other than
2230 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002231 vg_assert(VG_(threads)[tid].stack_size == 0);
2232 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002233 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2234 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002235 VG_(threads)[tid].stack_base = new_stack;
2236 VG_(threads)[tid].stack_size = new_stk_szb;
2237 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002238 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002239 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002240 }
sewardj1e8cdc92002-04-18 11:37:52 +00002241
njn25e49d8e72002-09-23 09:36:25 +00002242 /* Having got memory to hold the thread's stack:
2243 - set %esp as base + size
2244 - mark everything below %esp inaccessible
2245 - mark redzone at stack end inaccessible
2246 */
2247 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2248 + VG_(threads)[tid].stack_size
2249 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002250
njn25e49d8e72002-09-23 09:36:25 +00002251 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2252 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2253 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2254 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002255
njn25e49d8e72002-09-23 09:36:25 +00002256 /* push two args */
2257 VG_(threads)[tid].m_esp -= 8;
2258 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2259 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2260 "new thread: stack",
2261 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2262
2263 /* push arg and (bogus) return address */
2264 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002265 * (UInt*)(VG_(threads)[tid].m_esp)
2266 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002267
njn25e49d8e72002-09-23 09:36:25 +00002268 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002269
2270 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002271 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002272
sewardj8937c812002-04-12 20:12:20 +00002273 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002274 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002275 print_sched_event(tid, msg_buf);
2276 }
2277
sewardj018f7622002-05-15 21:13:39 +00002278 /* We inherit our parent's signal mask. */
2279 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002280 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002281
sewardj20917d82002-05-28 01:36:45 +00002282 /* return child's tid to parent */
2283 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002284}
2285
2286
sewardj604ec3c2002-04-18 22:38:41 +00002287/* -----------------------------------------------------------
2288 MUTEXes
2289 -------------------------------------------------------- */
2290
sewardj604ec3c2002-04-18 22:38:41 +00002291/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002292 typedef struct
2293 {
2294 int __m_reserved; -- Reserved for future use
2295 int __m_count; -- Depth of recursive locking
2296 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2297 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2298 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2299 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002300
sewardj6072c362002-04-19 14:40:57 +00002301 #define PTHREAD_MUTEX_INITIALIZER \
2302 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2303 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2304 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2305 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2306 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2307 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2308 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002309
sewardj6072c362002-04-19 14:40:57 +00002310 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002311
sewardj6072c362002-04-19 14:40:57 +00002312 __m_kind never changes and indicates whether or not it is recursive.
2313
2314 __m_count indicates the lock count; if 0, the mutex is not owned by
2315 anybody.
2316
2317 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2318 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2319 statically initialised mutexes correctly appear
2320 to belong to nobody.
2321
2322 In summary, a not-in-use mutex is distinguised by having __m_owner
2323 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2324 conditions holds, the other should too.
2325
2326 There is no linked list of threads waiting for this mutex. Instead
2327 a thread in WaitMX state points at the mutex with its waited_on_mx
2328 field. This makes _unlock() inefficient, but simple to implement the
2329 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002330
sewardj604ec3c2002-04-18 22:38:41 +00002331 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002332 deals with that for us.
2333*/
sewardje663cb92002-04-12 10:26:32 +00002334
sewardj3b5d8862002-04-20 13:53:23 +00002335/* Helper fns ... */
2336static
2337void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2338 Char* caller )
2339{
2340 Int i;
2341 Char msg_buf[100];
2342
2343 /* Find some arbitrary thread waiting on this mutex, and make it
2344 runnable. If none are waiting, mark the mutex as not held. */
2345 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002346 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002347 continue;
sewardj018f7622002-05-15 21:13:39 +00002348 if (VG_(threads)[i].status == VgTs_WaitMX
2349 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002350 break;
2351 }
2352
sewardj0af43bc2002-10-22 04:30:35 +00002353 VG_TRACK( post_mutex_unlock, (ThreadId)mutex->__m_owner, mutex );
2354
sewardj3b5d8862002-04-20 13:53:23 +00002355 vg_assert(i <= VG_N_THREADS);
2356 if (i == VG_N_THREADS) {
2357 /* Nobody else is waiting on it. */
2358 mutex->__m_count = 0;
2359 mutex->__m_owner = VG_INVALID_THREADID;
2360 } else {
2361 /* Notionally transfer the hold to thread i, whose
2362 pthread_mutex_lock() call now returns with 0 (success). */
2363 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002364 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002365 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002366 VG_(threads)[i].status = VgTs_Runnable;
2367 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002368 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002369
sewardj0af43bc2002-10-22 04:30:35 +00002370 VG_TRACK( post_mutex_lock, (ThreadId)i, mutex);
2371
sewardj3b5d8862002-04-20 13:53:23 +00002372 if (VG_(clo_trace_pthread_level) >= 1) {
2373 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2374 caller, mutex );
2375 print_pthread_event(i, msg_buf);
2376 }
2377 }
2378}
2379
sewardje663cb92002-04-12 10:26:32 +00002380
2381static
sewardj30671ff2002-04-21 00:13:57 +00002382void do_pthread_mutex_lock( ThreadId tid,
2383 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002384 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002385{
sewardj30671ff2002-04-21 00:13:57 +00002386 Char msg_buf[100];
2387 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002388 = is_trylock ? "pthread_mutex_trylock"
2389 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002390
sewardj604ec3c2002-04-18 22:38:41 +00002391 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002392 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002393 print_pthread_event(tid, msg_buf);
2394 }
2395
2396 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002397 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002398 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002399
2400 /* POSIX doesn't mandate this, but for sanity ... */
2401 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002402 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002403 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002404 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002405 return;
2406 }
2407
sewardj604ec3c2002-04-18 22:38:41 +00002408 /* More paranoia ... */
2409 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002410# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002411 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002412 case PTHREAD_MUTEX_ADAPTIVE_NP:
2413# endif
sewardja1679dd2002-05-10 22:31:40 +00002414# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002415 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002416# endif
sewardj604ec3c2002-04-18 22:38:41 +00002417 case PTHREAD_MUTEX_RECURSIVE_NP:
2418 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002419 if (mutex->__m_count >= 0) break;
2420 /* else fall thru */
2421 default:
njn25e49d8e72002-09-23 09:36:25 +00002422 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002423 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002424 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002425 return;
sewardje663cb92002-04-12 10:26:32 +00002426 }
2427
sewardj604ec3c2002-04-18 22:38:41 +00002428 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002429
sewardjb48e5002002-05-13 00:16:03 +00002430 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002431
2432 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002433 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002434 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002435 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002436 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002437 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002438 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002439 if (0)
2440 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2441 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002442 return;
2443 } else {
sewardj30671ff2002-04-21 00:13:57 +00002444 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002445 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002446 else
sewardjc3bd5f52002-05-01 03:24:23 +00002447 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002448 return;
2449 }
2450 } else {
sewardj6072c362002-04-19 14:40:57 +00002451 /* Someone else has it; we have to wait. Mark ourselves
2452 thusly. */
sewardj05553872002-04-20 20:53:17 +00002453 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002454 if (is_trylock) {
2455 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002456 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002457 } else {
sewardjdca84112002-11-13 22:29:34 +00002458 VG_TRACK ( pre_mutex_lock, tid, mutex );
2459
sewardj018f7622002-05-15 21:13:39 +00002460 VG_(threads)[tid].status = VgTs_WaitMX;
2461 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002462 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002463 if (VG_(clo_trace_pthread_level) >= 1) {
2464 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2465 caller, mutex );
2466 print_pthread_event(tid, msg_buf);
2467 }
2468 }
sewardje663cb92002-04-12 10:26:32 +00002469 return;
2470 }
sewardjf8f819e2002-04-17 23:21:37 +00002471
sewardje663cb92002-04-12 10:26:32 +00002472 } else {
sewardj6072c362002-04-19 14:40:57 +00002473 /* Nobody owns it. Sanity check ... */
2474 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjdca84112002-11-13 22:29:34 +00002475
2476 VG_TRACK ( pre_mutex_lock, tid, mutex );
2477
sewardjf8f819e2002-04-17 23:21:37 +00002478 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002479 mutex->__m_count = 1;
2480 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002481
2482 VG_TRACK( post_mutex_lock, tid, mutex);
2483
sewardje663cb92002-04-12 10:26:32 +00002484 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002485 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002486 }
sewardjf8f819e2002-04-17 23:21:37 +00002487
sewardje663cb92002-04-12 10:26:32 +00002488}
2489
2490
2491static
2492void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002493 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002494{
sewardj3b5d8862002-04-20 13:53:23 +00002495 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002496
sewardj45b4b372002-04-16 22:50:32 +00002497 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002498 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002499 print_pthread_event(tid, msg_buf);
2500 }
2501
sewardj604ec3c2002-04-18 22:38:41 +00002502 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002503 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002504 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002505
2506 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002507 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002508 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002509 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002510 return;
2511 }
2512
sewardjd8acdf22002-11-13 21:57:52 +00002513 /* If this was locked before the dawn of time, pretend it was
2514 locked now so that it balances with unlocks */
2515 if (mutex->__m_kind & VG_PTHREAD_PREHISTORY) {
2516 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
sewardjdca84112002-11-13 22:29:34 +00002517 VG_TRACK( pre_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
sewardjd8acdf22002-11-13 21:57:52 +00002518 VG_TRACK( post_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
2519 }
2520
sewardj604ec3c2002-04-18 22:38:41 +00002521 /* More paranoia ... */
2522 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002523# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002524 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002525 case PTHREAD_MUTEX_ADAPTIVE_NP:
2526# endif
sewardja1679dd2002-05-10 22:31:40 +00002527# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002528 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002529# endif
sewardj604ec3c2002-04-18 22:38:41 +00002530 case PTHREAD_MUTEX_RECURSIVE_NP:
2531 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002532 if (mutex->__m_count >= 0) break;
2533 /* else fall thru */
2534 default:
njn25e49d8e72002-09-23 09:36:25 +00002535 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002536 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002537 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002538 return;
2539 }
sewardje663cb92002-04-12 10:26:32 +00002540
2541 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002542 if (mutex->__m_count == 0) {
2543 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002544 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002545 "pthread_mutex_unlock: mutex is not locked");
2546 SET_EDX(tid, EPERM);
2547 return;
2548 }
2549
2550 if ((ThreadId)mutex->__m_owner != tid) {
2551 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002552 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002553 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002554 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002555 return;
2556 }
2557
sewardjf8f819e2002-04-17 23:21:37 +00002558 /* If it's a multiply-locked recursive mutex, just decrement the
2559 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002560 if (mutex->__m_count > 1) {
2561 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2562 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002563 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002564 return;
2565 }
2566
sewardj604ec3c2002-04-18 22:38:41 +00002567 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002568 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002569 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002570 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002571
sewardj3b5d8862002-04-20 13:53:23 +00002572 /* Release at max one thread waiting on this mutex. */
2573 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002574
sewardj3b5d8862002-04-20 13:53:23 +00002575 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002576 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002577}
2578
2579
sewardj6072c362002-04-19 14:40:57 +00002580/* -----------------------------------------------------------
2581 CONDITION VARIABLES
2582 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002583
sewardj6072c362002-04-19 14:40:57 +00002584/* The relevant native types are as follows:
2585 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002586
sewardj6072c362002-04-19 14:40:57 +00002587 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2588 typedef struct
2589 {
2590 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2591 _pthread_descr __c_waiting; -- Threads waiting on this condition
2592 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002593
sewardj6072c362002-04-19 14:40:57 +00002594 -- Attribute for conditionally variables.
2595 typedef struct
2596 {
2597 int __dummy;
2598 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002599
sewardj6072c362002-04-19 14:40:57 +00002600 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002601
sewardj3b5d8862002-04-20 13:53:23 +00002602 We don't use any fields of pthread_cond_t for anything at all.
2603 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002604
2605 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002606 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002607
sewardj77e466c2002-04-14 02:29:29 +00002608
sewardj5f07b662002-04-23 16:52:51 +00002609static
2610void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2611{
2612 Char msg_buf[100];
2613 pthread_mutex_t* mx;
2614 pthread_cond_t* cv;
2615
sewardjb48e5002002-05-13 00:16:03 +00002616 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002617 && VG_(threads)[tid].status == VgTs_WaitCV
2618 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2619 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002620 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002621 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002622 vg_assert(cv != NULL);
2623
2624 if (mx->__m_owner == VG_INVALID_THREADID) {
2625 /* Currently unheld; hand it out to thread tid. */
2626 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002627 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002628 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002629 VG_(threads)[tid].associated_cv = NULL;
2630 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002631 mx->__m_owner = (_pthread_descr)tid;
2632 mx->__m_count = 1;
2633
sewardj0af43bc2002-10-22 04:30:35 +00002634 VG_TRACK( post_mutex_lock, tid, mx );
2635
sewardj5f07b662002-04-23 16:52:51 +00002636 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002637 VG_(sprintf)(msg_buf,
2638 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2639 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002640 print_pthread_event(tid, msg_buf);
2641 }
2642 } else {
2643 /* Currently held. Make thread tid be blocked on it. */
2644 vg_assert(mx->__m_count > 0);
sewardjdca84112002-11-13 22:29:34 +00002645 VG_TRACK( pre_mutex_lock, tid, mx );
2646
sewardj018f7622002-05-15 21:13:39 +00002647 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002648 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002649 VG_(threads)[tid].associated_cv = NULL;
2650 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002651 if (VG_(clo_trace_pthread_level) >= 1) {
2652 VG_(sprintf)(msg_buf,
2653 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2654 cv, mx );
2655 print_pthread_event(tid, msg_buf);
2656 }
2657
2658 }
2659}
2660
2661
sewardj3b5d8862002-04-20 13:53:23 +00002662static
2663void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2664 Int n_to_release,
2665 Char* caller )
2666{
2667 Int i;
2668 Char msg_buf[100];
2669 pthread_mutex_t* mx;
2670
2671 while (True) {
2672 if (n_to_release == 0)
2673 return;
2674
2675 /* Find a thread waiting on this CV. */
2676 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002677 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002678 continue;
sewardj018f7622002-05-15 21:13:39 +00002679 if (VG_(threads)[i].status == VgTs_WaitCV
2680 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002681 break;
2682 }
2683 vg_assert(i <= VG_N_THREADS);
2684
2685 if (i == VG_N_THREADS) {
2686 /* Nobody else is waiting on it. */
2687 return;
2688 }
2689
sewardj018f7622002-05-15 21:13:39 +00002690 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002691 vg_assert(mx != NULL);
2692
sewardjdca84112002-11-13 22:29:34 +00002693 VG_TRACK( pre_mutex_lock, i, mx );
2694
sewardj3b5d8862002-04-20 13:53:23 +00002695 if (mx->__m_owner == VG_INVALID_THREADID) {
2696 /* Currently unheld; hand it out to thread i. */
2697 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002698 VG_(threads)[i].status = VgTs_Runnable;
2699 VG_(threads)[i].associated_cv = NULL;
2700 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002701 mx->__m_owner = (_pthread_descr)i;
2702 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002703 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002704
sewardj0af43bc2002-10-22 04:30:35 +00002705 VG_TRACK( post_mutex_lock, i, mx );
2706
sewardj3b5d8862002-04-20 13:53:23 +00002707 if (VG_(clo_trace_pthread_level) >= 1) {
2708 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2709 caller, cond, mx );
2710 print_pthread_event(i, msg_buf);
2711 }
2712
2713 } else {
2714 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002715 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002716 VG_(threads)[i].status = VgTs_WaitMX;
2717 VG_(threads)[i].associated_cv = NULL;
2718 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002719 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002720
2721 if (VG_(clo_trace_pthread_level) >= 1) {
2722 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2723 caller, cond, mx );
2724 print_pthread_event(i, msg_buf);
2725 }
2726
2727 }
2728
2729 n_to_release--;
2730 }
2731}
2732
2733
2734static
2735void do_pthread_cond_wait ( ThreadId tid,
2736 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002737 pthread_mutex_t *mutex,
2738 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002739{
2740 Char msg_buf[100];
2741
sewardj5f07b662002-04-23 16:52:51 +00002742 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2743 ms_end is the ending millisecond. */
2744
sewardj3b5d8862002-04-20 13:53:23 +00002745 /* pre: mutex should be a valid mutex and owned by tid. */
2746 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002747 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2748 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002749 print_pthread_event(tid, msg_buf);
2750 }
2751
2752 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002753 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002754 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002755
2756 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002757 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002758 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002759 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002760 return;
2761 }
2762
2763 /* More paranoia ... */
2764 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002765# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002766 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002767 case PTHREAD_MUTEX_ADAPTIVE_NP:
2768# endif
sewardja1679dd2002-05-10 22:31:40 +00002769# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002770 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002771# endif
sewardj3b5d8862002-04-20 13:53:23 +00002772 case PTHREAD_MUTEX_RECURSIVE_NP:
2773 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002774 if (mutex->__m_count >= 0) break;
2775 /* else fall thru */
2776 default:
njn25e49d8e72002-09-23 09:36:25 +00002777 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002778 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002779 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002780 return;
2781 }
2782
2783 /* Barf if we don't currently hold the mutex. */
2784 if (mutex->__m_count == 0 /* nobody holds it */
2785 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002786 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002787 "pthread_cond_wait/timedwait: mutex is unlocked "
2788 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002789 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002790 return;
2791 }
2792
2793 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002794 VG_(threads)[tid].status = VgTs_WaitCV;
2795 VG_(threads)[tid].associated_cv = cond;
2796 VG_(threads)[tid].associated_mx = mutex;
2797 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002798
2799 if (VG_(clo_trace_pthread_level) >= 1) {
2800 VG_(sprintf)(msg_buf,
2801 "pthread_cond_wait cv %p, mx %p: BLOCK",
2802 cond, mutex );
2803 print_pthread_event(tid, msg_buf);
2804 }
2805
2806 /* Release the mutex. */
2807 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2808}
2809
2810
2811static
2812void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2813 Bool broadcast,
2814 pthread_cond_t *cond )
2815{
2816 Char msg_buf[100];
2817 Char* caller
2818 = broadcast ? "pthread_cond_broadcast"
2819 : "pthread_cond_signal ";
2820
2821 if (VG_(clo_trace_pthread_level) >= 2) {
2822 VG_(sprintf)(msg_buf, "%s cv %p ...",
2823 caller, cond );
2824 print_pthread_event(tid, msg_buf);
2825 }
2826
2827 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002828 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002829 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002830
2831 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002832 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002833 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002834 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002835 return;
2836 }
2837
2838 release_N_threads_waiting_on_cond (
2839 cond,
2840 broadcast ? VG_N_THREADS : 1,
2841 caller
2842 );
2843
sewardjc3bd5f52002-05-01 03:24:23 +00002844 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002845}
2846
sewardj77e466c2002-04-14 02:29:29 +00002847
sewardj5f07b662002-04-23 16:52:51 +00002848/* -----------------------------------------------------------
2849 THREAD SPECIFIC DATA
2850 -------------------------------------------------------- */
2851
2852static __inline__
2853Bool is_valid_key ( ThreadKey k )
2854{
2855 /* k unsigned; hence no < 0 check */
2856 if (k >= VG_N_THREAD_KEYS) return False;
2857 if (!vg_thread_keys[k].inuse) return False;
2858 return True;
2859}
2860
sewardj00a66b12002-10-12 16:42:35 +00002861
2862/* Return in %EDX a value of 1 if the key is valid, else 0. */
2863static
2864void do_pthread_key_validate ( ThreadId tid,
2865 pthread_key_t key )
2866{
2867 Char msg_buf[100];
2868
2869 if (VG_(clo_trace_pthread_level) >= 1) {
2870 VG_(sprintf)(msg_buf, "pthread_key_validate key %p",
2871 key );
2872 print_pthread_event(tid, msg_buf);
2873 }
2874
2875 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
2876 vg_assert(VG_(is_valid_tid)(tid)
2877 && VG_(threads)[tid].status == VgTs_Runnable);
2878
2879 if (is_valid_key((ThreadKey)key)) {
2880 SET_EDX(tid, 1);
2881 } else {
2882 SET_EDX(tid, 0);
2883 }
2884}
2885
2886
sewardj5f07b662002-04-23 16:52:51 +00002887static
2888void do_pthread_key_create ( ThreadId tid,
2889 pthread_key_t* key,
2890 void (*destructor)(void*) )
2891{
2892 Int i;
2893 Char msg_buf[100];
2894
2895 if (VG_(clo_trace_pthread_level) >= 1) {
2896 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2897 key, destructor );
2898 print_pthread_event(tid, msg_buf);
2899 }
2900
2901 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002902 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002903 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002904
2905 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2906 if (!vg_thread_keys[i].inuse)
2907 break;
2908
2909 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002910 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002911 return;
2912 */
njne427a662002-10-02 11:08:25 +00002913 VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2914 " increase and recompile");
sewardj5f07b662002-04-23 16:52:51 +00002915 }
2916
sewardj870497a2002-05-29 01:06:47 +00002917 vg_thread_keys[i].inuse = True;
2918 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002919
sewardj5a3798b2002-06-04 23:24:22 +00002920 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002921 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2922 "pthread_key_create: key",
2923 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002924 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002925 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002926
2927 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002928}
2929
2930
2931static
2932void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2933{
2934 Char msg_buf[100];
2935 if (VG_(clo_trace_pthread_level) >= 1) {
2936 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2937 key );
2938 print_pthread_event(tid, msg_buf);
2939 }
2940
sewardjb48e5002002-05-13 00:16:03 +00002941 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002942 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002943
2944 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002945 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002946 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002947 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002948 return;
2949 }
2950
2951 vg_thread_keys[key].inuse = False;
sewardj648b3152002-12-09 19:07:59 +00002952 vg_thread_keys[key].destructor = NULL;
sewardj00a66b12002-10-12 16:42:35 +00002953 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002954}
2955
2956
sewardj00a66b12002-10-12 16:42:35 +00002957/* Get the .specific_ptr for a thread. Return 1 if the thread-slot
2958 isn't in use, so that client-space can scan all thread slots. 1
2959 cannot be confused with NULL or a legitimately-aligned specific_ptr
2960 value. */
sewardj5f07b662002-04-23 16:52:51 +00002961static
sewardj00a66b12002-10-12 16:42:35 +00002962void do_pthread_getspecific_ptr ( ThreadId tid )
sewardj5f07b662002-04-23 16:52:51 +00002963{
sewardj00a66b12002-10-12 16:42:35 +00002964 void** specifics_ptr;
2965 Char msg_buf[100];
2966
sewardj5f07b662002-04-23 16:52:51 +00002967 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002968 VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
sewardj5f07b662002-04-23 16:52:51 +00002969 print_pthread_event(tid, msg_buf);
2970 }
2971
sewardj00a66b12002-10-12 16:42:35 +00002972 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardj5f07b662002-04-23 16:52:51 +00002973
sewardj00a66b12002-10-12 16:42:35 +00002974 if (VG_(threads)[tid].status == VgTs_Empty) {
2975 SET_EDX(tid, 1);
sewardj5f07b662002-04-23 16:52:51 +00002976 return;
2977 }
2978
sewardj00a66b12002-10-12 16:42:35 +00002979 specifics_ptr = VG_(threads)[tid].specifics_ptr;
2980 vg_assert(specifics_ptr == NULL
2981 || IS_ALIGNED4_ADDR(specifics_ptr));
2982
2983 SET_EDX(tid, (UInt)specifics_ptr);
sewardj5f07b662002-04-23 16:52:51 +00002984}
2985
2986
2987static
sewardj00a66b12002-10-12 16:42:35 +00002988void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
sewardj5f07b662002-04-23 16:52:51 +00002989{
2990 Char msg_buf[100];
2991 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002992 VG_(sprintf)(msg_buf, "pthread_setspecific_ptr ptr %p",
2993 ptr );
sewardj5f07b662002-04-23 16:52:51 +00002994 print_pthread_event(tid, msg_buf);
2995 }
2996
sewardjb48e5002002-05-13 00:16:03 +00002997 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002998 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002999
sewardj00a66b12002-10-12 16:42:35 +00003000 VG_(threads)[tid].specifics_ptr = ptr;
sewardjc3bd5f52002-05-01 03:24:23 +00003001 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00003002}
3003
3004
sewardj870497a2002-05-29 01:06:47 +00003005/* Helper for calling destructors at thread exit. If key is valid,
3006 copy the thread's specific value into cu->arg and put the *key*'s
3007 destructor fn address in cu->fn. Then return 0 to the caller.
3008 Otherwise return non-zero to the caller. */
3009static
3010void do__get_key_destr_and_spec ( ThreadId tid,
3011 pthread_key_t key,
3012 CleanupEntry* cu )
3013{
3014 Char msg_buf[100];
3015 if (VG_(clo_trace_pthread_level) >= 1) {
3016 VG_(sprintf)(msg_buf,
3017 "get_key_destr_and_arg (key = %d)", key );
3018 print_pthread_event(tid, msg_buf);
3019 }
3020 vg_assert(VG_(is_valid_tid)(tid));
3021 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00003022
sewardj870497a2002-05-29 01:06:47 +00003023 if (!vg_thread_keys[key].inuse) {
3024 SET_EDX(tid, -1);
3025 return;
3026 }
njn36650922002-10-04 09:18:09 +00003027 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
sewardj00a66b12002-10-12 16:42:35 +00003028 "get_key_destr_and_spec: cu", (Addr)cu,
njn36650922002-10-04 09:18:09 +00003029 sizeof(CleanupEntry) );
sewardj00a66b12002-10-12 16:42:35 +00003030
sewardj870497a2002-05-29 01:06:47 +00003031 cu->fn = vg_thread_keys[key].destructor;
sewardj00a66b12002-10-12 16:42:35 +00003032 if (VG_(threads)[tid].specifics_ptr == NULL) {
3033 cu->arg = NULL;
3034 } else {
3035 VG_TRACK( pre_mem_read, Vg_CorePThread, & VG_(threads)[tid],
3036 "get_key_destr_and_spec: key",
3037 (Addr)(&VG_(threads)[tid].specifics_ptr[key]),
3038 sizeof(void*) );
3039 cu->arg = VG_(threads)[tid].specifics_ptr[key];
3040 }
3041
njn25e49d8e72002-09-23 09:36:25 +00003042 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00003043 SET_EDX(tid, 0);
3044}
3045
3046
sewardjb48e5002002-05-13 00:16:03 +00003047/* ---------------------------------------------------
3048 SIGNALS
3049 ------------------------------------------------ */
3050
3051/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00003052 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
3053 for OK and 1 for some kind of addressing error, which the
3054 vg_libpthread.c routine turns into return values 0 and EFAULT
3055 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00003056static
3057void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00003058 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00003059 vki_ksigset_t* newmask,
3060 vki_ksigset_t* oldmask )
3061{
3062 Char msg_buf[100];
3063 if (VG_(clo_trace_pthread_level) >= 1) {
3064 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00003065 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
3066 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003067 print_pthread_event(tid, msg_buf);
3068 }
3069
3070 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003071 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003072
njn25e49d8e72002-09-23 09:36:25 +00003073 if (newmask)
3074 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3075 "pthread_sigmask: newmask",
3076 (Addr)newmask, sizeof(vki_ksigset_t));
3077 if (oldmask)
3078 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3079 "pthread_sigmask: oldmask",
3080 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00003081
sewardj018f7622002-05-15 21:13:39 +00003082 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003083
njn25e49d8e72002-09-23 09:36:25 +00003084 if (oldmask)
3085 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00003086
sewardj018f7622002-05-15 21:13:39 +00003087 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00003088 SET_EDX(tid, 0);
3089}
3090
3091
3092static
3093void do_sigwait ( ThreadId tid,
3094 vki_ksigset_t* set,
3095 Int* sig )
3096{
sewardj018f7622002-05-15 21:13:39 +00003097 vki_ksigset_t irrelevant_sigmask;
3098 Char msg_buf[100];
3099
sewardjb48e5002002-05-13 00:16:03 +00003100 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3101 VG_(sprintf)(msg_buf,
3102 "suspend due to sigwait(): set %p, sig %p",
3103 set, sig );
3104 print_pthread_event(tid, msg_buf);
3105 }
3106
3107 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003108 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003109
sewardj018f7622002-05-15 21:13:39 +00003110 /* Change SCSS */
3111 VG_(threads)[tid].sigs_waited_for = *set;
3112 VG_(threads)[tid].status = VgTs_WaitSIG;
3113
3114 VG_(block_all_host_signals)( &irrelevant_sigmask );
3115 VG_(handle_SCSS_change)( False /* lazy update */ );
3116}
3117
3118
3119static
3120void do_pthread_kill ( ThreadId tid, /* me */
3121 ThreadId thread, /* thread to signal */
3122 Int sig )
3123{
3124 Char msg_buf[100];
3125
3126 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3127 VG_(sprintf)(msg_buf,
3128 "pthread_kill thread %d, signo %d",
3129 thread, sig );
3130 print_pthread_event(tid, msg_buf);
3131 }
3132
3133 vg_assert(VG_(is_valid_tid)(tid)
3134 && VG_(threads)[tid].status == VgTs_Runnable);
3135
sewardj4dced352002-06-04 22:54:20 +00003136 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003137 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003138 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003139 SET_EDX(tid, -VKI_ESRCH);
3140 return;
3141 }
3142
3143 if (sig < 1 || sig > VKI_KNSIG) {
3144 SET_EDX(tid, -VKI_EINVAL);
3145 return;
3146 }
3147
3148 VG_(send_signal_to_thread)( thread, sig );
3149 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003150}
3151
3152
sewardj2cb00342002-06-28 01:46:26 +00003153/* -----------------------------------------------------------
3154 FORK HANDLERS.
3155 -------------------------------------------------------- */
3156
3157static
3158void do__set_fhstack_used ( ThreadId tid, Int n )
3159{
3160 Char msg_buf[100];
3161 if (VG_(clo_trace_sched)) {
3162 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3163 print_pthread_event(tid, msg_buf);
3164 }
3165
3166 vg_assert(VG_(is_valid_tid)(tid)
3167 && VG_(threads)[tid].status == VgTs_Runnable);
3168
3169 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3170 vg_fhstack_used = n;
3171 SET_EDX(tid, 0);
3172 } else {
3173 SET_EDX(tid, -1);
3174 }
3175}
3176
3177
3178static
3179void do__get_fhstack_used ( ThreadId tid )
3180{
3181 Int n;
3182 Char msg_buf[100];
3183 if (VG_(clo_trace_sched)) {
3184 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3185 print_pthread_event(tid, msg_buf);
3186 }
3187
3188 vg_assert(VG_(is_valid_tid)(tid)
3189 && VG_(threads)[tid].status == VgTs_Runnable);
3190
3191 n = vg_fhstack_used;
3192 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3193 SET_EDX(tid, n);
3194}
3195
3196static
3197void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3198{
3199 Char msg_buf[100];
3200 if (VG_(clo_trace_sched)) {
3201 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3202 print_pthread_event(tid, msg_buf);
3203 }
3204
3205 vg_assert(VG_(is_valid_tid)(tid)
3206 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003207 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3208 "pthread_atfork: prepare/parent/child",
3209 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003210
njn25e49d8e72002-09-23 09:36:25 +00003211 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003212 SET_EDX(tid, -1);
3213 return;
3214 }
3215
3216 vg_fhstack[n] = *fh;
3217 SET_EDX(tid, 0);
3218}
3219
3220
3221static
3222void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3223 ForkHandlerEntry* fh )
3224{
3225 Char msg_buf[100];
3226 if (VG_(clo_trace_sched)) {
3227 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3228 print_pthread_event(tid, msg_buf);
3229 }
3230
3231 vg_assert(VG_(is_valid_tid)(tid)
3232 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003233 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3234 "fork: prepare/parent/child",
3235 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003236
njn25e49d8e72002-09-23 09:36:25 +00003237 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003238 SET_EDX(tid, -1);
3239 return;
3240 }
3241
3242 *fh = vg_fhstack[n];
3243 SET_EDX(tid, 0);
3244
njn25e49d8e72002-09-23 09:36:25 +00003245 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003246}
3247
3248
sewardje663cb92002-04-12 10:26:32 +00003249/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003250 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003251 ------------------------------------------------------------------ */
3252
sewardj124ca2a2002-06-20 10:19:38 +00003253/* Do a client request for the thread tid. After the request, tid may
3254 or may not still be runnable; if not, the scheduler will have to
3255 choose a new thread to run.
3256*/
sewardje663cb92002-04-12 10:26:32 +00003257static
sewardj124ca2a2002-06-20 10:19:38 +00003258void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003259{
njn25e49d8e72002-09-23 09:36:25 +00003260# define RETURN_WITH(vvv) \
3261 { tst->m_edx = (vvv); \
3262 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003263 }
3264
3265 ThreadState* tst = &VG_(threads)[tid];
3266 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3267 UInt req_no = arg[0];
3268
3269 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003270 switch (req_no) {
3271
njn3e884182003-04-15 13:03:23 +00003272 /* For the CLIENT_{,tst}CALL[0123] ones, have to do some nasty casting
3273 to make gcc believe it's a function. */
3274 case VG_USERREQ__CLIENT_CALL0: {
3275 UInt (*f)(void) = (void*)arg[1];
3276 RETURN_WITH(
3277 f ( )
3278 );
3279 break;
3280 }
3281 case VG_USERREQ__CLIENT_CALL1: {
3282 UInt (*f)(UInt) = (void*)arg[1];
3283 RETURN_WITH(
3284 f ( arg[2] )
3285 );
3286 break;
3287 }
3288 case VG_USERREQ__CLIENT_CALL2: {
3289 UInt (*f)(UInt, UInt) = (void*)arg[1];
3290 RETURN_WITH(
3291 f ( arg[2], arg[3] )
3292 );
3293 break;
3294 }
3295 case VG_USERREQ__CLIENT_CALL3: {
3296 UInt (*f)(UInt, UInt, UInt) = (void*)arg[1];
3297 RETURN_WITH(
3298 f ( arg[2], arg[3], arg[4] )
3299 );
3300 break;
3301 }
3302
3303 case VG_USERREQ__CLIENT_tstCALL0: {
3304 UInt (*f)(ThreadState*) = (void*)arg[1];
3305 RETURN_WITH(
3306 f ( tst )
3307 );
3308 break;
3309 }
3310 case VG_USERREQ__CLIENT_tstCALL1: {
3311 UInt (*f)(ThreadState*, UInt) = (void*)arg[1];
3312 RETURN_WITH(
3313 f ( tst, arg[2] )
3314 );
3315 break;
3316 }
3317 case VG_USERREQ__CLIENT_tstCALL2: {
3318 UInt (*f)(ThreadState*, UInt, UInt) = (void*)arg[1];
3319 RETURN_WITH(
3320 f ( tst, arg[2], arg[3] )
3321 );
3322 break;
3323 }
3324 case VG_USERREQ__CLIENT_tstCALL3: {
3325 UInt (*f)(ThreadState*, UInt, UInt, UInt) = (void*)arg[1];
3326 RETURN_WITH(
3327 f ( tst, arg[2], arg[3], arg[4] )
3328 );
3329 break;
3330 }
3331
3332 /* Note: for skins that replace malloc() et al, we want to call
3333 the replacement versions. For those that don't, we want to call
3334 VG_(cli_malloc)() et al. We do this by calling SK_(malloc)(), which
3335 malloc-replacing skins must replace, but have its default definition
3336 call */
3337
3338 /* Note: for MALLOC and FREE, must set the appropriate "lock"... see
3339 the comment in vg_defaults.c/SK_(malloc)() for why. */
sewardj124ca2a2002-06-20 10:19:38 +00003340 case VG_USERREQ__MALLOC:
njn3e884182003-04-15 13:03:23 +00003341 VG_(sk_malloc_called_by_scheduler) = True;
sewardj124ca2a2002-06-20 10:19:38 +00003342 RETURN_WITH(
njn3e884182003-04-15 13:03:23 +00003343 (UInt)SK_(malloc) ( tst, arg[1] )
sewardj124ca2a2002-06-20 10:19:38 +00003344 );
njn3e884182003-04-15 13:03:23 +00003345 VG_(sk_malloc_called_by_scheduler) = False;
sewardj124ca2a2002-06-20 10:19:38 +00003346 break;
3347
3348 case VG_USERREQ__FREE:
njn3e884182003-04-15 13:03:23 +00003349 VG_(sk_malloc_called_by_scheduler) = True;
3350 SK_(free) ( tst, (void*)arg[1] );
3351 VG_(sk_malloc_called_by_scheduler) = False;
sewardj124ca2a2002-06-20 10:19:38 +00003352 RETURN_WITH(0); /* irrelevant */
3353 break;
3354
sewardj124ca2a2002-06-20 10:19:38 +00003355 case VG_USERREQ__PTHREAD_GET_THREADID:
3356 RETURN_WITH(tid);
3357 break;
3358
3359 case VG_USERREQ__RUNNING_ON_VALGRIND:
3360 RETURN_WITH(1);
3361 break;
3362
3363 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3364 RETURN_WITH(VG_(clo_trace_pthread_level));
3365 break;
3366
3367 case VG_USERREQ__READ_MILLISECOND_TIMER:
3368 RETURN_WITH(VG_(read_millisecond_timer)());
3369 break;
3370
3371 /* Some of these may make thread tid non-runnable, but the
3372 scheduler checks for that on return from this function. */
3373 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3374 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3375 break;
3376
3377 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3378 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3379 break;
3380
3381 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3382 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3383 break;
3384
sewardj00a66b12002-10-12 16:42:35 +00003385 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
3386 do_pthread_getspecific_ptr ( tid );
sewardj124ca2a2002-06-20 10:19:38 +00003387 break;
3388
3389 case VG_USERREQ__SET_CANCELTYPE:
3390 do__set_canceltype ( tid, arg[1] );
3391 break;
3392
3393 case VG_USERREQ__CLEANUP_PUSH:
3394 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3395 break;
3396
3397 case VG_USERREQ__CLEANUP_POP:
3398 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3399 break;
3400
3401 case VG_USERREQ__TESTCANCEL:
3402 do__testcancel ( tid );
3403 break;
3404
3405 case VG_USERREQ__GET_N_SIGS_RETURNED:
3406 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3407 break;
3408
sewardje663cb92002-04-12 10:26:32 +00003409 case VG_USERREQ__PTHREAD_JOIN:
3410 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3411 break;
3412
sewardj3b5d8862002-04-20 13:53:23 +00003413 case VG_USERREQ__PTHREAD_COND_WAIT:
3414 do_pthread_cond_wait( tid,
3415 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003416 (pthread_mutex_t *)(arg[2]),
3417 0xFFFFFFFF /* no timeout */ );
3418 break;
3419
3420 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3421 do_pthread_cond_wait( tid,
3422 (pthread_cond_t *)(arg[1]),
3423 (pthread_mutex_t *)(arg[2]),
3424 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003425 break;
3426
3427 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3428 do_pthread_cond_signal_or_broadcast(
3429 tid,
3430 False, /* signal, not broadcast */
3431 (pthread_cond_t *)(arg[1]) );
3432 break;
3433
3434 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3435 do_pthread_cond_signal_or_broadcast(
3436 tid,
3437 True, /* broadcast, not signal */
3438 (pthread_cond_t *)(arg[1]) );
3439 break;
3440
sewardj00a66b12002-10-12 16:42:35 +00003441 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
3442 do_pthread_key_validate ( tid,
3443 (pthread_key_t)(arg[1]) );
3444 break;
3445
sewardj5f07b662002-04-23 16:52:51 +00003446 case VG_USERREQ__PTHREAD_KEY_CREATE:
3447 do_pthread_key_create ( tid,
3448 (pthread_key_t*)(arg[1]),
3449 (void(*)(void*))(arg[2]) );
3450 break;
3451
3452 case VG_USERREQ__PTHREAD_KEY_DELETE:
3453 do_pthread_key_delete ( tid,
3454 (pthread_key_t)(arg[1]) );
3455 break;
3456
sewardj00a66b12002-10-12 16:42:35 +00003457 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
3458 do_pthread_setspecific_ptr ( tid,
3459 (void**)(arg[1]) );
sewardj5f07b662002-04-23 16:52:51 +00003460 break;
3461
sewardjb48e5002002-05-13 00:16:03 +00003462 case VG_USERREQ__PTHREAD_SIGMASK:
3463 do_pthread_sigmask ( tid,
3464 arg[1],
3465 (vki_ksigset_t*)(arg[2]),
3466 (vki_ksigset_t*)(arg[3]) );
3467 break;
3468
3469 case VG_USERREQ__SIGWAIT:
3470 do_sigwait ( tid,
3471 (vki_ksigset_t*)(arg[1]),
3472 (Int*)(arg[2]) );
3473 break;
3474
sewardj018f7622002-05-15 21:13:39 +00003475 case VG_USERREQ__PTHREAD_KILL:
3476 do_pthread_kill ( tid, arg[1], arg[2] );
3477 break;
3478
sewardjff42d1d2002-05-22 13:17:31 +00003479 case VG_USERREQ__PTHREAD_YIELD:
3480 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003481 /* On return from do_client_request(), the scheduler will
3482 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003483 break;
sewardj018f7622002-05-15 21:13:39 +00003484
sewardj7989d0c2002-05-28 11:00:01 +00003485 case VG_USERREQ__SET_CANCELSTATE:
3486 do__set_cancelstate ( tid, arg[1] );
3487 break;
3488
sewardj7989d0c2002-05-28 11:00:01 +00003489 case VG_USERREQ__SET_OR_GET_DETACH:
3490 do__set_or_get_detach ( tid, arg[1], arg[2] );
3491 break;
3492
3493 case VG_USERREQ__SET_CANCELPEND:
3494 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3495 break;
3496
3497 case VG_USERREQ__WAIT_JOINER:
3498 do__wait_joiner ( tid, (void*)arg[1] );
3499 break;
3500
3501 case VG_USERREQ__QUIT:
3502 do__quit ( tid );
3503 break;
3504
3505 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3506 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3507 (void*)arg[2] );
3508 break;
3509
sewardj870497a2002-05-29 01:06:47 +00003510 case VG_USERREQ__GET_KEY_D_AND_S:
3511 do__get_key_destr_and_spec ( tid,
3512 (pthread_key_t)arg[1],
3513 (CleanupEntry*)arg[2] );
3514 break;
3515
sewardjef037c72002-05-30 00:40:03 +00003516 case VG_USERREQ__NUKE_OTHER_THREADS:
3517 VG_(nuke_all_threads_except) ( tid );
3518 SET_EDX(tid, 0);
3519 break;
3520
sewardj4dced352002-06-04 22:54:20 +00003521 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003522 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003523 SET_EDX(tid, 0);
3524 break;
3525
sewardj2cb00342002-06-28 01:46:26 +00003526 case VG_USERREQ__SET_FHSTACK_USED:
3527 do__set_fhstack_used( tid, (Int)(arg[1]) );
3528 break;
3529
3530 case VG_USERREQ__GET_FHSTACK_USED:
3531 do__get_fhstack_used( tid );
3532 break;
3533
3534 case VG_USERREQ__SET_FHSTACK_ENTRY:
3535 do__set_fhstack_entry( tid, (Int)(arg[1]),
3536 (ForkHandlerEntry*)(arg[2]) );
3537 break;
3538
3539 case VG_USERREQ__GET_FHSTACK_ENTRY:
3540 do__get_fhstack_entry( tid, (Int)(arg[1]),
3541 (ForkHandlerEntry*)(arg[2]) );
3542 break;
3543
sewardj77e466c2002-04-14 02:29:29 +00003544 case VG_USERREQ__SIGNAL_RETURNS:
3545 handle_signal_return(tid);
3546 break;
sewardj69a72a52002-11-03 13:41:41 +00003547
njn25e49d8e72002-09-23 09:36:25 +00003548 /* Requests from the client program */
3549
3550 case VG_USERREQ__DISCARD_TRANSLATIONS:
3551 if (VG_(clo_verbosity) > 2)
3552 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3553 " addr %p, len %d\n",
3554 (void*)arg[1], arg[2] );
3555
sewardj97ad5522003-05-04 12:32:56 +00003556 VG_(invalidate_translations)( arg[1], arg[2], True );
njn25e49d8e72002-09-23 09:36:25 +00003557
3558 SET_EDX( tid, 0 ); /* return value is meaningless */
3559 break;
3560
njn47363ab2003-04-21 13:24:40 +00003561 case VG_USERREQ__COUNT_ERRORS:
3562 SET_EDX( tid, VG_(n_errs_found) );
3563 break;
3564
sewardje663cb92002-04-12 10:26:32 +00003565 default:
njn25e49d8e72002-09-23 09:36:25 +00003566 if (VG_(needs).client_requests) {
sewardj34042512002-10-22 04:14:35 +00003567 UInt ret;
3568
njn25e49d8e72002-09-23 09:36:25 +00003569 if (VG_(clo_verbosity) > 2)
3570 VG_(printf)("client request: code %d, addr %p, len %d\n",
3571 arg[0], (void*)arg[1], arg[2] );
3572
sewardj34042512002-10-22 04:14:35 +00003573 if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret ))
3574 SET_EDX(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00003575 } else {
sewardj34042512002-10-22 04:14:35 +00003576 static Bool whined = False;
3577
3578 if (!whined) {
3579 VG_(message)(Vg_UserMsg, "Warning:\n"
3580 " unhandled client request: 0x%x (%c%c+%d). Perhaps\n"
3581 " VG_(needs).client_requests should be set?\n",
3582 arg[0], (arg[0] >> 24) & 0xff, (arg[0] >> 16) & 0xff,
3583 arg[0] & 0xffff);
3584 whined = True;
3585 }
njn25e49d8e72002-09-23 09:36:25 +00003586 }
sewardje663cb92002-04-12 10:26:32 +00003587 break;
3588 }
sewardj124ca2a2002-06-20 10:19:38 +00003589
3590# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003591}
3592
3593
sewardj6072c362002-04-19 14:40:57 +00003594/* ---------------------------------------------------------------------
3595 Sanity checking.
3596 ------------------------------------------------------------------ */
3597
3598/* Internal consistency checks on the sched/pthread structures. */
3599static
3600void scheduler_sanity ( void )
3601{
sewardj3b5d8862002-04-20 13:53:23 +00003602 pthread_mutex_t* mx;
3603 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003604 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003605
sewardj6072c362002-04-19 14:40:57 +00003606 /* VG_(printf)("scheduler_sanity\n"); */
3607 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003608 mx = VG_(threads)[i].associated_mx;
3609 cv = VG_(threads)[i].associated_cv;
3610 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003611 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3612 it's actually held by someone, since otherwise this thread
3613 is deadlocked, (4) the mutex's owner is not us, since
3614 otherwise this thread is also deadlocked. The logic in
3615 do_pthread_mutex_lock rejects attempts by a thread to lock
3616 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003617
sewardjbf290b92002-05-01 02:28:01 +00003618 (2) has been seen to fail sometimes. I don't know why.
3619 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003620 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003621 /* 1 */ vg_assert(mx != NULL);
3622 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003623 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003624 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003625 } else
sewardj018f7622002-05-15 21:13:39 +00003626 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003627 vg_assert(cv != NULL);
3628 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003629 } else {
sewardj05553872002-04-20 20:53:17 +00003630 /* Unfortunately these don't hold true when a sighandler is
3631 running. To be fixed. */
3632 /* vg_assert(cv == NULL); */
3633 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003634 }
sewardjbf290b92002-05-01 02:28:01 +00003635
sewardj018f7622002-05-15 21:13:39 +00003636 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003637 Int
sewardj018f7622002-05-15 21:13:39 +00003638 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3639 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003640 if (i > 1 /* not the root thread */
3641 && stack_used
3642 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3643 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003644 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003645 "thread %d: stack used %d, available %d",
3646 i, stack_used, VG_PTHREAD_STACK_MIN );
3647 VG_(message)(Vg_UserMsg,
3648 "Terminating Valgrind. If thread(s) "
3649 "really need more stack, increase");
3650 VG_(message)(Vg_UserMsg,
3651 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3652 VG_(exit)(1);
3653 }
sewardjb48e5002002-05-13 00:16:03 +00003654
sewardj018f7622002-05-15 21:13:39 +00003655 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003656 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003657 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003658 } else {
3659 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003660 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003661 }
3662
sewardjbf290b92002-05-01 02:28:01 +00003663 }
sewardj6072c362002-04-19 14:40:57 +00003664 }
sewardj5f07b662002-04-23 16:52:51 +00003665
3666 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3667 if (!vg_thread_keys[i].inuse)
3668 vg_assert(vg_thread_keys[i].destructor == NULL);
3669 }
sewardj6072c362002-04-19 14:40:57 +00003670}
3671
3672
sewardje663cb92002-04-12 10:26:32 +00003673/*--------------------------------------------------------------------*/
3674/*--- end vg_scheduler.c ---*/
3675/*--------------------------------------------------------------------*/