blob: 4e6561b0864e4029b57e2d5b989dde335b7b7e20 [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/*--------------------------------------------------------------------*/
3/*--- A user-space pthreads implementation. vg_scheduler.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
njnc9539842002-10-02 13:26:35 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardje663cb92002-04-12 10:26:32 +00009
10 Copyright (C) 2000-2002 Julian Seward
11 jseward@acm.org
sewardje663cb92002-04-12 10:26:32 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardje663cb92002-04-12 10:26:32 +000029*/
30
31#include "vg_include.h"
njn25e49d8e72002-09-23 09:36:25 +000032#include "valgrind.h" /* for VG_USERREQ__RUNNING_ON_VALGRIND and
33 VG_USERREQ__DISCARD_TRANSLATIONS */
sewardje663cb92002-04-12 10:26:32 +000034
sewardjb60c1ad2002-05-29 20:23:26 +000035/* BORKAGE/ISSUES as of 29 May 02
sewardje663cb92002-04-12 10:26:32 +000036
sewardj77e466c2002-04-14 02:29:29 +000037- Currently, when a signal is run, just the ThreadStatus.status fields
38 are saved in the signal frame, along with the CPU state. Question:
39 should I also save and restore:
40 ThreadStatus.joiner
41 ThreadStatus.waited_on_mid
42 ThreadStatus.awaken_at
43 ThreadStatus.retval
44 Currently unsure, and so am not doing so.
sewardje663cb92002-04-12 10:26:32 +000045
sewardj77e466c2002-04-14 02:29:29 +000046- Signals interrupting read/write and nanosleep: SA_RESTART settings.
47 Read/write correctly return with EINTR when SA_RESTART isn't
48 specified and they are interrupted by a signal. nanosleep just
49 pretends signals don't exist -- should be fixed.
sewardje663cb92002-04-12 10:26:32 +000050
sewardj705d3cb2002-05-23 13:13:12 +000051- So, what's the deal with signals and mutexes? If a thread is
sewardj6072c362002-04-19 14:40:57 +000052 blocked on a mutex, or for a condition variable for that matter, can
53 signals still be delivered to it? This has serious consequences --
54 deadlocks, etc.
55
sewardj705d3cb2002-05-23 13:13:12 +000056- Signals still not really right. Each thread should have its
57 own pending-set, but there is just one process-wide pending set.
58
sewardjb60c1ad2002-05-29 20:23:26 +000059 TODO for valgrind-1.0:
60
sewardj055fbb82002-05-30 00:40:55 +000061- Update assertion checking in scheduler_sanity().
62
sewardjb60c1ad2002-05-29 20:23:26 +000063 TODO sometime:
64
sewardj645030e2002-06-06 01:27:39 +000065- poll() in the vg_libpthread.c -- should it handle the nanosleep
66 being interrupted by a signal? Ditto accept?
67
sewardjb60c1ad2002-05-29 20:23:26 +000068- Mutex scrubbing - clearup_after_thread_exit: look for threads
69 blocked on mutexes held by the exiting thread, and release them
70 appropriately. (??)
71
72- pthread_atfork
73
sewardje462e202002-04-13 04:09:07 +000074*/
sewardje663cb92002-04-12 10:26:32 +000075
76
77/* ---------------------------------------------------------------------
78 Types and globals for the scheduler.
79 ------------------------------------------------------------------ */
80
81/* type ThreadId is defined in vg_include.h. */
82
83/* struct ThreadState is defined in vg_include.h. */
84
sewardj018f7622002-05-15 21:13:39 +000085/* Globals. A statically allocated array of threads. NOTE: [0] is
86 never used, to simplify the simulation of initialisers for
sewardj6072c362002-04-19 14:40:57 +000087 LinuxThreads. */
sewardj018f7622002-05-15 21:13:39 +000088ThreadState VG_(threads)[VG_N_THREADS];
sewardje663cb92002-04-12 10:26:32 +000089
sewardj2cb00342002-06-28 01:46:26 +000090/* The process' fork-handler stack. */
91static Int vg_fhstack_used = 0;
92static ForkHandlerEntry vg_fhstack[VG_N_FORKHANDLERSTACK];
93
94
sewardj1e8cdc92002-04-18 11:37:52 +000095/* The tid of the thread currently in VG_(baseBlock). */
96static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
97
sewardjb52a1b02002-10-23 21:38:22 +000098/* The tid either currently in baseBlock, or was in baseBlock before
99 was saved it out; this is only updated when a new thread is loaded
100 into the baseBlock */
101static Int vg_tid_last_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000102
103/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
104jmp_buf VG_(scheduler_jmpbuf);
sewardj872051c2002-07-13 12:12:56 +0000105/* This says whether scheduler_jmpbuf is actually valid. Needed so
106 that our signal handler doesn't longjmp when the buffer isn't
107 actually valid. */
108Bool VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000109/* ... and if so, here's the signal which caused it to do so. */
110Int VG_(longjmpd_on_signal);
111
112
113/* Machinery to keep track of which threads are waiting on which
114 fds. */
115typedef
116 struct {
117 /* The thread which made the request. */
118 ThreadId tid;
119
120 /* The next two fields describe the request. */
121 /* File descriptor waited for. -1 means this slot is not in use */
122 Int fd;
123 /* The syscall number the fd is used in. */
124 Int syscall_no;
125
126 /* False => still waiting for select to tell us the fd is ready
127 to go. True => the fd is ready, but the results have not yet
128 been delivered back to the calling thread. Once the latter
129 happens, this entire record is marked as no longer in use, by
130 making the fd field be -1. */
131 Bool ready;
njn25e49d8e72002-09-23 09:36:25 +0000132
133 /* The result from SK_(pre_blocking_syscall)(); is passed to
134 * SK_(post_blocking_syscall)(). */
135 void* pre_result;
sewardje663cb92002-04-12 10:26:32 +0000136 }
137 VgWaitedOnFd;
138
139static VgWaitedOnFd vg_waiting_fds[VG_N_WAITING_FDS];
140
141
sewardj5f07b662002-04-23 16:52:51 +0000142/* Keeping track of keys. */
143typedef
144 struct {
145 /* Has this key been allocated ? */
146 Bool inuse;
147 /* If .inuse==True, records the address of the associated
148 destructor, or NULL if none. */
149 void (*destructor)(void*);
150 }
151 ThreadKeyState;
152
153/* And our array of thread keys. */
154static ThreadKeyState vg_thread_keys[VG_N_THREAD_KEYS];
155
156typedef UInt ThreadKey;
157
158
njn25e49d8e72002-09-23 09:36:25 +0000159UInt VG_(written_shadow_reg);
160
sewardje663cb92002-04-12 10:26:32 +0000161/* Forwards */
sewardj124ca2a2002-06-20 10:19:38 +0000162static void do_client_request ( ThreadId tid );
sewardj6072c362002-04-19 14:40:57 +0000163static void scheduler_sanity ( void );
sewardj124ca2a2002-06-20 10:19:38 +0000164static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid );
sewardjd140e442002-05-29 01:21:19 +0000165
sewardje663cb92002-04-12 10:26:32 +0000166/* ---------------------------------------------------------------------
167 Helper functions for the scheduler.
168 ------------------------------------------------------------------ */
169
sewardjb48e5002002-05-13 00:16:03 +0000170__inline__
171Bool VG_(is_valid_tid) ( ThreadId tid )
sewardj604ec3c2002-04-18 22:38:41 +0000172{
173 /* tid is unsigned, hence no < 0 test. */
sewardj6072c362002-04-19 14:40:57 +0000174 if (tid == 0) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000175 if (tid >= VG_N_THREADS) return False;
sewardj018f7622002-05-15 21:13:39 +0000176 if (VG_(threads)[tid].status == VgTs_Empty) return False;
177 return True;
178}
179
180
181__inline__
182Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
183{
184 /* tid is unsigned, hence no < 0 test. */
185 if (tid == 0) return False;
186 if (tid >= VG_N_THREADS) return False;
sewardj604ec3c2002-04-18 22:38:41 +0000187 return True;
188}
189
190
sewardj1e8cdc92002-04-18 11:37:52 +0000191/* For constructing error messages only: try and identify a thread
njn25e49d8e72002-09-23 09:36:25 +0000192 whose stack satisfies the predicate p, or return VG_INVALID_THREADID
193 if none do. A small complication is dealing with any currently
194 VG_(baseBlock)-resident thread.
sewardj1e8cdc92002-04-18 11:37:52 +0000195*/
njn25e49d8e72002-09-23 09:36:25 +0000196ThreadId VG_(any_matching_thread_stack)
197 ( Bool (*p) ( Addr stack_min, Addr stack_max ))
sewardj1e8cdc92002-04-18 11:37:52 +0000198{
199 ThreadId tid, tid_to_skip;
200
201 tid_to_skip = VG_INVALID_THREADID;
202
203 /* First check to see if there's a currently-loaded thread in
204 VG_(baseBlock). */
205 if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
206 tid = vg_tid_currently_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000207 if ( p ( VG_(baseBlock)[VGOFF_(m_esp)],
208 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000209 return tid;
210 else
211 tid_to_skip = tid;
212 }
213
sewardj6072c362002-04-19 14:40:57 +0000214 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000215 if (VG_(threads)[tid].status == VgTs_Empty) continue;
sewardj1e8cdc92002-04-18 11:37:52 +0000216 if (tid == tid_to_skip) continue;
njn25e49d8e72002-09-23 09:36:25 +0000217 if ( p ( VG_(threads)[tid].m_esp,
218 VG_(threads)[tid].stack_highest_word) )
sewardj1e8cdc92002-04-18 11:37:52 +0000219 return tid;
220 }
221 return VG_INVALID_THREADID;
222}
223
224
sewardj15a43e12002-04-17 19:35:12 +0000225/* Print the scheduler status. */
226void VG_(pp_sched_status) ( void )
sewardje663cb92002-04-12 10:26:32 +0000227{
228 Int i;
229 VG_(printf)("\nsched status:\n");
sewardj6072c362002-04-19 14:40:57 +0000230 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000231 if (VG_(threads)[i].status == VgTs_Empty) continue;
sewardj15a43e12002-04-17 19:35:12 +0000232 VG_(printf)("\nThread %d: status = ", i);
sewardj018f7622002-05-15 21:13:39 +0000233 switch (VG_(threads)[i].status) {
sewardj6072c362002-04-19 14:40:57 +0000234 case VgTs_Runnable: VG_(printf)("Runnable"); break;
235 case VgTs_WaitFD: VG_(printf)("WaitFD"); break;
sewardj20917d82002-05-28 01:36:45 +0000236 case VgTs_WaitJoinee: VG_(printf)("WaitJoinee(%d)",
237 VG_(threads)[i].joiner_jee_tid);
238 break;
239 case VgTs_WaitJoiner: VG_(printf)("WaitJoiner"); break;
sewardj6072c362002-04-19 14:40:57 +0000240 case VgTs_Sleeping: VG_(printf)("Sleeping"); break;
241 case VgTs_WaitMX: VG_(printf)("WaitMX"); break;
sewardj3b5d8862002-04-20 13:53:23 +0000242 case VgTs_WaitCV: VG_(printf)("WaitCV"); break;
sewardjb48e5002002-05-13 00:16:03 +0000243 case VgTs_WaitSIG: VG_(printf)("WaitSIG"); break;
sewardje663cb92002-04-12 10:26:32 +0000244 default: VG_(printf)("???"); break;
245 }
sewardj3b5d8862002-04-20 13:53:23 +0000246 VG_(printf)(", associated_mx = %p, associated_cv = %p\n",
sewardj018f7622002-05-15 21:13:39 +0000247 VG_(threads)[i].associated_mx,
248 VG_(threads)[i].associated_cv );
sewardj15a43e12002-04-17 19:35:12 +0000249 VG_(pp_ExeContext)(
njn25e49d8e72002-09-23 09:36:25 +0000250 VG_(get_ExeContext2)( VG_(threads)[i].m_eip, VG_(threads)[i].m_ebp,
251 VG_(threads)[i].m_esp,
252 VG_(threads)[i].stack_highest_word)
253 );
sewardje663cb92002-04-12 10:26:32 +0000254 }
255 VG_(printf)("\n");
256}
257
258static
njn25e49d8e72002-09-23 09:36:25 +0000259void add_waiting_fd ( ThreadId tid, Int fd, Int syscall_no, void* pre_res )
sewardje663cb92002-04-12 10:26:32 +0000260{
261 Int i;
262
263 vg_assert(fd != -1); /* avoid total chaos */
264
265 for (i = 0; i < VG_N_WAITING_FDS; i++)
266 if (vg_waiting_fds[i].fd == -1)
267 break;
268
269 if (i == VG_N_WAITING_FDS)
njne427a662002-10-02 11:08:25 +0000270 VG_(core_panic)("add_waiting_fd: VG_N_WAITING_FDS is too low");
sewardje663cb92002-04-12 10:26:32 +0000271 /*
272 VG_(printf)("add_waiting_fd: add (tid %d, fd %d) at slot %d\n",
273 tid, fd, i);
274 */
275 vg_waiting_fds[i].fd = fd;
276 vg_waiting_fds[i].tid = tid;
277 vg_waiting_fds[i].ready = False;
278 vg_waiting_fds[i].syscall_no = syscall_no;
njn25e49d8e72002-09-23 09:36:25 +0000279 vg_waiting_fds[i].pre_result = pre_res;
sewardje663cb92002-04-12 10:26:32 +0000280}
281
282
283
284static
285void print_sched_event ( ThreadId tid, Char* what )
286{
sewardj45b4b372002-04-16 22:50:32 +0000287 VG_(message)(Vg_DebugMsg, " SCHED[%d]: %s", tid, what );
sewardj8937c812002-04-12 20:12:20 +0000288}
289
290
291static
292void print_pthread_event ( ThreadId tid, Char* what )
293{
294 VG_(message)(Vg_DebugMsg, "PTHREAD[%d]: %s", tid, what );
sewardje663cb92002-04-12 10:26:32 +0000295}
296
297
298static
299Char* name_of_sched_event ( UInt event )
300{
301 switch (event) {
sewardje663cb92002-04-12 10:26:32 +0000302 case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
303 case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
304 case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
305 case VG_TRC_INNER_FASTMISS: return "FASTMISS";
306 case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
307 default: return "??UNKNOWN??";
308 }
309}
310
311
312/* Create a translation of the client basic block beginning at
313 orig_addr, and add it to the translation cache & translation table.
314 This probably doesn't really belong here, but, hey ...
315*/
sewardj1e8cdc92002-04-18 11:37:52 +0000316static
317void create_translation_for ( ThreadId tid, Addr orig_addr )
sewardje663cb92002-04-12 10:26:32 +0000318{
sewardj22854b92002-11-30 14:00:47 +0000319 Addr trans_addr;
320 Int orig_size, trans_size;
321 UShort jumps[VG_MAX_JUMPS];
322 Int i;
323
324 for(i = 0; i < VG_MAX_JUMPS; i++)
325 jumps[i] = (UShort)-1;
sewardj6c3769f2002-11-29 01:02:45 +0000326
327 /* Make a translation, into temporary storage. */
sewardj018f7622002-05-15 21:13:39 +0000328 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +0000329 orig_addr, &orig_size, &trans_addr, &trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000330
331 /* Copy data at trans_addr into the translation cache. */
sewardje663cb92002-04-12 10:26:32 +0000332 /* Since the .orig_size and .trans_size fields are
333 UShort, be paranoid. */
334 vg_assert(orig_size > 0 && orig_size < 65536);
335 vg_assert(trans_size > 0 && trans_size < 65536);
sewardj6c3769f2002-11-29 01:02:45 +0000336
sewardj22854b92002-11-30 14:00:47 +0000337 VG_(add_to_trans_tab)( orig_addr, orig_size, trans_addr, trans_size, jumps );
sewardj6c3769f2002-11-29 01:02:45 +0000338
sewardje663cb92002-04-12 10:26:32 +0000339 /* Free the intermediary -- was allocated by VG_(emit_code). */
njn25e49d8e72002-09-23 09:36:25 +0000340 VG_(arena_free)( VG_AR_JITTER, (void*)trans_addr );
sewardje663cb92002-04-12 10:26:32 +0000341}
342
343
344/* Allocate a completely empty ThreadState record. */
345static
346ThreadId vg_alloc_ThreadState ( void )
347{
348 Int i;
sewardj6072c362002-04-19 14:40:57 +0000349 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +0000350 if (VG_(threads)[i].status == VgTs_Empty)
sewardje663cb92002-04-12 10:26:32 +0000351 return i;
352 }
353 VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
354 VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
njne427a662002-10-02 11:08:25 +0000355 VG_(core_panic)("VG_N_THREADS is too low");
sewardje663cb92002-04-12 10:26:32 +0000356 /*NOTREACHED*/
357}
358
njn25e49d8e72002-09-23 09:36:25 +0000359ThreadState* VG_(get_ThreadState)( ThreadId tid )
360{
361 vg_assert(tid >= 0 && tid < VG_N_THREADS);
362 return & VG_(threads)[tid];
363}
sewardje663cb92002-04-12 10:26:32 +0000364
sewardj1e8cdc92002-04-18 11:37:52 +0000365ThreadState* VG_(get_current_thread_state) ( void )
366{
sewardj018f7622002-05-15 21:13:39 +0000367 vg_assert(VG_(is_valid_tid)(vg_tid_currently_in_baseBlock));
368 return & VG_(threads)[vg_tid_currently_in_baseBlock];
sewardj1e8cdc92002-04-18 11:37:52 +0000369}
370
371
372ThreadId VG_(get_current_tid) ( void )
373{
sewardjb52a1b02002-10-23 21:38:22 +0000374 if (!VG_(is_valid_tid)(vg_tid_currently_in_baseBlock))
375 return VG_INVALID_THREADID;
sewardj1e8cdc92002-04-18 11:37:52 +0000376 return vg_tid_currently_in_baseBlock;
377}
378
sewardjb52a1b02002-10-23 21:38:22 +0000379ThreadId VG_(get_current_or_recent_tid) ( void )
njn25e49d8e72002-09-23 09:36:25 +0000380{
sewardjb52a1b02002-10-23 21:38:22 +0000381 vg_assert(vg_tid_currently_in_baseBlock == vg_tid_last_in_baseBlock ||
382 vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
383 vg_assert(VG_(is_valid_tid)(vg_tid_last_in_baseBlock));
384
385 return vg_tid_last_in_baseBlock;
njn25e49d8e72002-09-23 09:36:25 +0000386}
387
sewardj7ab2aca2002-10-20 19:40:32 +0000388ThreadId VG_(get_tid_from_ThreadState) (ThreadState* tst)
389{
390 vg_assert(tst >= &VG_(threads)[1] && tst < &VG_(threads)[VG_N_THREADS]);
391 return tst->tid;
392}
393
sewardj1e8cdc92002-04-18 11:37:52 +0000394
sewardje663cb92002-04-12 10:26:32 +0000395/* Copy the saved state of a thread into VG_(baseBlock), ready for it
396 to be run. */
397__inline__
398void VG_(load_thread_state) ( ThreadId tid )
399{
400 Int i;
sewardj1e8cdc92002-04-18 11:37:52 +0000401 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
402
sewardj92a59562002-09-30 00:53:10 +0000403 VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt;
404 VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs;
405 VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss;
406 VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds;
407 VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es;
408 VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs;
409 VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs;
410
sewardj018f7622002-05-15 21:13:39 +0000411 VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax;
412 VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx;
413 VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx;
414 VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx;
415 VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi;
416 VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi;
417 VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp;
418 VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp;
419 VG_(baseBlock)[VGOFF_(m_eflags)] = VG_(threads)[tid].m_eflags;
420 VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip;
sewardje663cb92002-04-12 10:26:32 +0000421
422 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000423 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = VG_(threads)[tid].m_fpu[i];
sewardje663cb92002-04-12 10:26:32 +0000424
njn25e49d8e72002-09-23 09:36:25 +0000425 if (VG_(needs).shadow_regs) {
426 VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax;
427 VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx;
428 VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx;
429 VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx;
430 VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi;
431 VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi;
432 VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp;
433 VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp;
434 VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags;
435 } else {
436 /* Fields shouldn't be used -- check their values haven't changed. */
437 /* Nb: they are written to by some macros like SET_EDX, but they
438 * should just write VG_UNUSED_SHADOW_REG_VALUE. */
439 vg_assert(
440 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax &&
441 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx &&
442 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx &&
443 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx &&
444 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi &&
445 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi &&
446 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp &&
447 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp &&
448 VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags);
449 }
sewardj1e8cdc92002-04-18 11:37:52 +0000450
451 vg_tid_currently_in_baseBlock = tid;
sewardjb52a1b02002-10-23 21:38:22 +0000452 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +0000453}
454
455
456/* Copy the state of a thread from VG_(baseBlock), presumably after it
457 has been descheduled. For sanity-check purposes, fill the vacated
458 VG_(baseBlock) with garbage so as to make the system more likely to
459 fail quickly if we erroneously continue to poke around inside
460 VG_(baseBlock) without first doing a load_thread_state().
461*/
462__inline__
463void VG_(save_thread_state) ( ThreadId tid )
464{
465 Int i;
466 const UInt junk = 0xDEADBEEF;
467
sewardj1e8cdc92002-04-18 11:37:52 +0000468 vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
469
sewardj92a59562002-09-30 00:53:10 +0000470
471 /* We don't copy out the LDT entry, because it can never be changed
472 by the normal actions of the thread, only by the modify_ldt
473 syscall, in which case we will correctly be updating
474 VG_(threads)[tid].ldt. */
475 vg_assert((void*)VG_(threads)[tid].ldt
476 == (void*)VG_(baseBlock)[VGOFF_(ldt)]);
477
478 VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)];
479 VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)];
480 VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)];
481 VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)];
482 VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)];
483 VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)];
484
sewardj018f7622002-05-15 21:13:39 +0000485 VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
486 VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
487 VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
488 VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)];
489 VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)];
490 VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)];
491 VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
492 VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
493 VG_(threads)[tid].m_eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
494 VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
sewardje663cb92002-04-12 10:26:32 +0000495
496 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj018f7622002-05-15 21:13:39 +0000497 VG_(threads)[tid].m_fpu[i] = VG_(baseBlock)[VGOFF_(m_fpustate) + i];
sewardje663cb92002-04-12 10:26:32 +0000498
njn25e49d8e72002-09-23 09:36:25 +0000499 if (VG_(needs).shadow_regs) {
500 VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)];
501 VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)];
502 VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)];
503 VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)];
504 VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)];
505 VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)];
506 VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)];
507 VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)];
508 VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)];
509 } else {
510 /* Fill with recognisable junk */
511 VG_(threads)[tid].sh_eax =
512 VG_(threads)[tid].sh_ebx =
513 VG_(threads)[tid].sh_ecx =
514 VG_(threads)[tid].sh_edx =
515 VG_(threads)[tid].sh_esi =
516 VG_(threads)[tid].sh_edi =
517 VG_(threads)[tid].sh_ebp =
518 VG_(threads)[tid].sh_esp =
519 VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE;
520 }
sewardje663cb92002-04-12 10:26:32 +0000521
522 /* Fill it up with junk. */
sewardj92a59562002-09-30 00:53:10 +0000523 VG_(baseBlock)[VGOFF_(ldt)] = junk;
524 VG_(baseBlock)[VGOFF_(m_cs)] = junk;
525 VG_(baseBlock)[VGOFF_(m_ss)] = junk;
526 VG_(baseBlock)[VGOFF_(m_ds)] = junk;
527 VG_(baseBlock)[VGOFF_(m_es)] = junk;
528 VG_(baseBlock)[VGOFF_(m_fs)] = junk;
529 VG_(baseBlock)[VGOFF_(m_gs)] = junk;
530
sewardje663cb92002-04-12 10:26:32 +0000531 VG_(baseBlock)[VGOFF_(m_eax)] = junk;
532 VG_(baseBlock)[VGOFF_(m_ebx)] = junk;
533 VG_(baseBlock)[VGOFF_(m_ecx)] = junk;
534 VG_(baseBlock)[VGOFF_(m_edx)] = junk;
535 VG_(baseBlock)[VGOFF_(m_esi)] = junk;
536 VG_(baseBlock)[VGOFF_(m_edi)] = junk;
537 VG_(baseBlock)[VGOFF_(m_ebp)] = junk;
538 VG_(baseBlock)[VGOFF_(m_esp)] = junk;
539 VG_(baseBlock)[VGOFF_(m_eflags)] = junk;
540 VG_(baseBlock)[VGOFF_(m_eip)] = junk;
541
542 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
543 VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
sewardj1e8cdc92002-04-18 11:37:52 +0000544
545 vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
sewardje663cb92002-04-12 10:26:32 +0000546}
547
548
549/* Run the thread tid for a while, and return a VG_TRC_* value to the
550 scheduler indicating what happened. */
sewardj6072c362002-04-19 14:40:57 +0000551static
sewardje663cb92002-04-12 10:26:32 +0000552UInt run_thread_for_a_while ( ThreadId tid )
553{
sewardj7ccc5c22002-04-24 21:39:11 +0000554 volatile UInt trc = 0;
sewardjb48e5002002-05-13 00:16:03 +0000555 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000556 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000557 vg_assert(VG_(bbs_to_go) > 0);
sewardj872051c2002-07-13 12:12:56 +0000558 vg_assert(!VG_(scheduler_jmpbuf_valid));
sewardje663cb92002-04-12 10:26:32 +0000559
sewardj671ff542002-05-07 09:25:30 +0000560 VGP_PUSHCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000561 VG_(load_thread_state) ( tid );
562 if (__builtin_setjmp(VG_(scheduler_jmpbuf)) == 0) {
563 /* try this ... */
sewardj872051c2002-07-13 12:12:56 +0000564 VG_(scheduler_jmpbuf_valid) = True;
sewardje663cb92002-04-12 10:26:32 +0000565 trc = VG_(run_innerloop)();
sewardj872051c2002-07-13 12:12:56 +0000566 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000567 /* We get here if the client didn't take a fault. */
568 } else {
569 /* We get here if the client took a fault, which caused our
570 signal handler to longjmp. */
sewardj872051c2002-07-13 12:12:56 +0000571 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000572 vg_assert(trc == 0);
573 trc = VG_TRC_UNRESUMABLE_SIGNAL;
574 }
sewardj872051c2002-07-13 12:12:56 +0000575
576 vg_assert(!VG_(scheduler_jmpbuf_valid));
577
sewardje663cb92002-04-12 10:26:32 +0000578 VG_(save_thread_state) ( tid );
njn25e49d8e72002-09-23 09:36:25 +0000579 VGP_POPCC(VgpRun);
sewardje663cb92002-04-12 10:26:32 +0000580 return trc;
581}
582
583
sewardj20917d82002-05-28 01:36:45 +0000584static
585void mostly_clear_thread_record ( ThreadId tid )
586{
sewardj20917d82002-05-28 01:36:45 +0000587 vg_assert(tid >= 0 && tid < VG_N_THREADS);
sewardj92a59562002-09-30 00:53:10 +0000588 VG_(threads)[tid].ldt = NULL;
sewardj20917d82002-05-28 01:36:45 +0000589 VG_(threads)[tid].tid = tid;
590 VG_(threads)[tid].status = VgTs_Empty;
591 VG_(threads)[tid].associated_mx = NULL;
592 VG_(threads)[tid].associated_cv = NULL;
593 VG_(threads)[tid].awaken_at = 0;
594 VG_(threads)[tid].joinee_retval = NULL;
595 VG_(threads)[tid].joiner_thread_return = NULL;
596 VG_(threads)[tid].joiner_jee_tid = VG_INVALID_THREADID;
sewardj8ad94e12002-05-29 00:10:20 +0000597 VG_(threads)[tid].detached = False;
sewardj20917d82002-05-28 01:36:45 +0000598 VG_(threads)[tid].cancel_st = True; /* PTHREAD_CANCEL_ENABLE */
599 VG_(threads)[tid].cancel_ty = True; /* PTHREAD_CANCEL_DEFERRED */
600 VG_(threads)[tid].cancel_pend = NULL; /* not pending */
sewardj8ad94e12002-05-29 00:10:20 +0000601 VG_(threads)[tid].custack_used = 0;
sewardj9a2224b2002-06-19 10:17:40 +0000602 VG_(threads)[tid].n_signals_returned = 0;
sewardj20917d82002-05-28 01:36:45 +0000603 VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
604 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardj00a66b12002-10-12 16:42:35 +0000605 VG_(threads)[tid].specifics_ptr = NULL;
sewardj20917d82002-05-28 01:36:45 +0000606}
607
608
sewardje663cb92002-04-12 10:26:32 +0000609/* Initialise the scheduler. Create a single "main" thread ready to
sewardj6072c362002-04-19 14:40:57 +0000610 run, with special ThreadId of one. This is called at startup; the
sewardje663cb92002-04-12 10:26:32 +0000611 caller takes care to park the client's state is parked in
612 VG_(baseBlock).
613*/
614void VG_(scheduler_init) ( void )
615{
616 Int i;
617 Addr startup_esp;
618 ThreadId tid_main;
619
620 startup_esp = VG_(baseBlock)[VGOFF_(m_esp)];
sewardja1679dd2002-05-10 22:31:40 +0000621
622 if (VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_1)
daywalkera2562202002-07-15 19:39:51 +0000623 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_2)
njn25e49d8e72002-09-23 09:36:25 +0000624 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_3)
625 || VG_STACK_MATCHES_BASE(startup_esp, VG_STARTUP_STACK_BASE_4)) {
sewardja1679dd2002-05-10 22:31:40 +0000626 /* Jolly good! */
627 } else {
njn25e49d8e72002-09-23 09:36:25 +0000628 VG_(printf)(
629 "%%esp at startup = %p is not near %p, %p, %p or %p; aborting\n",
630 (void*)startup_esp,
631 (void*)VG_STARTUP_STACK_BASE_1,
632 (void*)VG_STARTUP_STACK_BASE_2,
633 (void*)VG_STARTUP_STACK_BASE_3,
634 (void*)VG_STARTUP_STACK_BASE_4
635 );
njne427a662002-10-02 11:08:25 +0000636 VG_(core_panic)("unexpected %esp at startup");
sewardje663cb92002-04-12 10:26:32 +0000637 }
638
sewardj6072c362002-04-19 14:40:57 +0000639 for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
sewardj20917d82002-05-28 01:36:45 +0000640 mostly_clear_thread_record(i);
641 VG_(threads)[i].stack_size = 0;
642 VG_(threads)[i].stack_base = (Addr)NULL;
643 VG_(threads)[i].stack_highest_word = (Addr)NULL;
sewardje663cb92002-04-12 10:26:32 +0000644 }
645
646 for (i = 0; i < VG_N_WAITING_FDS; i++)
647 vg_waiting_fds[i].fd = -1; /* not in use */
648
sewardj5f07b662002-04-23 16:52:51 +0000649 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
650 vg_thread_keys[i].inuse = False;
651 vg_thread_keys[i].destructor = NULL;
652 }
653
sewardj2cb00342002-06-28 01:46:26 +0000654 vg_fhstack_used = 0;
655
sewardje663cb92002-04-12 10:26:32 +0000656 /* Assert this is thread zero, which has certain magic
657 properties. */
658 tid_main = vg_alloc_ThreadState();
sewardj6072c362002-04-19 14:40:57 +0000659 vg_assert(tid_main == 1);
sewardj20917d82002-05-28 01:36:45 +0000660 VG_(threads)[tid_main].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +0000661
662 /* Copy VG_(baseBlock) state to tid_main's slot. */
sewardj1e8cdc92002-04-18 11:37:52 +0000663 vg_tid_currently_in_baseBlock = tid_main;
sewardjb52a1b02002-10-23 21:38:22 +0000664 vg_tid_last_in_baseBlock = tid_main;
sewardje663cb92002-04-12 10:26:32 +0000665 VG_(save_thread_state) ( tid_main );
sewardj1e8cdc92002-04-18 11:37:52 +0000666
sewardj018f7622002-05-15 21:13:39 +0000667 VG_(threads)[tid_main].stack_highest_word
668 = VG_(threads)[tid_main].m_esp /* -4 ??? */;
sewardjbf290b92002-05-01 02:28:01 +0000669
sewardj1e8cdc92002-04-18 11:37:52 +0000670 /* So now ... */
671 vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
sewardj872051c2002-07-13 12:12:56 +0000672
673 /* Not running client code right now. */
674 VG_(scheduler_jmpbuf_valid) = False;
sewardje663cb92002-04-12 10:26:32 +0000675}
676
677
678/* What if fd isn't a valid fd? */
679static
680void set_fd_nonblocking ( Int fd )
681{
682 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
683 vg_assert(!VG_(is_kerror)(res));
684 res |= VKI_O_NONBLOCK;
685 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
686 vg_assert(!VG_(is_kerror)(res));
687}
688
689static
690void set_fd_blocking ( Int fd )
691{
692 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
693 vg_assert(!VG_(is_kerror)(res));
694 res &= ~VKI_O_NONBLOCK;
695 res = VG_(fcntl)( fd, VKI_F_SETFL, res );
696 vg_assert(!VG_(is_kerror)(res));
697}
698
699static
700Bool fd_is_blockful ( Int fd )
701{
702 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
703 vg_assert(!VG_(is_kerror)(res));
704 return (res & VKI_O_NONBLOCK) ? False : True;
705}
706
sewardj3947e622002-05-23 16:52:11 +0000707static
708Bool fd_is_valid ( Int fd )
709{
710 Int res = VG_(fcntl)( fd, VKI_F_GETFL, 0 );
711 return VG_(is_kerror)(res) ? False : True;
712}
713
sewardje663cb92002-04-12 10:26:32 +0000714
715
sewardj6072c362002-04-19 14:40:57 +0000716/* vthread tid is returning from a signal handler; modify its
717 stack/regs accordingly. */
sewardj1ffa8da2002-04-26 22:47:57 +0000718
719/* [Helper fn for handle_signal_return] tid, assumed to be in WaitFD
720 for read or write, has been interrupted by a signal. Find and
721 clear the relevant vg_waiting_fd[] entry. Most of the code in this
722 procedure is total paranoia, if you look closely. */
723static
724void cleanup_waiting_fd_table ( ThreadId tid )
725{
726 Int i, waiters;
727
sewardjb48e5002002-05-13 00:16:03 +0000728 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000729 vg_assert(VG_(threads)[tid].status == VgTs_WaitFD);
730 vg_assert(VG_(threads)[tid].m_eax == __NR_read
731 || VG_(threads)[tid].m_eax == __NR_write);
sewardj1ffa8da2002-04-26 22:47:57 +0000732
733 /* Excessively paranoidly ... find the fd this op was waiting
734 for, and mark it as not being waited on. */
735 waiters = 0;
736 for (i = 0; i < VG_N_WAITING_FDS; i++) {
737 if (vg_waiting_fds[i].tid == tid) {
738 waiters++;
sewardj018f7622002-05-15 21:13:39 +0000739 vg_assert(vg_waiting_fds[i].syscall_no == VG_(threads)[tid].m_eax);
sewardj1ffa8da2002-04-26 22:47:57 +0000740 }
741 }
742 vg_assert(waiters == 1);
743 for (i = 0; i < VG_N_WAITING_FDS; i++)
744 if (vg_waiting_fds[i].tid == tid)
745 break;
746 vg_assert(i < VG_N_WAITING_FDS);
747 vg_assert(vg_waiting_fds[i].fd != -1);
748 vg_waiting_fds[i].fd = -1; /* not in use */
749}
750
751
sewardj6072c362002-04-19 14:40:57 +0000752static
753void handle_signal_return ( ThreadId tid )
754{
755 Char msg_buf[100];
756 Bool restart_blocked_syscalls;
sewardj645030e2002-06-06 01:27:39 +0000757 struct vki_timespec * rem;
sewardj6072c362002-04-19 14:40:57 +0000758
sewardjb48e5002002-05-13 00:16:03 +0000759 vg_assert(VG_(is_valid_tid)(tid));
sewardj6072c362002-04-19 14:40:57 +0000760
sewardj9a2224b2002-06-19 10:17:40 +0000761 /* Increment signal-returned counter. Used only to implement
762 pause(). */
763 VG_(threads)[tid].n_signals_returned++;
764
sewardj6072c362002-04-19 14:40:57 +0000765 restart_blocked_syscalls = VG_(signal_returns)(tid);
766
767 if (restart_blocked_syscalls)
768 /* Easy; we don't have to do anything. */
769 return;
770
sewardj018f7622002-05-15 21:13:39 +0000771 if (VG_(threads)[tid].status == VgTs_WaitFD
772 && (VG_(threads)[tid].m_eax == __NR_read
773 || VG_(threads)[tid].m_eax == __NR_write)) {
sewardj6072c362002-04-19 14:40:57 +0000774 /* read() or write() interrupted. Force a return with EINTR. */
sewardj1ffa8da2002-04-26 22:47:57 +0000775 cleanup_waiting_fd_table(tid);
sewardj018f7622002-05-15 21:13:39 +0000776 VG_(threads)[tid].m_eax = -VKI_EINTR;
777 VG_(threads)[tid].status = VgTs_Runnable;
sewardj1ffa8da2002-04-26 22:47:57 +0000778
sewardj6072c362002-04-19 14:40:57 +0000779 if (VG_(clo_trace_sched)) {
780 VG_(sprintf)(msg_buf,
781 "read() / write() interrupted by signal; return EINTR" );
782 print_sched_event(tid, msg_buf);
783 }
784 return;
785 }
786
sewardj645030e2002-06-06 01:27:39 +0000787 if (VG_(threads)[tid].status == VgTs_Sleeping
sewardj018f7622002-05-15 21:13:39 +0000788 && VG_(threads)[tid].m_eax == __NR_nanosleep) {
sewardj6072c362002-04-19 14:40:57 +0000789 /* We interrupted a nanosleep(). The right thing to do is to
sewardj645030e2002-06-06 01:27:39 +0000790 write the unused time to nanosleep's second param, but that's
791 too much effort ... we just say that 1 nanosecond was not
792 used, and return EINTR. */
793 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
794 if (rem != NULL) {
795 rem->tv_sec = 0;
796 rem->tv_nsec = 1;
797 }
798 SET_EAX(tid, -VKI_EINTR);
799 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000800 return;
801 }
802
sewardj018f7622002-05-15 21:13:39 +0000803 if (VG_(threads)[tid].status == VgTs_WaitFD) {
njne427a662002-10-02 11:08:25 +0000804 VG_(core_panic)("handle_signal_return: unknown interrupted syscall");
sewardj1ffa8da2002-04-26 22:47:57 +0000805 }
806
sewardj6072c362002-04-19 14:40:57 +0000807 /* All other cases? Just return. */
808}
809
810
sewardje663cb92002-04-12 10:26:32 +0000811static
812void sched_do_syscall ( ThreadId tid )
813{
njn25e49d8e72002-09-23 09:36:25 +0000814 UInt saved_eax;
815 UInt res, syscall_no;
816 UInt fd;
817 void* pre_res;
818 Bool orig_fd_blockness;
819 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +0000820
sewardjb48e5002002-05-13 00:16:03 +0000821 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +0000822 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000823
sewardj018f7622002-05-15 21:13:39 +0000824 syscall_no = VG_(threads)[tid].m_eax; /* syscall number */
sewardje663cb92002-04-12 10:26:32 +0000825
826 if (syscall_no == __NR_nanosleep) {
sewardj5f07b662002-04-23 16:52:51 +0000827 UInt t_now, t_awaken;
sewardje663cb92002-04-12 10:26:32 +0000828 struct vki_timespec* req;
sewardj018f7622002-05-15 21:13:39 +0000829 req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */
sewardj5f07b662002-04-23 16:52:51 +0000830 t_now = VG_(read_millisecond_timer)();
sewardje663cb92002-04-12 10:26:32 +0000831 t_awaken
832 = t_now
sewardj5f07b662002-04-23 16:52:51 +0000833 + (UInt)1000ULL * (UInt)(req->tv_sec)
834 + (UInt)(req->tv_nsec) / 1000000;
sewardj018f7622002-05-15 21:13:39 +0000835 VG_(threads)[tid].status = VgTs_Sleeping;
836 VG_(threads)[tid].awaken_at = t_awaken;
sewardj8937c812002-04-12 20:12:20 +0000837 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000838 VG_(sprintf)(msg_buf, "at %d: nanosleep for %d",
sewardje663cb92002-04-12 10:26:32 +0000839 t_now, t_awaken-t_now);
840 print_sched_event(tid, msg_buf);
841 }
842 /* Force the scheduler to run something else for a while. */
843 return;
844 }
845
sewardjaec22c02002-04-29 01:58:08 +0000846 if (syscall_no != __NR_read && syscall_no != __NR_write) {
sewardje663cb92002-04-12 10:26:32 +0000847 /* We think it's non-blocking. Just do it in the normal way. */
848 VG_(perform_assumed_nonblocking_syscall)(tid);
849 /* The thread is still runnable. */
850 return;
851 }
852
sewardje663cb92002-04-12 10:26:32 +0000853 /* Set the fd to nonblocking, and do the syscall, which will return
854 immediately, in order to lodge a request with the Linux kernel.
855 We later poll for I/O completion using select(). */
856
sewardj018f7622002-05-15 21:13:39 +0000857 fd = VG_(threads)[tid].m_ebx /* arg1 */;
sewardj3947e622002-05-23 16:52:11 +0000858
859 /* Deal with error case immediately. */
860 if (!fd_is_valid(fd)) {
njn25e49d8e72002-09-23 09:36:25 +0000861 if (VG_(needs).core_errors)
862 VG_(message)(Vg_UserMsg,
863 "Warning: invalid file descriptor %d in syscall %s",
864 fd, syscall_no == __NR_read ? "read()" : "write()" );
865 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardj3947e622002-05-23 16:52:11 +0000866 KERNEL_DO_SYSCALL(tid, res);
njn25e49d8e72002-09-23 09:36:25 +0000867 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardj3947e622002-05-23 16:52:11 +0000868 /* We're still runnable. */
869 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
870 return;
871 }
872
873 /* From here onwards we know that fd is valid. */
874
sewardje663cb92002-04-12 10:26:32 +0000875 orig_fd_blockness = fd_is_blockful(fd);
876 set_fd_nonblocking(fd);
877 vg_assert(!fd_is_blockful(fd));
njn25e49d8e72002-09-23 09:36:25 +0000878 pre_res = VG_(pre_known_blocking_syscall)(tid, syscall_no);
sewardje663cb92002-04-12 10:26:32 +0000879
880 /* This trashes the thread's %eax; we have to preserve it. */
sewardj018f7622002-05-15 21:13:39 +0000881 saved_eax = VG_(threads)[tid].m_eax;
sewardje663cb92002-04-12 10:26:32 +0000882 KERNEL_DO_SYSCALL(tid,res);
883
884 /* Restore original blockfulness of the fd. */
885 if (orig_fd_blockness)
886 set_fd_blocking(fd);
887 else
888 set_fd_nonblocking(fd);
889
sewardjaec22c02002-04-29 01:58:08 +0000890 if (res != -VKI_EWOULDBLOCK || !orig_fd_blockness) {
891 /* Finish off in the normal way. Don't restore %EAX, since that
892 now (correctly) holds the result of the call. We get here if either:
893 1. The call didn't block, or
894 2. The fd was already in nonblocking mode before we started to
895 mess with it. In this case, we're not expecting to handle
896 the I/O completion -- the client is. So don't file a
897 completion-wait entry.
898 */
njn25e49d8e72002-09-23 09:36:25 +0000899 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +0000900 /* We're still runnable. */
sewardj018f7622002-05-15 21:13:39 +0000901 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +0000902
903 } else {
904
sewardjaec22c02002-04-29 01:58:08 +0000905 vg_assert(res == -VKI_EWOULDBLOCK && orig_fd_blockness);
906
sewardje663cb92002-04-12 10:26:32 +0000907 /* It would have blocked. First, restore %EAX to what it was
908 before our speculative call. */
sewardj018f7622002-05-15 21:13:39 +0000909 VG_(threads)[tid].m_eax = saved_eax;
sewardje663cb92002-04-12 10:26:32 +0000910 /* Put this fd in a table of fds on which we are waiting for
911 completion. The arguments for select() later are constructed
912 from this table. */
njn25e49d8e72002-09-23 09:36:25 +0000913 add_waiting_fd(tid, fd, saved_eax /* which holds the syscall # */,
914 pre_res);
sewardje663cb92002-04-12 10:26:32 +0000915 /* Deschedule thread until an I/O completion happens. */
sewardj018f7622002-05-15 21:13:39 +0000916 VG_(threads)[tid].status = VgTs_WaitFD;
sewardj8937c812002-04-12 20:12:20 +0000917 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +0000918 VG_(sprintf)(msg_buf,"block until I/O ready on fd %d", fd);
919 print_sched_event(tid, msg_buf);
920 }
921
922 }
923}
924
925
926/* Find out which of the fds in vg_waiting_fds are now ready to go, by
927 making enquiries with select(), and mark them as ready. We have to
928 wait for the requesting threads to fall into the the WaitFD state
929 before we can actually finally deliver the results, so this
930 procedure doesn't do that; complete_blocked_syscalls() does it.
931
932 It might seem odd that a thread which has done a blocking syscall
933 is not in WaitFD state; the way this can happen is if it initially
934 becomes WaitFD, but then a signal is delivered to it, so it becomes
935 Runnable for a while. In this case we have to wait for the
936 sighandler to return, whereupon the WaitFD state is resumed, and
937 only at that point can the I/O result be delivered to it. However,
938 this point may be long after the fd is actually ready.
939
940 So, poll_for_ready_fds() merely detects fds which are ready.
941 complete_blocked_syscalls() does the second half of the trick,
942 possibly much later: it delivers the results from ready fds to
943 threads in WaitFD state.
944*/
sewardj9a199dc2002-04-14 13:01:38 +0000945static
sewardje663cb92002-04-12 10:26:32 +0000946void poll_for_ready_fds ( void )
947{
948 vki_ksigset_t saved_procmask;
949 vki_fd_set readfds;
950 vki_fd_set writefds;
951 vki_fd_set exceptfds;
952 struct vki_timeval timeout;
953 Int fd, fd_max, i, n_ready, syscall_no, n_ok;
954 ThreadId tid;
955 Bool rd_ok, wr_ok, ex_ok;
956 Char msg_buf[100];
957
sewardje462e202002-04-13 04:09:07 +0000958 struct vki_timespec* rem;
sewardj5f07b662002-04-23 16:52:51 +0000959 UInt t_now;
sewardje462e202002-04-13 04:09:07 +0000960
sewardje663cb92002-04-12 10:26:32 +0000961 /* Awaken any sleeping threads whose sleep has expired. */
sewardj6072c362002-04-19 14:40:57 +0000962 for (tid = 1; tid < VG_N_THREADS; tid++)
sewardj018f7622002-05-15 21:13:39 +0000963 if (VG_(threads)[tid].status == VgTs_Sleeping)
sewardj853f55d2002-04-26 00:27:53 +0000964 break;
sewardj6072c362002-04-19 14:40:57 +0000965
sewardj5f07b662002-04-23 16:52:51 +0000966 /* Avoid pointless calls to VG_(read_millisecond_timer). */
sewardj6072c362002-04-19 14:40:57 +0000967 if (tid < VG_N_THREADS) {
sewardj5f07b662002-04-23 16:52:51 +0000968 t_now = VG_(read_millisecond_timer)();
sewardj6072c362002-04-19 14:40:57 +0000969 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +0000970 if (VG_(threads)[tid].status != VgTs_Sleeping)
sewardj6072c362002-04-19 14:40:57 +0000971 continue;
sewardj018f7622002-05-15 21:13:39 +0000972 if (t_now >= VG_(threads)[tid].awaken_at) {
sewardj6072c362002-04-19 14:40:57 +0000973 /* Resume this thread. Set to zero the remaining-time
974 (second) arg of nanosleep, since it's used up all its
975 time. */
sewardj018f7622002-05-15 21:13:39 +0000976 vg_assert(VG_(threads)[tid].m_eax == __NR_nanosleep);
977 rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */
sewardj6072c362002-04-19 14:40:57 +0000978 if (rem != NULL) {
979 rem->tv_sec = 0;
980 rem->tv_nsec = 0;
981 }
982 /* Make the syscall return 0 (success). */
sewardj018f7622002-05-15 21:13:39 +0000983 VG_(threads)[tid].m_eax = 0;
sewardj6072c362002-04-19 14:40:57 +0000984 /* Reschedule this thread. */
sewardj018f7622002-05-15 21:13:39 +0000985 VG_(threads)[tid].status = VgTs_Runnable;
sewardj6072c362002-04-19 14:40:57 +0000986 if (VG_(clo_trace_sched)) {
sewardj5f07b662002-04-23 16:52:51 +0000987 VG_(sprintf)(msg_buf, "at %d: nanosleep done",
sewardj6072c362002-04-19 14:40:57 +0000988 t_now);
989 print_sched_event(tid, msg_buf);
990 }
sewardje663cb92002-04-12 10:26:32 +0000991 }
992 }
993 }
sewardje663cb92002-04-12 10:26:32 +0000994
sewardje462e202002-04-13 04:09:07 +0000995 /* And look for threads waiting on file descriptors which are now
996 ready for I/O.*/
sewardje663cb92002-04-12 10:26:32 +0000997 timeout.tv_sec = 0;
998 timeout.tv_usec = 0;
999
1000 VKI_FD_ZERO(&readfds);
1001 VKI_FD_ZERO(&writefds);
1002 VKI_FD_ZERO(&exceptfds);
1003 fd_max = -1;
1004 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1005 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1006 continue;
1007 if (vg_waiting_fds[i].ready /* already ready? */)
1008 continue;
1009 fd = vg_waiting_fds[i].fd;
1010 /* VG_(printf)("adding QUERY for fd %d\n", fd); */
sewardje462e202002-04-13 04:09:07 +00001011 vg_assert(fd >= 0);
sewardje663cb92002-04-12 10:26:32 +00001012 if (fd > fd_max)
1013 fd_max = fd;
1014 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001015 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001016 syscall_no = vg_waiting_fds[i].syscall_no;
1017 switch (syscall_no) {
sewardj3984b852002-05-12 03:00:17 +00001018 case __NR_read:
1019 /* In order to catch timeout events on fds which are
1020 readable and which have been ioctl(TCSETA)'d with a
1021 VTIMEout, we appear to need to ask if the fd is
1022 writable, for some reason. Ask me not why. Since this
1023 is strange and potentially troublesome we only do it if
1024 the user asks specially. */
sewardj8d365b52002-05-12 10:52:16 +00001025 if (VG_(strstr)(VG_(clo_weird_hacks), "ioctl-VTIME") != NULL)
sewardj3984b852002-05-12 03:00:17 +00001026 VKI_FD_SET(fd, &writefds);
sewardje663cb92002-04-12 10:26:32 +00001027 VKI_FD_SET(fd, &readfds); break;
1028 case __NR_write:
1029 VKI_FD_SET(fd, &writefds); break;
1030 default:
njne427a662002-10-02 11:08:25 +00001031 VG_(core_panic)("poll_for_ready_fds: unexpected syscall");
sewardje663cb92002-04-12 10:26:32 +00001032 /*NOTREACHED*/
1033 break;
1034 }
1035 }
1036
sewardje462e202002-04-13 04:09:07 +00001037 /* Short cut: if no fds are waiting, give up now. */
1038 if (fd_max == -1)
1039 return;
1040
sewardje663cb92002-04-12 10:26:32 +00001041 /* BLOCK ALL SIGNALS. We don't want the complication of select()
1042 getting interrupted. */
1043 VG_(block_all_host_signals)( &saved_procmask );
1044
1045 n_ready = VG_(select)
1046 ( fd_max+1, &readfds, &writefds, &exceptfds, &timeout);
1047 if (VG_(is_kerror)(n_ready)) {
1048 VG_(printf)("poll_for_ready_fds: select returned %d\n", n_ready);
njne427a662002-10-02 11:08:25 +00001049 VG_(core_panic)("poll_for_ready_fds: select failed?!");
sewardje663cb92002-04-12 10:26:32 +00001050 /*NOTREACHED*/
1051 }
1052
1053 /* UNBLOCK ALL SIGNALS */
sewardj018f7622002-05-15 21:13:39 +00001054 VG_(restore_all_host_signals)( &saved_procmask );
sewardje663cb92002-04-12 10:26:32 +00001055
1056 /* VG_(printf)("poll_for_io_completions: %d fs ready\n", n_ready); */
1057
1058 if (n_ready == 0)
1059 return;
1060
1061 /* Inspect all the fds we know about, and handle any completions that
1062 have happened. */
1063 /*
1064 VG_(printf)("\n\n");
1065 for (fd = 0; fd < 100; fd++)
1066 if (VKI_FD_ISSET(fd, &writefds) || VKI_FD_ISSET(fd, &readfds)) {
1067 VG_(printf)("X"); } else { VG_(printf)("."); };
1068 VG_(printf)("\n\nfd_max = %d\n", fd_max);
1069 */
1070
1071 for (fd = 0; fd <= fd_max; fd++) {
1072 rd_ok = VKI_FD_ISSET(fd, &readfds);
1073 wr_ok = VKI_FD_ISSET(fd, &writefds);
1074 ex_ok = VKI_FD_ISSET(fd, &exceptfds);
1075
1076 n_ok = (rd_ok ? 1 : 0) + (wr_ok ? 1 : 0) + (ex_ok ? 1 : 0);
1077 if (n_ok == 0)
1078 continue;
1079 if (n_ok > 1) {
1080 VG_(printf)("offending fd = %d\n", fd);
njne427a662002-10-02 11:08:25 +00001081 VG_(core_panic)("poll_for_ready_fds: multiple events on fd");
sewardje663cb92002-04-12 10:26:32 +00001082 }
sewardjbc7d8782002-06-30 12:44:54 +00001083
sewardje663cb92002-04-12 10:26:32 +00001084 /* An I/O event completed for fd. Find the thread which
1085 requested this. */
1086 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1087 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1088 continue;
1089 if (vg_waiting_fds[i].fd == fd)
1090 break;
1091 }
1092
1093 /* And a bit more paranoia ... */
1094 vg_assert(i >= 0 && i < VG_N_WAITING_FDS);
1095
1096 /* Mark the fd as ready. */
1097 vg_assert(! vg_waiting_fds[i].ready);
1098 vg_waiting_fds[i].ready = True;
1099 }
1100}
1101
1102
1103/* See comment attached to poll_for_ready_fds() for explaination. */
sewardj9a199dc2002-04-14 13:01:38 +00001104static
sewardje663cb92002-04-12 10:26:32 +00001105void complete_blocked_syscalls ( void )
1106{
1107 Int fd, i, res, syscall_no;
njn25e49d8e72002-09-23 09:36:25 +00001108 void* pre_res;
sewardje663cb92002-04-12 10:26:32 +00001109 ThreadId tid;
1110 Char msg_buf[100];
1111
1112 /* Inspect all the outstanding fds we know about. */
1113
1114 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1115 if (vg_waiting_fds[i].fd == -1 /* not in use */)
1116 continue;
1117 if (! vg_waiting_fds[i].ready)
1118 continue;
1119
1120 fd = vg_waiting_fds[i].fd;
1121 tid = vg_waiting_fds[i].tid;
sewardjb48e5002002-05-13 00:16:03 +00001122 vg_assert(VG_(is_valid_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00001123
1124 /* The thread actually has to be waiting for the I/O event it
1125 requested before we can deliver the result! */
sewardj018f7622002-05-15 21:13:39 +00001126 if (VG_(threads)[tid].status != VgTs_WaitFD)
sewardje663cb92002-04-12 10:26:32 +00001127 continue;
1128
1129 /* Ok, actually do it! We can safely use %EAX as the syscall
1130 number, because the speculative call made by
1131 sched_do_syscall() doesn't change %EAX in the case where the
1132 call would have blocked. */
sewardje663cb92002-04-12 10:26:32 +00001133 syscall_no = vg_waiting_fds[i].syscall_no;
sewardj018f7622002-05-15 21:13:39 +00001134 vg_assert(syscall_no == VG_(threads)[tid].m_eax);
sewardjbc7d8782002-06-30 12:44:54 +00001135
njn25e49d8e72002-09-23 09:36:25 +00001136 pre_res = vg_waiting_fds[i].pre_result;
1137
sewardjbc7d8782002-06-30 12:44:54 +00001138 /* In a rare case pertaining to writing into a pipe, write()
1139 will block when asked to write > 4096 bytes even though the
1140 kernel claims, when asked via select(), that blocking will
1141 not occur for a write on that fd. This can cause deadlocks.
1142 An easy answer is to limit the size of the write to 4096
1143 anyway and hope that the client program's logic can handle
1144 the short write. That shoulds dubious to me, so we don't do
1145 it by default. */
1146 if (syscall_no == __NR_write
1147 && VG_(threads)[tid].m_edx /* arg3, count */ > 4096
1148 && VG_(strstr)(VG_(clo_weird_hacks), "truncate-writes") != NULL) {
1149 /* VG_(printf)("truncate write from %d to 4096\n",
1150 VG_(threads)[tid].m_edx ); */
1151 VG_(threads)[tid].m_edx = 4096;
1152 }
1153
sewardje663cb92002-04-12 10:26:32 +00001154 KERNEL_DO_SYSCALL(tid,res);
njn25e49d8e72002-09-23 09:36:25 +00001155 VG_(post_known_blocking_syscall)(tid, syscall_no, pre_res, res);
sewardje663cb92002-04-12 10:26:32 +00001156
1157 /* Reschedule. */
sewardj018f7622002-05-15 21:13:39 +00001158 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00001159 /* Mark slot as no longer in use. */
1160 vg_waiting_fds[i].fd = -1;
1161 /* pp_sched_status(); */
sewardj8937c812002-04-12 20:12:20 +00001162 if (VG_(clo_trace_sched)) {
sewardje663cb92002-04-12 10:26:32 +00001163 VG_(sprintf)(msg_buf,"resume due to I/O completion on fd %d", fd);
1164 print_sched_event(tid, msg_buf);
1165 }
1166 }
1167}
1168
1169
1170static
sewardj5f07b662002-04-23 16:52:51 +00001171void check_for_pthread_cond_timedwait ( void )
1172{
sewardj51c0aaf2002-04-25 01:32:10 +00001173 Int i, now;
sewardj5f07b662002-04-23 16:52:51 +00001174 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00001175 if (VG_(threads)[i].status != VgTs_WaitCV)
sewardj5f07b662002-04-23 16:52:51 +00001176 continue;
sewardj018f7622002-05-15 21:13:39 +00001177 if (VG_(threads)[i].awaken_at == 0xFFFFFFFF /* no timeout */)
sewardj5f07b662002-04-23 16:52:51 +00001178 continue;
sewardj51c0aaf2002-04-25 01:32:10 +00001179 now = VG_(read_millisecond_timer)();
sewardj018f7622002-05-15 21:13:39 +00001180 if (now >= VG_(threads)[i].awaken_at) {
sewardj5f07b662002-04-23 16:52:51 +00001181 do_pthread_cond_timedwait_TIMEOUT(i);
sewardj51c0aaf2002-04-25 01:32:10 +00001182 }
sewardj5f07b662002-04-23 16:52:51 +00001183 }
1184}
1185
1186
1187static
sewardje663cb92002-04-12 10:26:32 +00001188void nanosleep_for_a_while ( void )
1189{
1190 Int res;
1191 struct vki_timespec req;
1192 struct vki_timespec rem;
1193 req.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001194 req.tv_nsec = 10 * 1000 * 1000;
sewardje663cb92002-04-12 10:26:32 +00001195 res = VG_(nanosleep)( &req, &rem );
sewardj5f07b662002-04-23 16:52:51 +00001196 vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
sewardje663cb92002-04-12 10:26:32 +00001197}
1198
1199
1200/* ---------------------------------------------------------------------
1201 The scheduler proper.
1202 ------------------------------------------------------------------ */
1203
1204/* Run user-space threads until either
1205 * Deadlock occurs
1206 * One thread asks to shutdown Valgrind
1207 * The specified number of basic blocks has gone by.
1208*/
1209VgSchedReturnCode VG_(scheduler) ( void )
1210{
1211 ThreadId tid, tid_next;
1212 UInt trc;
1213 UInt dispatch_ctr_SAVED;
sewardj124ca2a2002-06-20 10:19:38 +00001214 Int done_this_time, n_in_bounded_wait;
sewardje663cb92002-04-12 10:26:32 +00001215 Addr trans_addr;
sewardj14e03422002-04-24 19:51:31 +00001216 Bool sigs_delivered;
sewardje663cb92002-04-12 10:26:32 +00001217
sewardje663cb92002-04-12 10:26:32 +00001218 /* Start with the root thread. tid in general indicates the
1219 currently runnable/just-finished-running thread. */
sewardj7e87e382002-05-03 19:09:05 +00001220 VG_(last_run_tid) = tid = 1;
sewardje663cb92002-04-12 10:26:32 +00001221
1222 /* This is the top level scheduler loop. It falls into three
1223 phases. */
1224 while (True) {
1225
sewardj6072c362002-04-19 14:40:57 +00001226 /* ======================= Phase 0 of 3 =======================
1227 Be paranoid. Always a good idea. */
sewardjd7fd4d22002-04-24 01:57:27 +00001228 stage1:
sewardj6072c362002-04-19 14:40:57 +00001229 scheduler_sanity();
sewardj0c3b53f2002-05-01 01:58:35 +00001230 VG_(do_sanity_checks)( False );
sewardj6072c362002-04-19 14:40:57 +00001231
sewardje663cb92002-04-12 10:26:32 +00001232 /* ======================= Phase 1 of 3 =======================
1233 Handle I/O completions and signals. This may change the
1234 status of various threads. Then select a new thread to run,
1235 or declare deadlock, or sleep if there are no runnable
1236 threads but some are blocked on I/O. */
1237
sewardje663cb92002-04-12 10:26:32 +00001238 /* Was a debug-stop requested? */
1239 if (VG_(bbs_to_go) == 0)
1240 goto debug_stop;
1241
1242 /* Do the following loop until a runnable thread is found, or
1243 deadlock is detected. */
1244 while (True) {
1245
1246 /* For stats purposes only. */
1247 VG_(num_scheduling_events_MAJOR) ++;
1248
1249 /* See if any I/O operations which we were waiting for have
1250 completed, and, if so, make runnable the relevant waiting
1251 threads. */
1252 poll_for_ready_fds();
1253 complete_blocked_syscalls();
sewardj5f07b662002-04-23 16:52:51 +00001254 check_for_pthread_cond_timedwait();
sewardje663cb92002-04-12 10:26:32 +00001255
1256 /* See if there are any signals which need to be delivered. If
1257 so, choose thread(s) to deliver them to, and build signal
1258 delivery frames on those thread(s) stacks. */
sewardj6072c362002-04-19 14:40:57 +00001259
1260 /* Be careful about delivering signals to a thread waiting
1261 for a mutex. In particular, when the handler is running,
1262 that thread is temporarily apparently-not-waiting for the
1263 mutex, so if it is unlocked by another thread whilst the
1264 handler is running, this thread is not informed. When the
1265 handler returns, the thread resumes waiting on the mutex,
1266 even if, as a result, it has missed the unlocking of it.
1267 Potential deadlock. This sounds all very strange, but the
1268 POSIX standard appears to require this behaviour. */
sewardjb48e5002002-05-13 00:16:03 +00001269 sigs_delivered = VG_(deliver_signals)();
sewardj14e03422002-04-24 19:51:31 +00001270 if (sigs_delivered)
sewardj0c3b53f2002-05-01 01:58:35 +00001271 VG_(do_sanity_checks)( False );
sewardje663cb92002-04-12 10:26:32 +00001272
1273 /* Try and find a thread (tid) to run. */
1274 tid_next = tid;
sewardj51c0aaf2002-04-25 01:32:10 +00001275 n_in_bounded_wait = 0;
sewardje663cb92002-04-12 10:26:32 +00001276 while (True) {
1277 tid_next++;
sewardj6072c362002-04-19 14:40:57 +00001278 if (tid_next >= VG_N_THREADS) tid_next = 1;
sewardj018f7622002-05-15 21:13:39 +00001279 if (VG_(threads)[tid_next].status == VgTs_WaitFD
1280 || VG_(threads)[tid_next].status == VgTs_Sleeping
1281 || VG_(threads)[tid_next].status == VgTs_WaitSIG
1282 || (VG_(threads)[tid_next].status == VgTs_WaitCV
1283 && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
sewardj51c0aaf2002-04-25 01:32:10 +00001284 n_in_bounded_wait ++;
sewardj018f7622002-05-15 21:13:39 +00001285 if (VG_(threads)[tid_next].status == VgTs_Runnable)
sewardje663cb92002-04-12 10:26:32 +00001286 break; /* We can run this one. */
1287 if (tid_next == tid)
1288 break; /* been all the way round */
1289 }
1290 tid = tid_next;
1291
sewardj018f7622002-05-15 21:13:39 +00001292 if (VG_(threads)[tid].status == VgTs_Runnable) {
sewardje663cb92002-04-12 10:26:32 +00001293 /* Found a suitable candidate. Fall out of this loop, so
1294 we can advance to stage 2 of the scheduler: actually
1295 running the thread. */
1296 break;
1297 }
1298
1299 /* We didn't find a runnable thread. Now what? */
sewardj51c0aaf2002-04-25 01:32:10 +00001300 if (n_in_bounded_wait == 0) {
sewardj54cacf02002-04-12 23:24:59 +00001301 /* No runnable threads and no prospect of any appearing
1302 even if we wait for an arbitrary length of time. In
1303 short, we have a deadlock. */
sewardj15a43e12002-04-17 19:35:12 +00001304 VG_(pp_sched_status)();
sewardje663cb92002-04-12 10:26:32 +00001305 return VgSrc_Deadlock;
1306 }
1307
1308 /* At least one thread is in a fd-wait state. Delay for a
1309 while, and go round again, in the hope that eventually a
1310 thread becomes runnable. */
1311 nanosleep_for_a_while();
sewardj7e87e382002-05-03 19:09:05 +00001312 /* pp_sched_status(); */
sewardjb48e5002002-05-13 00:16:03 +00001313 /* VG_(printf)("."); */
sewardje663cb92002-04-12 10:26:32 +00001314 }
1315
1316
1317 /* ======================= Phase 2 of 3 =======================
1318 Wahey! We've finally decided that thread tid is runnable, so
1319 we now do that. Run it for as much of a quanta as possible.
1320 Trivial requests are handled and the thread continues. The
1321 aim is not to do too many of Phase 1 since it is expensive. */
1322
1323 if (0)
sewardj3b5d8862002-04-20 13:53:23 +00001324 VG_(printf)("SCHED: tid %d\n", tid);
sewardje663cb92002-04-12 10:26:32 +00001325
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_TRACK( thread_run, tid );
1327
sewardje663cb92002-04-12 10:26:32 +00001328 /* Figure out how many bbs to ask vg_run_innerloop to do. Note
1329 that it decrements the counter before testing it for zero, so
1330 that if VG_(dispatch_ctr) is set to N you get at most N-1
1331 iterations. Also this means that VG_(dispatch_ctr) must
1332 exceed zero before entering the innerloop. Also also, the
1333 decrement is done before the bb is actually run, so you
1334 always get at least one decrement even if nothing happens.
1335 */
1336 if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
1337 VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
1338 else
1339 VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
1340
1341 /* ... and remember what we asked for. */
1342 dispatch_ctr_SAVED = VG_(dispatch_ctr);
1343
sewardj1e8cdc92002-04-18 11:37:52 +00001344 /* paranoia ... */
sewardj018f7622002-05-15 21:13:39 +00001345 vg_assert(VG_(threads)[tid].tid == tid);
sewardj1e8cdc92002-04-18 11:37:52 +00001346
sewardje663cb92002-04-12 10:26:32 +00001347 /* Actually run thread tid. */
1348 while (True) {
1349
sewardj7e87e382002-05-03 19:09:05 +00001350 VG_(last_run_tid) = tid;
1351
sewardje663cb92002-04-12 10:26:32 +00001352 /* For stats purposes only. */
1353 VG_(num_scheduling_events_MINOR) ++;
1354
1355 if (0)
1356 VG_(message)(Vg_DebugMsg, "thread %d: running for %d bbs",
1357 tid, VG_(dispatch_ctr) - 1 );
sewardjb3eef6b2002-05-01 00:05:27 +00001358# if 0
1359 if (VG_(bbs_done) > 31700000 + 0) {
1360 dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2;
sewardj018f7622002-05-15 21:13:39 +00001361 VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip,
sewardjb3eef6b2002-05-01 00:05:27 +00001362 NULL,NULL,NULL);
1363 }
sewardj018f7622002-05-15 21:13:39 +00001364 vg_assert(VG_(threads)[tid].m_eip != 0);
sewardjb3eef6b2002-05-01 00:05:27 +00001365# endif
sewardje663cb92002-04-12 10:26:32 +00001366
1367 trc = run_thread_for_a_while ( tid );
1368
sewardjb3eef6b2002-05-01 00:05:27 +00001369# if 0
sewardj018f7622002-05-15 21:13:39 +00001370 if (0 == VG_(threads)[tid].m_eip) {
sewardjb3eef6b2002-05-01 00:05:27 +00001371 VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done));
sewardj018f7622002-05-15 21:13:39 +00001372 vg_assert(0 != VG_(threads)[tid].m_eip);
sewardjb3eef6b2002-05-01 00:05:27 +00001373 }
1374# endif
1375
sewardje663cb92002-04-12 10:26:32 +00001376 /* Deal quickly with trivial scheduling events, and resume the
1377 thread. */
1378
1379 if (trc == VG_TRC_INNER_FASTMISS) {
1380 vg_assert(VG_(dispatch_ctr) > 0);
1381
1382 /* Trivial event. Miss in the fast-cache. Do a full
1383 lookup for it. */
1384 trans_addr
sewardj018f7622002-05-15 21:13:39 +00001385 = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001386 if (trans_addr == (Addr)0) {
1387 /* Not found; we need to request a translation. */
njn25e49d8e72002-09-23 09:36:25 +00001388 create_translation_for(
1389 tid, VG_(threads)[tid].m_eip );
sewardj018f7622002-05-15 21:13:39 +00001390 trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip );
sewardje663cb92002-04-12 10:26:32 +00001391 if (trans_addr == (Addr)0)
njne427a662002-10-02 11:08:25 +00001392 VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
sewardje663cb92002-04-12 10:26:32 +00001393 }
1394 continue; /* with this thread */
1395 }
1396
1397 if (trc == VG_TRC_EBP_JMP_CLIENTREQ) {
sewardj18a62ff2002-07-12 22:30:51 +00001398 UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax);
1399 /* VG_(printf)("request 0x%x\n", reqno); */
sewardj1fe7b002002-07-16 01:43:15 +00001400
1401 /* Are we really absolutely totally quitting? */
1402 if (reqno == VG_USERREQ__LIBC_FREERES_DONE) {
1403 if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1404 VG_(message)(Vg_DebugMsg,
1405 "__libc_freeres() done; really quitting!");
1406 }
1407 return VgSrc_ExitSyscall;
1408 }
1409
sewardj124ca2a2002-06-20 10:19:38 +00001410 do_client_request(tid);
1411 /* Following the request, we try and continue with the
1412 same thread if still runnable. If not, go back to
1413 Stage 1 to select a new thread to run. */
sewardj18a62ff2002-07-12 22:30:51 +00001414 if (VG_(threads)[tid].status == VgTs_Runnable
1415 && reqno != VG_USERREQ__PTHREAD_YIELD)
sewardj124ca2a2002-06-20 10:19:38 +00001416 continue; /* with this thread */
1417 else
1418 goto stage1;
sewardje663cb92002-04-12 10:26:32 +00001419 }
1420
sewardj51c0aaf2002-04-25 01:32:10 +00001421 if (trc == VG_TRC_EBP_JMP_SYSCALL) {
1422 /* Do a syscall for the vthread tid. This could cause it
sewardj7e87e382002-05-03 19:09:05 +00001423 to become non-runnable. One special case: spot the
1424 client doing calls to exit() and take this as the cue
1425 to exit. */
sewardjb3eef6b2002-05-01 00:05:27 +00001426# if 0
1427 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001428 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001429 VG_(printf)("\nBEFORE\n");
1430 for (i = 10; i >= -10; i--)
1431 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1432 }
1433# endif
1434
sewardj1fe7b002002-07-16 01:43:15 +00001435 /* Deal with calling __libc_freeres() at exit. When the
1436 client does __NR_exit, it's exiting for good. So we
1437 then run VG_(__libc_freeres_wrapper). That quits by
1438 doing VG_USERREQ__LIBC_FREERES_DONE, and at that point
1439 we really exit. To be safe we nuke all other threads
sewardjade9d0d2002-07-26 10:52:48 +00001440 currently running.
1441
1442 If not valgrinding (cachegrinding, etc) don't do this.
1443 __libc_freeres does some invalid frees which crash
1444 the unprotected malloc/free system. */
njn25e49d8e72002-09-23 09:36:25 +00001445
sewardj858964b2002-10-05 14:15:43 +00001446 if (VG_(threads)[tid].m_eax == __NR_exit) {
1447
1448 /* If __NR_exit, remember the supplied argument. */
njn25e49d8e72002-09-23 09:36:25 +00001449 VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
1450
sewardj858964b2002-10-05 14:15:43 +00001451 /* Only run __libc_freeres if the skin says it's ok and
1452 it hasn't been overridden with --run-libc-freeres=no
1453 on the command line. */
1454
1455 if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
1456
sewardj00631892002-10-05 15:34:38 +00001457 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001458 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1459 VG_(message)(Vg_DebugMsg,
1460 "Caught __NR_exit; running __libc_freeres()");
1461 }
1462 VG_(nuke_all_threads_except) ( tid );
1463 VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
1464 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1465 goto stage1; /* party on, dudes (but not for much longer :) */
1466
1467 } else {
1468 /* We won't run __libc_freeres; just exit now. */
sewardj00631892002-10-05 15:34:38 +00001469 if (VG_(clo_verbosity) > 2
sewardj858964b2002-10-05 14:15:43 +00001470 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
1471 VG_(message)(Vg_DebugMsg,
1472 "Caught __NR_exit; quitting");
1473 }
1474 return VgSrc_ExitSyscall;
1475 }
1476
sewardjade9d0d2002-07-26 10:52:48 +00001477 }
1478
sewardj858964b2002-10-05 14:15:43 +00001479 /* We've dealt with __NR_exit at this point. */
1480 vg_assert(VG_(threads)[tid].m_eax != __NR_exit);
sewardj7e87e382002-05-03 19:09:05 +00001481
sewardj83798bf2002-05-24 00:11:16 +00001482 /* Trap syscalls to __NR_sched_yield and just have this
1483 thread yield instead. Not essential, just an
1484 optimisation. */
1485 if (VG_(threads)[tid].m_eax == __NR_sched_yield) {
1486 SET_EAX(tid, 0); /* syscall returns with success */
1487 goto stage1; /* find a new thread to run */
1488 }
1489
sewardj51c0aaf2002-04-25 01:32:10 +00001490 sched_do_syscall(tid);
sewardjb3eef6b2002-05-01 00:05:27 +00001491
1492# if 0
1493 { UInt* esp; Int i;
sewardj018f7622002-05-15 21:13:39 +00001494 esp=(UInt*)VG_(threads)[tid].m_esp;
sewardjb3eef6b2002-05-01 00:05:27 +00001495 VG_(printf)("AFTER\n");
1496 for (i = 10; i >= -10; i--)
1497 VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]);
1498 }
1499# endif
1500
sewardj77f0fc12002-07-12 01:23:03 +00001501 if (VG_(threads)[tid].status == VgTs_Runnable) {
1502 /* Better do a signal check, since if in a tight loop
1503 with a slow syscall it may be a very long time
1504 before we get back to the main signal check in Stage 1. */
1505 sigs_delivered = VG_(deliver_signals)();
1506 if (sigs_delivered)
1507 VG_(do_sanity_checks)( False );
sewardj51c0aaf2002-04-25 01:32:10 +00001508 continue; /* with this thread */
sewardj77f0fc12002-07-12 01:23:03 +00001509 } else {
1510 goto stage1;
1511 }
sewardj51c0aaf2002-04-25 01:32:10 +00001512 }
1513
sewardjd7fd4d22002-04-24 01:57:27 +00001514 /* It's an event we can't quickly deal with. Give up running
1515 this thread and handle things the expensive way. */
sewardje663cb92002-04-12 10:26:32 +00001516 break;
1517 }
1518
1519 /* ======================= Phase 3 of 3 =======================
1520 Handle non-trivial thread requests, mostly pthread stuff. */
1521
1522 /* Ok, we've fallen out of the dispatcher for a
1523 non-completely-trivial reason. First, update basic-block
1524 counters. */
1525
1526 done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
1527 vg_assert(done_this_time >= 0);
1528 VG_(bbs_to_go) -= (ULong)done_this_time;
1529 VG_(bbs_done) += (ULong)done_this_time;
1530
1531 if (0 && trc != VG_TRC_INNER_FASTMISS)
1532 VG_(message)(Vg_DebugMsg, "thread %d: completed %d bbs, trc %d",
1533 tid, done_this_time, (Int)trc );
1534
1535 if (0 && trc != VG_TRC_INNER_FASTMISS)
1536 VG_(message)(Vg_DebugMsg, "thread %d: %ld bbs, event %s",
1537 tid, VG_(bbs_done),
1538 name_of_sched_event(trc) );
sewardj9d1b5d32002-04-17 19:40:49 +00001539
sewardje663cb92002-04-12 10:26:32 +00001540 /* Examine the thread's return code to figure out why it
sewardj124ca2a2002-06-20 10:19:38 +00001541 stopped. */
sewardje663cb92002-04-12 10:26:32 +00001542
1543 switch (trc) {
1544
sewardje663cb92002-04-12 10:26:32 +00001545 case VG_TRC_INNER_COUNTERZERO:
1546 /* Timeslice is out. Let a new thread be scheduled,
1547 simply by doing nothing, causing us to arrive back at
1548 Phase 1. */
1549 if (VG_(bbs_to_go) == 0) {
1550 goto debug_stop;
1551 }
1552 vg_assert(VG_(dispatch_ctr) == 0);
1553 break;
1554
1555 case VG_TRC_UNRESUMABLE_SIGNAL:
1556 /* It got a SIGSEGV/SIGBUS, which we need to deliver right
1557 away. Again, do nothing, so we wind up back at Phase
1558 1, whereupon the signal will be "delivered". */
1559 break;
1560
sewardje663cb92002-04-12 10:26:32 +00001561 default:
1562 VG_(printf)("\ntrc = %d\n", trc);
njne427a662002-10-02 11:08:25 +00001563 VG_(core_panic)("VG_(scheduler), phase 3: "
1564 "unexpected thread return code");
sewardje663cb92002-04-12 10:26:32 +00001565 /* NOTREACHED */
1566 break;
1567
1568 } /* switch (trc) */
1569
1570 /* That completes Phase 3 of 3. Return now to the top of the
1571 main scheduler loop, to Phase 1 of 3. */
1572
1573 } /* top-level scheduler loop */
1574
1575
1576 /* NOTREACHED */
njne427a662002-10-02 11:08:25 +00001577 VG_(core_panic)("scheduler: post-main-loop ?!");
sewardje663cb92002-04-12 10:26:32 +00001578 /* NOTREACHED */
1579
1580 debug_stop:
1581 /* If we exited because of a debug stop, print the translation
1582 of the last block executed -- by translating it again, and
1583 throwing away the result. */
1584 VG_(printf)(
1585 "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
sewardj018f7622002-05-15 21:13:39 +00001586 VG_(translate)( &VG_(threads)[tid],
sewardj22854b92002-11-30 14:00:47 +00001587 VG_(threads)[tid].m_eip, NULL, NULL, NULL, NULL );
sewardje663cb92002-04-12 10:26:32 +00001588 VG_(printf)("\n");
1589 VG_(printf)(
1590 "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
1591
1592 return VgSrc_BbsDone;
1593}
1594
1595
1596/* ---------------------------------------------------------------------
1597 The pthread implementation.
1598 ------------------------------------------------------------------ */
1599
1600#include <pthread.h>
1601#include <errno.h>
1602
sewardjbf290b92002-05-01 02:28:01 +00001603#define VG_PTHREAD_STACK_MIN \
sewardjc3bd5f52002-05-01 03:24:23 +00001604 (VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB)
sewardje663cb92002-04-12 10:26:32 +00001605
1606/* /usr/include/bits/pthreadtypes.h:
1607 typedef unsigned long int pthread_t;
1608*/
1609
sewardje663cb92002-04-12 10:26:32 +00001610
sewardj604ec3c2002-04-18 22:38:41 +00001611/* -----------------------------------------------------------
sewardj20917d82002-05-28 01:36:45 +00001612 Thread CREATION, JOINAGE and CANCELLATION: HELPER FNS
sewardj604ec3c2002-04-18 22:38:41 +00001613 -------------------------------------------------------- */
1614
sewardj20917d82002-05-28 01:36:45 +00001615/* We've decided to action a cancellation on tid. Make it jump to
1616 thread_exit_wrapper() in vg_libpthread.c, passing PTHREAD_CANCELED
1617 as the arg. */
1618static
1619void make_thread_jump_to_cancelhdlr ( ThreadId tid )
1620{
1621 Char msg_buf[100];
1622 vg_assert(VG_(is_valid_tid)(tid));
1623 /* Push PTHREAD_CANCELED on the stack and jump to the cancellation
1624 handler -- which is really thread_exit_wrapper() in
1625 vg_libpthread.c. */
1626 vg_assert(VG_(threads)[tid].cancel_pend != NULL);
1627 VG_(threads)[tid].m_esp -= 4;
1628 * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED;
1629 VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend;
1630 VG_(threads)[tid].status = VgTs_Runnable;
1631 /* Make sure we aren't cancelled again whilst handling this
1632 cancellation. */
1633 VG_(threads)[tid].cancel_st = False;
1634 if (VG_(clo_trace_sched)) {
1635 VG_(sprintf)(msg_buf,
1636 "jump to cancellation handler (hdlr = %p)",
1637 VG_(threads)[tid].cancel_pend);
1638 print_sched_event(tid, msg_buf);
1639 }
1640}
1641
1642
1643
sewardjb48e5002002-05-13 00:16:03 +00001644/* Release resources and generally clean up once a thread has finally
1645 disappeared. */
1646static
1647void cleanup_after_thread_exited ( ThreadId tid )
1648{
sewardj89f20fd2002-06-30 10:57:30 +00001649 Int i;
sewardj3a951cf2002-05-15 22:25:47 +00001650 vki_ksigset_t irrelevant_sigmask;
sewardj018f7622002-05-15 21:13:39 +00001651 vg_assert(VG_(is_valid_or_empty_tid)(tid));
1652 vg_assert(VG_(threads)[tid].status == VgTs_Empty);
njn25e49d8e72002-09-23 09:36:25 +00001653 /* Its stack is now off-limits */
1654 VG_TRACK( die_mem_stack, VG_(threads)[tid].stack_base,
1655 VG_(threads)[tid].stack_size );
1656
sewardjb48e5002002-05-13 00:16:03 +00001657 /* Forget about any pending signals directed specifically at this
sewardj018f7622002-05-15 21:13:39 +00001658 thread, and get rid of signal handlers specifically arranged for
1659 this thread. */
sewardj3a951cf2002-05-15 22:25:47 +00001660 VG_(block_all_host_signals)( &irrelevant_sigmask );
sewardj018f7622002-05-15 21:13:39 +00001661 VG_(handle_SCSS_change)( False /* lazy update */ );
sewardj89f20fd2002-06-30 10:57:30 +00001662
1663 /* Clean up the waiting_fd table */
1664 for (i = 0; i < VG_N_WAITING_FDS; i++) {
1665 if (vg_waiting_fds[i].tid == tid) {
1666 vg_waiting_fds[i].fd = -1; /* not in use */
1667 }
1668 }
sewardj92a59562002-09-30 00:53:10 +00001669
1670 /* Deallocate its LDT, if it ever had one. */
1671 VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt );
1672 VG_(threads)[tid].ldt = NULL;
sewardjb48e5002002-05-13 00:16:03 +00001673}
1674
1675
sewardj20917d82002-05-28 01:36:45 +00001676/* Look for matching pairs of threads waiting for joiners and threads
1677 waiting for joinees. For each such pair copy the return value of
1678 the joinee into the joiner, let the joiner resume and discard the
1679 joinee. */
1680static
1681void maybe_rendezvous_joiners_and_joinees ( void )
1682{
1683 Char msg_buf[100];
1684 void** thread_return;
1685 ThreadId jnr, jee;
1686
1687 for (jnr = 1; jnr < VG_N_THREADS; jnr++) {
1688 if (VG_(threads)[jnr].status != VgTs_WaitJoinee)
1689 continue;
1690 jee = VG_(threads)[jnr].joiner_jee_tid;
1691 if (jee == VG_INVALID_THREADID)
1692 continue;
1693 vg_assert(VG_(is_valid_tid)(jee));
1694 if (VG_(threads)[jee].status != VgTs_WaitJoiner)
1695 continue;
1696 /* ok! jnr is waiting to join with jee, and jee is waiting to be
1697 joined by ... well, any thread. So let's do it! */
1698
1699 /* Copy return value to where joiner wants it. */
1700 thread_return = VG_(threads)[jnr].joiner_thread_return;
1701 if (thread_return != NULL) {
1702 /* CHECK thread_return writable */
njn25e49d8e72002-09-23 09:36:25 +00001703 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[jnr],
1704 "pthread_join: thread_return",
1705 (Addr)thread_return, sizeof(void*));
sewardj5a3798b2002-06-04 23:24:22 +00001706
sewardj20917d82002-05-28 01:36:45 +00001707 *thread_return = VG_(threads)[jee].joinee_retval;
1708 /* Not really right, since it makes the thread's return value
1709 appear to be defined even if it isn't. */
njn25e49d8e72002-09-23 09:36:25 +00001710 VG_TRACK( post_mem_write, (Addr)thread_return, sizeof(void*) );
sewardj20917d82002-05-28 01:36:45 +00001711 }
1712
1713 /* Joinee is discarded */
1714 VG_(threads)[jee].status = VgTs_Empty; /* bye! */
1715 cleanup_after_thread_exited ( jee );
sewardjc4a810d2002-11-13 22:25:51 +00001716 if (VG_(clo_trace_sched)) {
1717 VG_(sprintf)(msg_buf,
1718 "rendezvous with joinee %d. %d resumes, %d exits.",
1719 jee, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001720 print_sched_event(jnr, msg_buf);
1721 }
sewardjc4a810d2002-11-13 22:25:51 +00001722
1723 VG_TRACK( post_thread_join, jnr, jee );
sewardj20917d82002-05-28 01:36:45 +00001724
1725 /* joiner returns with success */
1726 VG_(threads)[jnr].status = VgTs_Runnable;
1727 SET_EDX(jnr, 0);
1728 }
1729}
1730
1731
sewardjccef2e62002-05-29 19:26:32 +00001732/* Nuke all threads other than tid. POSIX specifies that this should
1733 happen in __NR_exec, and after a __NR_fork() when I am the child,
1734 as POSIX requires. */
1735void VG_(nuke_all_threads_except) ( ThreadId me )
1736{
1737 ThreadId tid;
1738 for (tid = 1; tid < VG_N_THREADS; tid++) {
1739 if (tid == me
1740 || VG_(threads)[tid].status == VgTs_Empty)
1741 continue;
sewardjef037c72002-05-30 00:40:03 +00001742 if (0)
1743 VG_(printf)(
1744 "VG_(nuke_all_threads_except): nuking tid %d\n", tid);
sewardjccef2e62002-05-29 19:26:32 +00001745 VG_(threads)[tid].status = VgTs_Empty;
1746 cleanup_after_thread_exited( tid );
1747 }
1748}
1749
1750
sewardj20917d82002-05-28 01:36:45 +00001751/* -----------------------------------------------------------
1752 Thread CREATION, JOINAGE and CANCELLATION: REQUESTS
1753 -------------------------------------------------------- */
1754
sewardje663cb92002-04-12 10:26:32 +00001755static
sewardj8ad94e12002-05-29 00:10:20 +00001756void do__cleanup_push ( ThreadId tid, CleanupEntry* cu )
1757{
1758 Int sp;
1759 Char msg_buf[100];
1760 vg_assert(VG_(is_valid_tid)(tid));
1761 sp = VG_(threads)[tid].custack_used;
1762 if (VG_(clo_trace_sched)) {
1763 VG_(sprintf)(msg_buf,
1764 "cleanup_push (fn %p, arg %p) -> slot %d",
1765 cu->fn, cu->arg, sp);
1766 print_sched_event(tid, msg_buf);
1767 }
1768 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1769 if (sp == VG_N_CLEANUPSTACK)
njne427a662002-10-02 11:08:25 +00001770 VG_(core_panic)("do__cleanup_push: VG_N_CLEANUPSTACK is too small."
sewardj8ad94e12002-05-29 00:10:20 +00001771 " Increase and recompile.");
1772 VG_(threads)[tid].custack[sp] = *cu;
1773 sp++;
1774 VG_(threads)[tid].custack_used = sp;
1775 SET_EDX(tid, 0);
1776}
1777
1778
1779static
1780void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
1781{
1782 Int sp;
1783 Char msg_buf[100];
1784 vg_assert(VG_(is_valid_tid)(tid));
1785 sp = VG_(threads)[tid].custack_used;
1786 if (VG_(clo_trace_sched)) {
njn36650922002-10-04 09:18:09 +00001787 VG_(sprintf)(msg_buf, "cleanup_pop from slot %d", sp-1);
sewardj8ad94e12002-05-29 00:10:20 +00001788 print_sched_event(tid, msg_buf);
1789 }
1790 vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
1791 if (sp == 0) {
1792 SET_EDX(tid, -1);
1793 return;
1794 }
1795 sp--;
njn36650922002-10-04 09:18:09 +00001796 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
1797 "cleanup pop", (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001798 *cu = VG_(threads)[tid].custack[sp];
njn25e49d8e72002-09-23 09:36:25 +00001799 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj8ad94e12002-05-29 00:10:20 +00001800 VG_(threads)[tid].custack_used = sp;
1801 SET_EDX(tid, 0);
1802}
1803
1804
1805static
sewardjff42d1d2002-05-22 13:17:31 +00001806void do_pthread_yield ( ThreadId tid )
1807{
1808 Char msg_buf[100];
1809 vg_assert(VG_(is_valid_tid)(tid));
sewardjff42d1d2002-05-22 13:17:31 +00001810 if (VG_(clo_trace_sched)) {
1811 VG_(sprintf)(msg_buf, "yield");
1812 print_sched_event(tid, msg_buf);
1813 }
1814 SET_EDX(tid, 0);
1815}
1816
1817
1818static
sewardj20917d82002-05-28 01:36:45 +00001819void do__testcancel ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00001820{
sewardj7989d0c2002-05-28 11:00:01 +00001821 Char msg_buf[100];
sewardjb48e5002002-05-13 00:16:03 +00001822 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001823 if (VG_(clo_trace_sched)) {
1824 VG_(sprintf)(msg_buf, "testcancel");
1825 print_sched_event(tid, msg_buf);
1826 }
sewardj20917d82002-05-28 01:36:45 +00001827 if (/* is there a cancellation pending on this thread? */
1828 VG_(threads)[tid].cancel_pend != NULL
1829 && /* is this thread accepting cancellations? */
1830 VG_(threads)[tid].cancel_st) {
1831 /* Ok, let's do the cancellation. */
1832 make_thread_jump_to_cancelhdlr ( tid );
sewardje663cb92002-04-12 10:26:32 +00001833 } else {
sewardj20917d82002-05-28 01:36:45 +00001834 /* No, we keep going. */
1835 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00001836 }
sewardje663cb92002-04-12 10:26:32 +00001837}
1838
1839
1840static
sewardj20917d82002-05-28 01:36:45 +00001841void do__set_cancelstate ( ThreadId tid, Int state )
1842{
1843 Bool old_st;
sewardj7989d0c2002-05-28 11:00:01 +00001844 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001845 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001846 if (VG_(clo_trace_sched)) {
1847 VG_(sprintf)(msg_buf, "set_cancelstate to %d (%s)", state,
1848 state==PTHREAD_CANCEL_ENABLE
1849 ? "ENABLE"
1850 : (state==PTHREAD_CANCEL_DISABLE ? "DISABLE" : "???"));
1851 print_sched_event(tid, msg_buf);
1852 }
sewardj20917d82002-05-28 01:36:45 +00001853 old_st = VG_(threads)[tid].cancel_st;
1854 if (state == PTHREAD_CANCEL_ENABLE) {
1855 VG_(threads)[tid].cancel_st = True;
1856 } else
1857 if (state == PTHREAD_CANCEL_DISABLE) {
1858 VG_(threads)[tid].cancel_st = False;
1859 } else {
njne427a662002-10-02 11:08:25 +00001860 VG_(core_panic)("do__set_cancelstate");
sewardj20917d82002-05-28 01:36:45 +00001861 }
1862 SET_EDX(tid, old_st ? PTHREAD_CANCEL_ENABLE
1863 : PTHREAD_CANCEL_DISABLE);
1864}
1865
1866
1867static
1868void do__set_canceltype ( ThreadId tid, Int type )
1869{
1870 Bool old_ty;
sewardj7989d0c2002-05-28 11:00:01 +00001871 Char msg_buf[100];
sewardj20917d82002-05-28 01:36:45 +00001872 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001873 if (VG_(clo_trace_sched)) {
1874 VG_(sprintf)(msg_buf, "set_canceltype to %d (%s)", type,
1875 type==PTHREAD_CANCEL_ASYNCHRONOUS
1876 ? "ASYNCHRONOUS"
1877 : (type==PTHREAD_CANCEL_DEFERRED ? "DEFERRED" : "???"));
1878 print_sched_event(tid, msg_buf);
1879 }
sewardj20917d82002-05-28 01:36:45 +00001880 old_ty = VG_(threads)[tid].cancel_ty;
1881 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
1882 VG_(threads)[tid].cancel_ty = False;
1883 } else
1884 if (type == PTHREAD_CANCEL_DEFERRED) {
sewardjaf00b6d2002-05-29 23:30:28 +00001885 VG_(threads)[tid].cancel_ty = True;
sewardj20917d82002-05-28 01:36:45 +00001886 } else {
njne427a662002-10-02 11:08:25 +00001887 VG_(core_panic)("do__set_canceltype");
sewardj20917d82002-05-28 01:36:45 +00001888 }
1889 SET_EDX(tid, old_ty ? PTHREAD_CANCEL_DEFERRED
1890 : PTHREAD_CANCEL_ASYNCHRONOUS);
1891}
1892
1893
sewardj7989d0c2002-05-28 11:00:01 +00001894/* Set or get the detach state for thread det. */
sewardj20917d82002-05-28 01:36:45 +00001895static
sewardj7989d0c2002-05-28 11:00:01 +00001896void do__set_or_get_detach ( ThreadId tid,
1897 Int what, ThreadId det )
sewardj20917d82002-05-28 01:36:45 +00001898{
sewardj7989d0c2002-05-28 11:00:01 +00001899 ThreadId i;
1900 Char msg_buf[100];
1901 /* VG_(printf)("do__set_or_get_detach tid %d what %d det %d\n",
1902 tid, what, det); */
sewardj20917d82002-05-28 01:36:45 +00001903 vg_assert(VG_(is_valid_tid)(tid));
sewardj7989d0c2002-05-28 11:00:01 +00001904 if (VG_(clo_trace_sched)) {
1905 VG_(sprintf)(msg_buf, "set_or_get_detach %d (%s) for tid %d", what,
1906 what==0 ? "not-detached" : (
1907 what==1 ? "detached" : (
1908 what==2 ? "fetch old value" : "???")),
1909 det );
1910 print_sched_event(tid, msg_buf);
1911 }
1912
1913 if (!VG_(is_valid_tid)(det)) {
1914 SET_EDX(tid, -1);
1915 return;
1916 }
1917
sewardj20917d82002-05-28 01:36:45 +00001918 switch (what) {
1919 case 2: /* get */
sewardj7989d0c2002-05-28 11:00:01 +00001920 SET_EDX(tid, VG_(threads)[det].detached ? 1 : 0);
sewardj20917d82002-05-28 01:36:45 +00001921 return;
sewardj7989d0c2002-05-28 11:00:01 +00001922 case 1: /* set detached. If someone is in a join-wait for det,
1923 do not detach. */
1924 for (i = 1; i < VG_N_THREADS; i++) {
1925 if (VG_(threads)[i].status == VgTs_WaitJoinee
1926 && VG_(threads)[i].joiner_jee_tid == det) {
1927 SET_EDX(tid, 0);
1928 if (VG_(clo_trace_sched)) {
1929 VG_(sprintf)(msg_buf,
njn9b6d34e2002-10-15 08:48:08 +00001930 "tid %d not detached because %d in join-wait for it",
sewardj7989d0c2002-05-28 11:00:01 +00001931 det, i);
1932 print_sched_event(tid, msg_buf);
1933 }
1934 return;
1935 }
1936 }
1937 VG_(threads)[det].detached = True;
sewardj20917d82002-05-28 01:36:45 +00001938 SET_EDX(tid, 0);
1939 return;
1940 case 0: /* set not detached */
sewardj7989d0c2002-05-28 11:00:01 +00001941 VG_(threads)[det].detached = False;
sewardj20917d82002-05-28 01:36:45 +00001942 SET_EDX(tid, 0);
1943 return;
1944 default:
njne427a662002-10-02 11:08:25 +00001945 VG_(core_panic)("do__set_or_get_detach");
sewardj20917d82002-05-28 01:36:45 +00001946 }
1947}
1948
1949
1950static
1951void do__set_cancelpend ( ThreadId tid,
1952 ThreadId cee,
1953 void (*cancelpend_hdlr)(void*) )
sewardje663cb92002-04-12 10:26:32 +00001954{
1955 Char msg_buf[100];
1956
sewardj20917d82002-05-28 01:36:45 +00001957 vg_assert(VG_(is_valid_tid)(tid));
1958 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
1959
sewardj7989d0c2002-05-28 11:00:01 +00001960 if (!VG_(is_valid_tid)(cee)) {
1961 if (VG_(clo_trace_sched)) {
1962 VG_(sprintf)(msg_buf,
1963 "set_cancelpend for invalid tid %d", cee);
1964 print_sched_event(tid, msg_buf);
1965 }
njn25e49d8e72002-09-23 09:36:25 +00001966 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00001967 "pthread_cancel: target thread does not exist, or invalid");
sewardj7989d0c2002-05-28 11:00:01 +00001968 SET_EDX(tid, -VKI_ESRCH);
1969 return;
1970 }
sewardj20917d82002-05-28 01:36:45 +00001971
1972 VG_(threads)[cee].cancel_pend = cancelpend_hdlr;
1973
1974 if (VG_(clo_trace_sched)) {
1975 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00001976 "set_cancelpend (hdlr = %p, set by tid %d)",
sewardj20917d82002-05-28 01:36:45 +00001977 cancelpend_hdlr, tid);
1978 print_sched_event(cee, msg_buf);
1979 }
1980
1981 /* Thread doing the cancelling returns with success. */
1982 SET_EDX(tid, 0);
1983
1984 /* Perhaps we can nuke the cancellee right now? */
1985 do__testcancel(cee);
1986}
1987
1988
1989static
1990void do_pthread_join ( ThreadId tid,
1991 ThreadId jee, void** thread_return )
1992{
1993 Char msg_buf[100];
1994 ThreadId i;
sewardje663cb92002-04-12 10:26:32 +00001995 /* jee, the joinee, is the thread specified as an arg in thread
1996 tid's call to pthread_join. So tid is the join-er. */
sewardjb48e5002002-05-13 00:16:03 +00001997 vg_assert(VG_(is_valid_tid)(tid));
sewardj018f7622002-05-15 21:13:39 +00001998 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00001999
2000 if (jee == tid) {
njn25e49d8e72002-09-23 09:36:25 +00002001 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002002 "pthread_join: attempt to join to self");
sewardjc3bd5f52002-05-01 03:24:23 +00002003 SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
sewardj018f7622002-05-15 21:13:39 +00002004 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002005 return;
2006 }
2007
sewardj20917d82002-05-28 01:36:45 +00002008 /* Flush any completed pairs, so as to make sure what we're looking
2009 at is up-to-date. */
2010 maybe_rendezvous_joiners_and_joinees();
2011
2012 /* Is this a sane request? */
sewardje663cb92002-04-12 10:26:32 +00002013 if (jee < 0
2014 || jee >= VG_N_THREADS
sewardj018f7622002-05-15 21:13:39 +00002015 || VG_(threads)[jee].status == VgTs_Empty) {
sewardje663cb92002-04-12 10:26:32 +00002016 /* Invalid thread to join to. */
njn25e49d8e72002-09-23 09:36:25 +00002017 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002018 "pthread_join: target thread does not exist, or invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002019 SET_EDX(tid, EINVAL);
sewardj018f7622002-05-15 21:13:39 +00002020 VG_(threads)[tid].status = VgTs_Runnable;
sewardje663cb92002-04-12 10:26:32 +00002021 return;
2022 }
2023
sewardj20917d82002-05-28 01:36:45 +00002024 /* Is anyone else already in a join-wait for jee? */
2025 for (i = 1; i < VG_N_THREADS; i++) {
2026 if (i == tid) continue;
2027 if (VG_(threads)[i].status == VgTs_WaitJoinee
2028 && VG_(threads)[i].joiner_jee_tid == jee) {
2029 /* Someone already did join on this thread */
njn25e49d8e72002-09-23 09:36:25 +00002030 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002031 "pthread_join: another thread already "
2032 "in join-wait for target thread");
sewardj20917d82002-05-28 01:36:45 +00002033 SET_EDX(tid, EINVAL);
2034 VG_(threads)[tid].status = VgTs_Runnable;
2035 return;
2036 }
sewardje663cb92002-04-12 10:26:32 +00002037 }
2038
sewardj20917d82002-05-28 01:36:45 +00002039 /* Mark this thread as waiting for the joinee. */
sewardj018f7622002-05-15 21:13:39 +00002040 VG_(threads)[tid].status = VgTs_WaitJoinee;
sewardj20917d82002-05-28 01:36:45 +00002041 VG_(threads)[tid].joiner_thread_return = thread_return;
2042 VG_(threads)[tid].joiner_jee_tid = jee;
2043
2044 /* Look for matching joiners and joinees and do the right thing. */
2045 maybe_rendezvous_joiners_and_joinees();
2046
2047 /* Return value is irrelevant since this this thread becomes
2048 non-runnable. maybe_resume_joiner() will cause it to return the
2049 right value when it resumes. */
2050
sewardj8937c812002-04-12 20:12:20 +00002051 if (VG_(clo_trace_sched)) {
sewardj20917d82002-05-28 01:36:45 +00002052 VG_(sprintf)(msg_buf,
2053 "wait for joinee %d (may already be ready)", jee);
sewardje663cb92002-04-12 10:26:32 +00002054 print_sched_event(tid, msg_buf);
2055 }
sewardje663cb92002-04-12 10:26:32 +00002056}
2057
2058
sewardj20917d82002-05-28 01:36:45 +00002059/* ( void* ): calling thread waits for joiner and returns the void* to
2060 it. This is one of two ways in which a thread can finally exit --
2061 the other is do__quit. */
sewardje663cb92002-04-12 10:26:32 +00002062static
sewardj20917d82002-05-28 01:36:45 +00002063void do__wait_joiner ( ThreadId tid, void* retval )
sewardje663cb92002-04-12 10:26:32 +00002064{
sewardj20917d82002-05-28 01:36:45 +00002065 Char msg_buf[100];
2066 vg_assert(VG_(is_valid_tid)(tid));
2067 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2068 if (VG_(clo_trace_sched)) {
2069 VG_(sprintf)(msg_buf,
sewardj7989d0c2002-05-28 11:00:01 +00002070 "do__wait_joiner(retval = %p) (non-detached thread exit)", retval);
sewardj20917d82002-05-28 01:36:45 +00002071 print_sched_event(tid, msg_buf);
2072 }
2073 VG_(threads)[tid].status = VgTs_WaitJoiner;
2074 VG_(threads)[tid].joinee_retval = retval;
2075 maybe_rendezvous_joiners_and_joinees();
2076}
2077
2078
2079/* ( no-args ): calling thread disappears from the system forever.
2080 Reclaim resources. */
2081static
2082void do__quit ( ThreadId tid )
2083{
2084 Char msg_buf[100];
2085 vg_assert(VG_(is_valid_tid)(tid));
2086 vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
2087 VG_(threads)[tid].status = VgTs_Empty; /* bye! */
2088 cleanup_after_thread_exited ( tid );
sewardj20917d82002-05-28 01:36:45 +00002089 if (VG_(clo_trace_sched)) {
sewardj7989d0c2002-05-28 11:00:01 +00002090 VG_(sprintf)(msg_buf, "do__quit (detached thread exit)");
sewardj20917d82002-05-28 01:36:45 +00002091 print_sched_event(tid, msg_buf);
2092 }
2093 /* Return value is irrelevant; this thread will not get
2094 rescheduled. */
2095}
2096
2097
2098/* Should never be entered. If it is, will be on the simulated
2099 CPU. */
2100static
2101void do__apply_in_new_thread_bogusRA ( void )
2102{
njne427a662002-10-02 11:08:25 +00002103 VG_(core_panic)("do__apply_in_new_thread_bogusRA");
sewardj20917d82002-05-28 01:36:45 +00002104}
2105
2106/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
2107 MUST NOT return -- ever. Eventually it will do either __QUIT or
2108 __WAIT_JOINER. Return the child tid to the parent. */
2109static
2110void do__apply_in_new_thread ( ThreadId parent_tid,
2111 void* (*fn)(void *),
2112 void* arg )
2113{
sewardje663cb92002-04-12 10:26:32 +00002114 Addr new_stack;
2115 UInt new_stk_szb;
2116 ThreadId tid;
2117 Char msg_buf[100];
2118
2119 /* Paranoia ... */
2120 vg_assert(sizeof(pthread_t) == sizeof(UInt));
2121
sewardj018f7622002-05-15 21:13:39 +00002122 vg_assert(VG_(threads)[parent_tid].status != VgTs_Empty);
sewardje663cb92002-04-12 10:26:32 +00002123
sewardj1e8cdc92002-04-18 11:37:52 +00002124 tid = vg_alloc_ThreadState();
sewardje663cb92002-04-12 10:26:32 +00002125
2126 /* If we've created the main thread's tid, we're in deep trouble :) */
sewardj6072c362002-04-19 14:40:57 +00002127 vg_assert(tid != 1);
sewardj018f7622002-05-15 21:13:39 +00002128 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardje663cb92002-04-12 10:26:32 +00002129
sewardjc4a810d2002-11-13 22:25:51 +00002130 /* do this early, before the child gets any memory writes */
2131 VG_TRACK ( post_thread_create, parent_tid, tid );
2132
sewardjf6374322002-11-13 22:35:55 +00002133 /* Create new thread with default attrs:
2134 deferred cancellation, not detached
2135 */
2136 mostly_clear_thread_record(tid);
2137 VG_(threads)[tid].status = VgTs_Runnable;
2138
sewardje663cb92002-04-12 10:26:32 +00002139 /* Copy the parent's CPU state into the child's, in a roundabout
2140 way (via baseBlock). */
2141 VG_(load_thread_state)(parent_tid);
2142 VG_(save_thread_state)(tid);
sewardjf6374322002-11-13 22:35:55 +00002143 vg_tid_last_in_baseBlock = tid;
sewardje663cb92002-04-12 10:26:32 +00002144
2145 /* Consider allocating the child a stack, if the one it already has
2146 is inadequate. */
sewardjbf290b92002-05-01 02:28:01 +00002147 new_stk_szb = VG_PTHREAD_STACK_MIN;
sewardje663cb92002-04-12 10:26:32 +00002148
sewardj018f7622002-05-15 21:13:39 +00002149 if (new_stk_szb > VG_(threads)[tid].stack_size) {
sewardje663cb92002-04-12 10:26:32 +00002150 /* Again, for good measure :) We definitely don't want to be
2151 allocating a stack for the main thread. */
sewardj6072c362002-04-19 14:40:57 +00002152 vg_assert(tid != 1);
sewardje663cb92002-04-12 10:26:32 +00002153 /* for now, we don't handle the case of anything other than
2154 assigning it for the first time. */
sewardj018f7622002-05-15 21:13:39 +00002155 vg_assert(VG_(threads)[tid].stack_size == 0);
2156 vg_assert(VG_(threads)[tid].stack_base == (Addr)NULL);
sewardje9047952002-06-05 20:28:33 +00002157 new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb,
2158 "new thread stack" );
sewardj018f7622002-05-15 21:13:39 +00002159 VG_(threads)[tid].stack_base = new_stack;
2160 VG_(threads)[tid].stack_size = new_stk_szb;
2161 VG_(threads)[tid].stack_highest_word
sewardje663cb92002-04-12 10:26:32 +00002162 = new_stack + new_stk_szb
sewardj1e8cdc92002-04-18 11:37:52 +00002163 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
sewardje663cb92002-04-12 10:26:32 +00002164 }
sewardj1e8cdc92002-04-18 11:37:52 +00002165
njn25e49d8e72002-09-23 09:36:25 +00002166 /* Having got memory to hold the thread's stack:
2167 - set %esp as base + size
2168 - mark everything below %esp inaccessible
2169 - mark redzone at stack end inaccessible
2170 */
2171 VG_(threads)[tid].m_esp = VG_(threads)[tid].stack_base
2172 + VG_(threads)[tid].stack_size
2173 - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
sewardj1e8cdc92002-04-18 11:37:52 +00002174
njn25e49d8e72002-09-23 09:36:25 +00002175 VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base,
2176 + new_stk_szb - VG_AR_CLIENT_STACKBASE_REDZONE_SZB);
2177 VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp,
2178 VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
sewardje663cb92002-04-12 10:26:32 +00002179
njn25e49d8e72002-09-23 09:36:25 +00002180 /* push two args */
2181 VG_(threads)[tid].m_esp -= 8;
2182 VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2183 VG_TRACK ( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
2184 "new thread: stack",
2185 (Addr)VG_(threads)[tid].m_esp, 2 * 4 );
2186
2187 /* push arg and (bogus) return address */
2188 * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg;
sewardj20917d82002-05-28 01:36:45 +00002189 * (UInt*)(VG_(threads)[tid].m_esp)
2190 = (UInt)&do__apply_in_new_thread_bogusRA;
sewardje663cb92002-04-12 10:26:32 +00002191
njn25e49d8e72002-09-23 09:36:25 +00002192 VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 );
sewardje663cb92002-04-12 10:26:32 +00002193
2194 /* this is where we start */
sewardj20917d82002-05-28 01:36:45 +00002195 VG_(threads)[tid].m_eip = (UInt)fn;
sewardje663cb92002-04-12 10:26:32 +00002196
sewardj8937c812002-04-12 20:12:20 +00002197 if (VG_(clo_trace_sched)) {
njn25e49d8e72002-09-23 09:36:25 +00002198 VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid );
sewardje663cb92002-04-12 10:26:32 +00002199 print_sched_event(tid, msg_buf);
2200 }
2201
sewardj018f7622002-05-15 21:13:39 +00002202 /* We inherit our parent's signal mask. */
2203 VG_(threads)[tid].sig_mask = VG_(threads)[parent_tid].sig_mask;
sewardj20917d82002-05-28 01:36:45 +00002204 VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
sewardjb48e5002002-05-13 00:16:03 +00002205
sewardj92a59562002-09-30 00:53:10 +00002206 /* We inherit our parent's LDT. */
2207 if (VG_(threads)[parent_tid].ldt == NULL) {
2208 /* We hope this is the common case. */
2209 VG_(threads)[tid].ldt = NULL;
2210 } else {
2211 /* No luck .. we have to take a copy of the parent's. */
2212 VG_(threads)[tid].ldt
2213 = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt );
2214 }
2215
sewardj20917d82002-05-28 01:36:45 +00002216 /* return child's tid to parent */
2217 SET_EDX(parent_tid, tid); /* success */
sewardje663cb92002-04-12 10:26:32 +00002218}
2219
2220
sewardj604ec3c2002-04-18 22:38:41 +00002221/* -----------------------------------------------------------
2222 MUTEXes
2223 -------------------------------------------------------- */
2224
sewardj604ec3c2002-04-18 22:38:41 +00002225/* pthread_mutex_t is a struct with at 5 words:
sewardje663cb92002-04-12 10:26:32 +00002226 typedef struct
2227 {
2228 int __m_reserved; -- Reserved for future use
2229 int __m_count; -- Depth of recursive locking
2230 _pthread_descr __m_owner; -- Owner thread (if recursive or errcheck)
2231 int __m_kind; -- Mutex kind: fast, recursive or errcheck
2232 struct _pthread_fastlock __m_lock; -- Underlying fast lock
2233 } pthread_mutex_t;
sewardj604ec3c2002-04-18 22:38:41 +00002234
sewardj6072c362002-04-19 14:40:57 +00002235 #define PTHREAD_MUTEX_INITIALIZER \
2236 {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
2237 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
2238 {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
2239 # define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
2240 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER}
2241 # define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
2242 {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
sewardj604ec3c2002-04-18 22:38:41 +00002243
sewardj6072c362002-04-19 14:40:57 +00002244 How we use it:
sewardj604ec3c2002-04-18 22:38:41 +00002245
sewardj6072c362002-04-19 14:40:57 +00002246 __m_kind never changes and indicates whether or not it is recursive.
2247
2248 __m_count indicates the lock count; if 0, the mutex is not owned by
2249 anybody.
2250
2251 __m_owner has a ThreadId value stuffed into it. We carefully arrange
2252 that ThreadId == 0 is invalid (VG_INVALID_THREADID), so that
2253 statically initialised mutexes correctly appear
2254 to belong to nobody.
2255
2256 In summary, a not-in-use mutex is distinguised by having __m_owner
2257 == 0 (VG_INVALID_THREADID) and __m_count == 0 too. If one of those
2258 conditions holds, the other should too.
2259
2260 There is no linked list of threads waiting for this mutex. Instead
2261 a thread in WaitMX state points at the mutex with its waited_on_mx
2262 field. This makes _unlock() inefficient, but simple to implement the
2263 right semantics viz-a-viz signals.
sewardje663cb92002-04-12 10:26:32 +00002264
sewardj604ec3c2002-04-18 22:38:41 +00002265 We don't have to deal with mutex initialisation; the client side
sewardj6072c362002-04-19 14:40:57 +00002266 deals with that for us.
2267*/
sewardje663cb92002-04-12 10:26:32 +00002268
sewardj3b5d8862002-04-20 13:53:23 +00002269/* Helper fns ... */
2270static
2271void release_one_thread_waiting_on_mutex ( pthread_mutex_t* mutex,
2272 Char* caller )
2273{
2274 Int i;
2275 Char msg_buf[100];
2276
2277 /* Find some arbitrary thread waiting on this mutex, and make it
2278 runnable. If none are waiting, mark the mutex as not held. */
2279 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002280 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002281 continue;
sewardj018f7622002-05-15 21:13:39 +00002282 if (VG_(threads)[i].status == VgTs_WaitMX
2283 && VG_(threads)[i].associated_mx == mutex)
sewardj3b5d8862002-04-20 13:53:23 +00002284 break;
2285 }
2286
sewardj0af43bc2002-10-22 04:30:35 +00002287 VG_TRACK( post_mutex_unlock, (ThreadId)mutex->__m_owner, mutex );
2288
sewardj3b5d8862002-04-20 13:53:23 +00002289 vg_assert(i <= VG_N_THREADS);
2290 if (i == VG_N_THREADS) {
2291 /* Nobody else is waiting on it. */
2292 mutex->__m_count = 0;
2293 mutex->__m_owner = VG_INVALID_THREADID;
2294 } else {
2295 /* Notionally transfer the hold to thread i, whose
2296 pthread_mutex_lock() call now returns with 0 (success). */
2297 /* The .count is already == 1. */
sewardj018f7622002-05-15 21:13:39 +00002298 vg_assert(VG_(threads)[i].associated_mx == mutex);
sewardj3b5d8862002-04-20 13:53:23 +00002299 mutex->__m_owner = (_pthread_descr)i;
sewardj018f7622002-05-15 21:13:39 +00002300 VG_(threads)[i].status = VgTs_Runnable;
2301 VG_(threads)[i].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002302 /* m_edx already holds pth_mx_lock() success (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002303
sewardj0af43bc2002-10-22 04:30:35 +00002304 VG_TRACK( post_mutex_lock, (ThreadId)i, mutex);
2305
sewardj3b5d8862002-04-20 13:53:23 +00002306 if (VG_(clo_trace_pthread_level) >= 1) {
2307 VG_(sprintf)(msg_buf, "%s mx %p: RESUME",
2308 caller, mutex );
2309 print_pthread_event(i, msg_buf);
2310 }
2311 }
2312}
2313
sewardje663cb92002-04-12 10:26:32 +00002314
2315static
sewardj30671ff2002-04-21 00:13:57 +00002316void do_pthread_mutex_lock( ThreadId tid,
2317 Bool is_trylock,
sewardj124ca2a2002-06-20 10:19:38 +00002318 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002319{
sewardj30671ff2002-04-21 00:13:57 +00002320 Char msg_buf[100];
2321 Char* caller
sewardj8ccc2be2002-05-10 20:26:37 +00002322 = is_trylock ? "pthread_mutex_trylock"
2323 : "pthread_mutex_lock ";
sewardje663cb92002-04-12 10:26:32 +00002324
sewardj604ec3c2002-04-18 22:38:41 +00002325 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj30671ff2002-04-21 00:13:57 +00002326 VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex );
sewardj604ec3c2002-04-18 22:38:41 +00002327 print_pthread_event(tid, msg_buf);
2328 }
2329
2330 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002331 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002332 && VG_(threads)[tid].status == VgTs_Runnable);
sewardje663cb92002-04-12 10:26:32 +00002333
2334 /* POSIX doesn't mandate this, but for sanity ... */
2335 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002336 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002337 "pthread_mutex_lock/trylock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002338 SET_EDX(tid, EINVAL);
sewardje663cb92002-04-12 10:26:32 +00002339 return;
2340 }
2341
sewardj604ec3c2002-04-18 22:38:41 +00002342 /* More paranoia ... */
2343 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002344# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002345 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002346 case PTHREAD_MUTEX_ADAPTIVE_NP:
2347# endif
sewardja1679dd2002-05-10 22:31:40 +00002348# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002349 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002350# endif
sewardj604ec3c2002-04-18 22:38:41 +00002351 case PTHREAD_MUTEX_RECURSIVE_NP:
2352 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002353 if (mutex->__m_count >= 0) break;
2354 /* else fall thru */
2355 default:
njn25e49d8e72002-09-23 09:36:25 +00002356 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002357 "pthread_mutex_lock/trylock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002358 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002359 return;
sewardje663cb92002-04-12 10:26:32 +00002360 }
2361
sewardj604ec3c2002-04-18 22:38:41 +00002362 if (mutex->__m_count > 0) {
sewardje663cb92002-04-12 10:26:32 +00002363
sewardjb48e5002002-05-13 00:16:03 +00002364 vg_assert(VG_(is_valid_tid)((ThreadId)mutex->__m_owner));
sewardjf8f819e2002-04-17 23:21:37 +00002365
2366 /* Someone has it already. */
sewardj604ec3c2002-04-18 22:38:41 +00002367 if ((ThreadId)mutex->__m_owner == tid) {
sewardjf8f819e2002-04-17 23:21:37 +00002368 /* It's locked -- by me! */
sewardj604ec3c2002-04-18 22:38:41 +00002369 if (mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP) {
sewardjf8f819e2002-04-17 23:21:37 +00002370 /* return 0 (success). */
sewardj604ec3c2002-04-18 22:38:41 +00002371 mutex->__m_count++;
sewardjc3bd5f52002-05-01 03:24:23 +00002372 SET_EDX(tid, 0);
sewardj853f55d2002-04-26 00:27:53 +00002373 if (0)
2374 VG_(printf)("!!!!!! tid %d, mx %p -> locked %d\n",
2375 tid, mutex, mutex->__m_count);
sewardjf8f819e2002-04-17 23:21:37 +00002376 return;
2377 } else {
sewardj30671ff2002-04-21 00:13:57 +00002378 if (is_trylock)
sewardjc3bd5f52002-05-01 03:24:23 +00002379 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002380 else
sewardjc3bd5f52002-05-01 03:24:23 +00002381 SET_EDX(tid, EDEADLK);
sewardjf8f819e2002-04-17 23:21:37 +00002382 return;
2383 }
2384 } else {
sewardj6072c362002-04-19 14:40:57 +00002385 /* Someone else has it; we have to wait. Mark ourselves
2386 thusly. */
sewardj05553872002-04-20 20:53:17 +00002387 /* GUARD: __m_count > 0 && __m_owner is valid */
sewardj30671ff2002-04-21 00:13:57 +00002388 if (is_trylock) {
2389 /* caller is polling; so return immediately. */
sewardjc3bd5f52002-05-01 03:24:23 +00002390 SET_EDX(tid, EBUSY);
sewardj30671ff2002-04-21 00:13:57 +00002391 } else {
sewardjdca84112002-11-13 22:29:34 +00002392 VG_TRACK ( pre_mutex_lock, tid, mutex );
2393
sewardj018f7622002-05-15 21:13:39 +00002394 VG_(threads)[tid].status = VgTs_WaitMX;
2395 VG_(threads)[tid].associated_mx = mutex;
sewardjc3bd5f52002-05-01 03:24:23 +00002396 SET_EDX(tid, 0); /* pth_mx_lock success value */
sewardj30671ff2002-04-21 00:13:57 +00002397 if (VG_(clo_trace_pthread_level) >= 1) {
2398 VG_(sprintf)(msg_buf, "%s mx %p: BLOCK",
2399 caller, mutex );
2400 print_pthread_event(tid, msg_buf);
2401 }
2402 }
sewardje663cb92002-04-12 10:26:32 +00002403 return;
2404 }
sewardjf8f819e2002-04-17 23:21:37 +00002405
sewardje663cb92002-04-12 10:26:32 +00002406 } else {
sewardj6072c362002-04-19 14:40:57 +00002407 /* Nobody owns it. Sanity check ... */
2408 vg_assert(mutex->__m_owner == VG_INVALID_THREADID);
sewardjdca84112002-11-13 22:29:34 +00002409
2410 VG_TRACK ( pre_mutex_lock, tid, mutex );
2411
sewardjf8f819e2002-04-17 23:21:37 +00002412 /* We get it! [for the first time]. */
sewardj604ec3c2002-04-18 22:38:41 +00002413 mutex->__m_count = 1;
2414 mutex->__m_owner = (_pthread_descr)tid;
njn25e49d8e72002-09-23 09:36:25 +00002415
2416 VG_TRACK( post_mutex_lock, tid, mutex);
2417
sewardje663cb92002-04-12 10:26:32 +00002418 /* return 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002419 SET_EDX(tid, 0);
sewardje663cb92002-04-12 10:26:32 +00002420 }
sewardjf8f819e2002-04-17 23:21:37 +00002421
sewardje663cb92002-04-12 10:26:32 +00002422}
2423
2424
2425static
2426void do_pthread_mutex_unlock ( ThreadId tid,
sewardj124ca2a2002-06-20 10:19:38 +00002427 pthread_mutex_t* mutex )
sewardje663cb92002-04-12 10:26:32 +00002428{
sewardj3b5d8862002-04-20 13:53:23 +00002429 Char msg_buf[100];
sewardje663cb92002-04-12 10:26:32 +00002430
sewardj45b4b372002-04-16 22:50:32 +00002431 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj3b5d8862002-04-20 13:53:23 +00002432 VG_(sprintf)(msg_buf, "pthread_mutex_unlock mx %p ...", mutex );
sewardj8937c812002-04-12 20:12:20 +00002433 print_pthread_event(tid, msg_buf);
2434 }
2435
sewardj604ec3c2002-04-18 22:38:41 +00002436 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002437 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002438 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj604ec3c2002-04-18 22:38:41 +00002439
2440 if (mutex == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002441 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002442 "pthread_mutex_unlock: mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002443 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002444 return;
2445 }
2446
sewardjd8acdf22002-11-13 21:57:52 +00002447 /* If this was locked before the dawn of time, pretend it was
2448 locked now so that it balances with unlocks */
2449 if (mutex->__m_kind & VG_PTHREAD_PREHISTORY) {
2450 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
sewardjdca84112002-11-13 22:29:34 +00002451 VG_TRACK( pre_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
sewardjd8acdf22002-11-13 21:57:52 +00002452 VG_TRACK( post_mutex_lock, (ThreadId)mutex->__m_owner, mutex );
2453 }
2454
sewardj604ec3c2002-04-18 22:38:41 +00002455 /* More paranoia ... */
2456 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002457# ifndef GLIBC_2_1
sewardj604ec3c2002-04-18 22:38:41 +00002458 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002459 case PTHREAD_MUTEX_ADAPTIVE_NP:
2460# endif
sewardja1679dd2002-05-10 22:31:40 +00002461# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002462 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002463# endif
sewardj604ec3c2002-04-18 22:38:41 +00002464 case PTHREAD_MUTEX_RECURSIVE_NP:
2465 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj604ec3c2002-04-18 22:38:41 +00002466 if (mutex->__m_count >= 0) break;
2467 /* else fall thru */
2468 default:
njn25e49d8e72002-09-23 09:36:25 +00002469 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002470 "pthread_mutex_unlock: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002471 SET_EDX(tid, EINVAL);
sewardj604ec3c2002-04-18 22:38:41 +00002472 return;
2473 }
sewardje663cb92002-04-12 10:26:32 +00002474
2475 /* Barf if we don't currently hold the mutex. */
sewardj4dced352002-06-04 22:54:20 +00002476 if (mutex->__m_count == 0) {
2477 /* nobody holds it */
njn25e49d8e72002-09-23 09:36:25 +00002478 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002479 "pthread_mutex_unlock: mutex is not locked");
2480 SET_EDX(tid, EPERM);
2481 return;
2482 }
2483
2484 if ((ThreadId)mutex->__m_owner != tid) {
2485 /* we don't hold it */
njn25e49d8e72002-09-23 09:36:25 +00002486 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002487 "pthread_mutex_unlock: mutex is locked by a different thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002488 SET_EDX(tid, EPERM);
sewardje663cb92002-04-12 10:26:32 +00002489 return;
2490 }
2491
sewardjf8f819e2002-04-17 23:21:37 +00002492 /* If it's a multiply-locked recursive mutex, just decrement the
2493 lock count and return. */
sewardj604ec3c2002-04-18 22:38:41 +00002494 if (mutex->__m_count > 1) {
2495 vg_assert(mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP);
2496 mutex->__m_count --;
sewardjc3bd5f52002-05-01 03:24:23 +00002497 SET_EDX(tid, 0); /* success */
sewardjf8f819e2002-04-17 23:21:37 +00002498 return;
2499 }
2500
sewardj604ec3c2002-04-18 22:38:41 +00002501 /* Now we're sure it is locked exactly once, and by the thread who
sewardjf8f819e2002-04-17 23:21:37 +00002502 is now doing an unlock on it. */
sewardj604ec3c2002-04-18 22:38:41 +00002503 vg_assert(mutex->__m_count == 1);
sewardj6072c362002-04-19 14:40:57 +00002504 vg_assert((ThreadId)mutex->__m_owner == tid);
sewardjf8f819e2002-04-17 23:21:37 +00002505
sewardj3b5d8862002-04-20 13:53:23 +00002506 /* Release at max one thread waiting on this mutex. */
2507 release_one_thread_waiting_on_mutex ( mutex, "pthread_mutex_lock" );
sewardje663cb92002-04-12 10:26:32 +00002508
sewardj3b5d8862002-04-20 13:53:23 +00002509 /* Our (tid's) pth_unlock() returns with 0 (success). */
sewardjc3bd5f52002-05-01 03:24:23 +00002510 SET_EDX(tid, 0); /* Success. */
sewardje663cb92002-04-12 10:26:32 +00002511}
2512
2513
sewardj6072c362002-04-19 14:40:57 +00002514/* -----------------------------------------------------------
2515 CONDITION VARIABLES
2516 -------------------------------------------------------- */
sewardje663cb92002-04-12 10:26:32 +00002517
sewardj6072c362002-04-19 14:40:57 +00002518/* The relevant native types are as follows:
2519 (copied from /usr/include/bits/pthreadtypes.h)
sewardj77e466c2002-04-14 02:29:29 +00002520
sewardj6072c362002-04-19 14:40:57 +00002521 -- Conditions (not abstract because of PTHREAD_COND_INITIALIZER
2522 typedef struct
2523 {
2524 struct _pthread_fastlock __c_lock; -- Protect against concurrent access
2525 _pthread_descr __c_waiting; -- Threads waiting on this condition
2526 } pthread_cond_t;
sewardj77e466c2002-04-14 02:29:29 +00002527
sewardj6072c362002-04-19 14:40:57 +00002528 -- Attribute for conditionally variables.
2529 typedef struct
2530 {
2531 int __dummy;
2532 } pthread_condattr_t;
sewardj77e466c2002-04-14 02:29:29 +00002533
sewardj6072c362002-04-19 14:40:57 +00002534 #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
sewardj77e466c2002-04-14 02:29:29 +00002535
sewardj3b5d8862002-04-20 13:53:23 +00002536 We don't use any fields of pthread_cond_t for anything at all.
2537 Only the identity of the CVs is important.
sewardj6072c362002-04-19 14:40:57 +00002538
2539 Linux pthreads supports no attributes on condition variables, so we
sewardj3b5d8862002-04-20 13:53:23 +00002540 don't need to think too hard there. */
sewardj6072c362002-04-19 14:40:57 +00002541
sewardj77e466c2002-04-14 02:29:29 +00002542
sewardj5f07b662002-04-23 16:52:51 +00002543static
2544void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid )
2545{
2546 Char msg_buf[100];
2547 pthread_mutex_t* mx;
2548 pthread_cond_t* cv;
2549
sewardjb48e5002002-05-13 00:16:03 +00002550 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002551 && VG_(threads)[tid].status == VgTs_WaitCV
2552 && VG_(threads)[tid].awaken_at != 0xFFFFFFFF);
2553 mx = VG_(threads)[tid].associated_mx;
sewardj5f07b662002-04-23 16:52:51 +00002554 vg_assert(mx != NULL);
sewardj018f7622002-05-15 21:13:39 +00002555 cv = VG_(threads)[tid].associated_cv;
sewardj5f07b662002-04-23 16:52:51 +00002556 vg_assert(cv != NULL);
2557
2558 if (mx->__m_owner == VG_INVALID_THREADID) {
2559 /* Currently unheld; hand it out to thread tid. */
2560 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002561 VG_(threads)[tid].status = VgTs_Runnable;
sewardjc3bd5f52002-05-01 03:24:23 +00002562 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002563 VG_(threads)[tid].associated_cv = NULL;
2564 VG_(threads)[tid].associated_mx = NULL;
sewardj5f07b662002-04-23 16:52:51 +00002565 mx->__m_owner = (_pthread_descr)tid;
2566 mx->__m_count = 1;
2567
sewardj0af43bc2002-10-22 04:30:35 +00002568 VG_TRACK( post_mutex_lock, tid, mx );
2569
sewardj5f07b662002-04-23 16:52:51 +00002570 if (VG_(clo_trace_pthread_level) >= 1) {
sewardjc3bd5f52002-05-01 03:24:23 +00002571 VG_(sprintf)(msg_buf,
2572 "pthread_cond_timedwai cv %p: TIMEOUT with mx %p",
2573 cv, mx );
sewardj5f07b662002-04-23 16:52:51 +00002574 print_pthread_event(tid, msg_buf);
2575 }
2576 } else {
2577 /* Currently held. Make thread tid be blocked on it. */
2578 vg_assert(mx->__m_count > 0);
sewardjdca84112002-11-13 22:29:34 +00002579 VG_TRACK( pre_mutex_lock, tid, mx );
2580
sewardj018f7622002-05-15 21:13:39 +00002581 VG_(threads)[tid].status = VgTs_WaitMX;
sewardjc3bd5f52002-05-01 03:24:23 +00002582 SET_EDX(tid, ETIMEDOUT); /* pthread_cond_wait return value */
sewardj018f7622002-05-15 21:13:39 +00002583 VG_(threads)[tid].associated_cv = NULL;
2584 VG_(threads)[tid].associated_mx = mx;
sewardj5f07b662002-04-23 16:52:51 +00002585 if (VG_(clo_trace_pthread_level) >= 1) {
2586 VG_(sprintf)(msg_buf,
2587 "pthread_cond_timedwai cv %p: TIMEOUT -> BLOCK for mx %p",
2588 cv, mx );
2589 print_pthread_event(tid, msg_buf);
2590 }
2591
2592 }
2593}
2594
2595
sewardj3b5d8862002-04-20 13:53:23 +00002596static
2597void release_N_threads_waiting_on_cond ( pthread_cond_t* cond,
2598 Int n_to_release,
2599 Char* caller )
2600{
2601 Int i;
2602 Char msg_buf[100];
2603 pthread_mutex_t* mx;
2604
2605 while (True) {
2606 if (n_to_release == 0)
2607 return;
2608
2609 /* Find a thread waiting on this CV. */
2610 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00002611 if (VG_(threads)[i].status == VgTs_Empty)
sewardj3b5d8862002-04-20 13:53:23 +00002612 continue;
sewardj018f7622002-05-15 21:13:39 +00002613 if (VG_(threads)[i].status == VgTs_WaitCV
2614 && VG_(threads)[i].associated_cv == cond)
sewardj3b5d8862002-04-20 13:53:23 +00002615 break;
2616 }
2617 vg_assert(i <= VG_N_THREADS);
2618
2619 if (i == VG_N_THREADS) {
2620 /* Nobody else is waiting on it. */
2621 return;
2622 }
2623
sewardj018f7622002-05-15 21:13:39 +00002624 mx = VG_(threads)[i].associated_mx;
sewardj3b5d8862002-04-20 13:53:23 +00002625 vg_assert(mx != NULL);
2626
sewardjdca84112002-11-13 22:29:34 +00002627 VG_TRACK( pre_mutex_lock, i, mx );
2628
sewardj3b5d8862002-04-20 13:53:23 +00002629 if (mx->__m_owner == VG_INVALID_THREADID) {
2630 /* Currently unheld; hand it out to thread i. */
2631 vg_assert(mx->__m_count == 0);
sewardj018f7622002-05-15 21:13:39 +00002632 VG_(threads)[i].status = VgTs_Runnable;
2633 VG_(threads)[i].associated_cv = NULL;
2634 VG_(threads)[i].associated_mx = NULL;
sewardj3b5d8862002-04-20 13:53:23 +00002635 mx->__m_owner = (_pthread_descr)i;
2636 mx->__m_count = 1;
sewardj5f07b662002-04-23 16:52:51 +00002637 /* .m_edx already holds pth_cond_wait success value (0) */
sewardj3b5d8862002-04-20 13:53:23 +00002638
sewardj0af43bc2002-10-22 04:30:35 +00002639 VG_TRACK( post_mutex_lock, i, mx );
2640
sewardj3b5d8862002-04-20 13:53:23 +00002641 if (VG_(clo_trace_pthread_level) >= 1) {
2642 VG_(sprintf)(msg_buf, "%s cv %p: RESUME with mx %p",
2643 caller, cond, mx );
2644 print_pthread_event(i, msg_buf);
2645 }
2646
2647 } else {
2648 /* Currently held. Make thread i be blocked on it. */
sewardj5f07b662002-04-23 16:52:51 +00002649 vg_assert(mx->__m_count > 0);
sewardj018f7622002-05-15 21:13:39 +00002650 VG_(threads)[i].status = VgTs_WaitMX;
2651 VG_(threads)[i].associated_cv = NULL;
2652 VG_(threads)[i].associated_mx = mx;
sewardjc3bd5f52002-05-01 03:24:23 +00002653 SET_EDX(i, 0); /* pth_cond_wait success value */
sewardj3b5d8862002-04-20 13:53:23 +00002654
2655 if (VG_(clo_trace_pthread_level) >= 1) {
2656 VG_(sprintf)(msg_buf, "%s cv %p: BLOCK for mx %p",
2657 caller, cond, mx );
2658 print_pthread_event(i, msg_buf);
2659 }
2660
2661 }
2662
2663 n_to_release--;
2664 }
2665}
2666
2667
2668static
2669void do_pthread_cond_wait ( ThreadId tid,
2670 pthread_cond_t *cond,
sewardj5f07b662002-04-23 16:52:51 +00002671 pthread_mutex_t *mutex,
2672 UInt ms_end )
sewardj3b5d8862002-04-20 13:53:23 +00002673{
2674 Char msg_buf[100];
2675
sewardj5f07b662002-04-23 16:52:51 +00002676 /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise,
2677 ms_end is the ending millisecond. */
2678
sewardj3b5d8862002-04-20 13:53:23 +00002679 /* pre: mutex should be a valid mutex and owned by tid. */
2680 if (VG_(clo_trace_pthread_level) >= 2) {
sewardj5f07b662002-04-23 16:52:51 +00002681 VG_(sprintf)(msg_buf, "pthread_cond_wait cv %p, mx %p, end %d ...",
2682 cond, mutex, ms_end );
sewardj3b5d8862002-04-20 13:53:23 +00002683 print_pthread_event(tid, msg_buf);
2684 }
2685
2686 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002687 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002688 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002689
2690 if (mutex == NULL || cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002691 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002692 "pthread_cond_wait/timedwait: cond or mutex is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002693 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002694 return;
2695 }
2696
2697 /* More paranoia ... */
2698 switch (mutex->__m_kind) {
sewardj2a1dcce2002-04-22 12:45:25 +00002699# ifndef GLIBC_2_1
sewardj3b5d8862002-04-20 13:53:23 +00002700 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00002701 case PTHREAD_MUTEX_ADAPTIVE_NP:
2702# endif
sewardja1679dd2002-05-10 22:31:40 +00002703# ifdef GLIBC_2_1
sewardj8e651d72002-05-10 21:00:19 +00002704 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00002705# endif
sewardj3b5d8862002-04-20 13:53:23 +00002706 case PTHREAD_MUTEX_RECURSIVE_NP:
2707 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardj3b5d8862002-04-20 13:53:23 +00002708 if (mutex->__m_count >= 0) break;
2709 /* else fall thru */
2710 default:
njn25e49d8e72002-09-23 09:36:25 +00002711 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002712 "pthread_cond_wait/timedwait: mutex is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002713 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002714 return;
2715 }
2716
2717 /* Barf if we don't currently hold the mutex. */
2718 if (mutex->__m_count == 0 /* nobody holds it */
2719 || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
njn25e49d8e72002-09-23 09:36:25 +00002720 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002721 "pthread_cond_wait/timedwait: mutex is unlocked "
2722 "or is locked but not owned by thread");
sewardjc3bd5f52002-05-01 03:24:23 +00002723 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002724 return;
2725 }
2726
2727 /* Queue ourselves on the condition. */
sewardj018f7622002-05-15 21:13:39 +00002728 VG_(threads)[tid].status = VgTs_WaitCV;
2729 VG_(threads)[tid].associated_cv = cond;
2730 VG_(threads)[tid].associated_mx = mutex;
2731 VG_(threads)[tid].awaken_at = ms_end;
sewardj3b5d8862002-04-20 13:53:23 +00002732
2733 if (VG_(clo_trace_pthread_level) >= 1) {
2734 VG_(sprintf)(msg_buf,
2735 "pthread_cond_wait cv %p, mx %p: BLOCK",
2736 cond, mutex );
2737 print_pthread_event(tid, msg_buf);
2738 }
2739
2740 /* Release the mutex. */
2741 release_one_thread_waiting_on_mutex ( mutex, "pthread_cond_wait " );
2742}
2743
2744
2745static
2746void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
2747 Bool broadcast,
2748 pthread_cond_t *cond )
2749{
2750 Char msg_buf[100];
2751 Char* caller
2752 = broadcast ? "pthread_cond_broadcast"
2753 : "pthread_cond_signal ";
2754
2755 if (VG_(clo_trace_pthread_level) >= 2) {
2756 VG_(sprintf)(msg_buf, "%s cv %p ...",
2757 caller, cond );
2758 print_pthread_event(tid, msg_buf);
2759 }
2760
2761 /* Paranoia ... */
sewardjb48e5002002-05-13 00:16:03 +00002762 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002763 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj3b5d8862002-04-20 13:53:23 +00002764
2765 if (cond == NULL) {
njn25e49d8e72002-09-23 09:36:25 +00002766 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002767 "pthread_cond_signal/broadcast: cond is NULL");
sewardjc3bd5f52002-05-01 03:24:23 +00002768 SET_EDX(tid, EINVAL);
sewardj3b5d8862002-04-20 13:53:23 +00002769 return;
2770 }
2771
2772 release_N_threads_waiting_on_cond (
2773 cond,
2774 broadcast ? VG_N_THREADS : 1,
2775 caller
2776 );
2777
sewardjc3bd5f52002-05-01 03:24:23 +00002778 SET_EDX(tid, 0); /* success */
sewardj3b5d8862002-04-20 13:53:23 +00002779}
2780
sewardj77e466c2002-04-14 02:29:29 +00002781
sewardj5f07b662002-04-23 16:52:51 +00002782/* -----------------------------------------------------------
2783 THREAD SPECIFIC DATA
2784 -------------------------------------------------------- */
2785
2786static __inline__
2787Bool is_valid_key ( ThreadKey k )
2788{
2789 /* k unsigned; hence no < 0 check */
2790 if (k >= VG_N_THREAD_KEYS) return False;
2791 if (!vg_thread_keys[k].inuse) return False;
2792 return True;
2793}
2794
sewardj00a66b12002-10-12 16:42:35 +00002795
2796/* Return in %EDX a value of 1 if the key is valid, else 0. */
2797static
2798void do_pthread_key_validate ( ThreadId tid,
2799 pthread_key_t key )
2800{
2801 Char msg_buf[100];
2802
2803 if (VG_(clo_trace_pthread_level) >= 1) {
2804 VG_(sprintf)(msg_buf, "pthread_key_validate key %p",
2805 key );
2806 print_pthread_event(tid, msg_buf);
2807 }
2808
2809 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
2810 vg_assert(VG_(is_valid_tid)(tid)
2811 && VG_(threads)[tid].status == VgTs_Runnable);
2812
2813 if (is_valid_key((ThreadKey)key)) {
2814 SET_EDX(tid, 1);
2815 } else {
2816 SET_EDX(tid, 0);
2817 }
2818}
2819
2820
sewardj5f07b662002-04-23 16:52:51 +00002821static
2822void do_pthread_key_create ( ThreadId tid,
2823 pthread_key_t* key,
2824 void (*destructor)(void*) )
2825{
2826 Int i;
2827 Char msg_buf[100];
2828
2829 if (VG_(clo_trace_pthread_level) >= 1) {
2830 VG_(sprintf)(msg_buf, "pthread_key_create *key %p, destr %p",
2831 key, destructor );
2832 print_pthread_event(tid, msg_buf);
2833 }
2834
2835 vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
sewardjb48e5002002-05-13 00:16:03 +00002836 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002837 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002838
2839 for (i = 0; i < VG_N_THREAD_KEYS; i++)
2840 if (!vg_thread_keys[i].inuse)
2841 break;
2842
2843 if (i == VG_N_THREAD_KEYS) {
sewardjc3bd5f52002-05-01 03:24:23 +00002844 /* SET_EDX(tid, EAGAIN);
sewardj5f07b662002-04-23 16:52:51 +00002845 return;
2846 */
njne427a662002-10-02 11:08:25 +00002847 VG_(core_panic)("pthread_key_create: VG_N_THREAD_KEYS is too low;"
2848 " increase and recompile");
sewardj5f07b662002-04-23 16:52:51 +00002849 }
2850
sewardj870497a2002-05-29 01:06:47 +00002851 vg_thread_keys[i].inuse = True;
2852 vg_thread_keys[i].destructor = destructor;
sewardjc3bd5f52002-05-01 03:24:23 +00002853
sewardj5a3798b2002-06-04 23:24:22 +00002854 /* check key for addressibility */
njn25e49d8e72002-09-23 09:36:25 +00002855 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
2856 "pthread_key_create: key",
2857 (Addr)key, sizeof(pthread_key_t));
sewardj5f07b662002-04-23 16:52:51 +00002858 *key = i;
njn25e49d8e72002-09-23 09:36:25 +00002859 VG_TRACK( post_mem_write, (Addr)key, sizeof(pthread_key_t) );
sewardjc3bd5f52002-05-01 03:24:23 +00002860
2861 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002862}
2863
2864
2865static
2866void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
2867{
2868 Char msg_buf[100];
2869 if (VG_(clo_trace_pthread_level) >= 1) {
2870 VG_(sprintf)(msg_buf, "pthread_key_delete key %d",
2871 key );
2872 print_pthread_event(tid, msg_buf);
2873 }
2874
sewardjb48e5002002-05-13 00:16:03 +00002875 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002876 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002877
2878 if (!is_valid_key(key)) {
njn25e49d8e72002-09-23 09:36:25 +00002879 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00002880 "pthread_key_delete: key is invalid");
sewardjc3bd5f52002-05-01 03:24:23 +00002881 SET_EDX(tid, EINVAL);
sewardj5f07b662002-04-23 16:52:51 +00002882 return;
2883 }
2884
2885 vg_thread_keys[key].inuse = False;
sewardj00a66b12002-10-12 16:42:35 +00002886 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002887}
2888
2889
sewardj00a66b12002-10-12 16:42:35 +00002890/* Get the .specific_ptr for a thread. Return 1 if the thread-slot
2891 isn't in use, so that client-space can scan all thread slots. 1
2892 cannot be confused with NULL or a legitimately-aligned specific_ptr
2893 value. */
sewardj5f07b662002-04-23 16:52:51 +00002894static
sewardj00a66b12002-10-12 16:42:35 +00002895void do_pthread_getspecific_ptr ( ThreadId tid )
sewardj5f07b662002-04-23 16:52:51 +00002896{
sewardj00a66b12002-10-12 16:42:35 +00002897 void** specifics_ptr;
2898 Char msg_buf[100];
2899
sewardj5f07b662002-04-23 16:52:51 +00002900 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002901 VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
sewardj5f07b662002-04-23 16:52:51 +00002902 print_pthread_event(tid, msg_buf);
2903 }
2904
sewardj00a66b12002-10-12 16:42:35 +00002905 vg_assert(VG_(is_valid_or_empty_tid)(tid));
sewardj5f07b662002-04-23 16:52:51 +00002906
sewardj00a66b12002-10-12 16:42:35 +00002907 if (VG_(threads)[tid].status == VgTs_Empty) {
2908 SET_EDX(tid, 1);
sewardj5f07b662002-04-23 16:52:51 +00002909 return;
2910 }
2911
sewardj00a66b12002-10-12 16:42:35 +00002912 specifics_ptr = VG_(threads)[tid].specifics_ptr;
2913 vg_assert(specifics_ptr == NULL
2914 || IS_ALIGNED4_ADDR(specifics_ptr));
2915
2916 SET_EDX(tid, (UInt)specifics_ptr);
sewardj5f07b662002-04-23 16:52:51 +00002917}
2918
2919
2920static
sewardj00a66b12002-10-12 16:42:35 +00002921void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
sewardj5f07b662002-04-23 16:52:51 +00002922{
2923 Char msg_buf[100];
2924 if (VG_(clo_trace_pthread_level) >= 1) {
sewardj00a66b12002-10-12 16:42:35 +00002925 VG_(sprintf)(msg_buf, "pthread_setspecific_ptr ptr %p",
2926 ptr );
sewardj5f07b662002-04-23 16:52:51 +00002927 print_pthread_event(tid, msg_buf);
2928 }
2929
sewardjb48e5002002-05-13 00:16:03 +00002930 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00002931 && VG_(threads)[tid].status == VgTs_Runnable);
sewardj5f07b662002-04-23 16:52:51 +00002932
sewardj00a66b12002-10-12 16:42:35 +00002933 VG_(threads)[tid].specifics_ptr = ptr;
sewardjc3bd5f52002-05-01 03:24:23 +00002934 SET_EDX(tid, 0);
sewardj5f07b662002-04-23 16:52:51 +00002935}
2936
2937
sewardj870497a2002-05-29 01:06:47 +00002938/* Helper for calling destructors at thread exit. If key is valid,
2939 copy the thread's specific value into cu->arg and put the *key*'s
2940 destructor fn address in cu->fn. Then return 0 to the caller.
2941 Otherwise return non-zero to the caller. */
2942static
2943void do__get_key_destr_and_spec ( ThreadId tid,
2944 pthread_key_t key,
2945 CleanupEntry* cu )
2946{
2947 Char msg_buf[100];
2948 if (VG_(clo_trace_pthread_level) >= 1) {
2949 VG_(sprintf)(msg_buf,
2950 "get_key_destr_and_arg (key = %d)", key );
2951 print_pthread_event(tid, msg_buf);
2952 }
2953 vg_assert(VG_(is_valid_tid)(tid));
2954 vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
njn25e49d8e72002-09-23 09:36:25 +00002955
sewardj870497a2002-05-29 01:06:47 +00002956 if (!vg_thread_keys[key].inuse) {
2957 SET_EDX(tid, -1);
2958 return;
2959 }
njn36650922002-10-04 09:18:09 +00002960 VG_TRACK( pre_mem_write, Vg_CorePThread, & VG_(threads)[tid],
sewardj00a66b12002-10-12 16:42:35 +00002961 "get_key_destr_and_spec: cu", (Addr)cu,
njn36650922002-10-04 09:18:09 +00002962 sizeof(CleanupEntry) );
sewardj00a66b12002-10-12 16:42:35 +00002963
sewardj870497a2002-05-29 01:06:47 +00002964 cu->fn = vg_thread_keys[key].destructor;
sewardj00a66b12002-10-12 16:42:35 +00002965 if (VG_(threads)[tid].specifics_ptr == NULL) {
2966 cu->arg = NULL;
2967 } else {
2968 VG_TRACK( pre_mem_read, Vg_CorePThread, & VG_(threads)[tid],
2969 "get_key_destr_and_spec: key",
2970 (Addr)(&VG_(threads)[tid].specifics_ptr[key]),
2971 sizeof(void*) );
2972 cu->arg = VG_(threads)[tid].specifics_ptr[key];
2973 }
2974
njn25e49d8e72002-09-23 09:36:25 +00002975 VG_TRACK( post_mem_write, (Addr)cu, sizeof(CleanupEntry) );
sewardj870497a2002-05-29 01:06:47 +00002976 SET_EDX(tid, 0);
2977}
2978
2979
sewardjb48e5002002-05-13 00:16:03 +00002980/* ---------------------------------------------------
2981 SIGNALS
2982 ------------------------------------------------ */
2983
2984/* See comment in vg_libthread.c:pthread_sigmask() regarding
sewardj018f7622002-05-15 21:13:39 +00002985 deliberate confusion of types sigset_t and vki_sigset_t. Return 0
2986 for OK and 1 for some kind of addressing error, which the
2987 vg_libpthread.c routine turns into return values 0 and EFAULT
2988 respectively. */
sewardjb48e5002002-05-13 00:16:03 +00002989static
2990void do_pthread_sigmask ( ThreadId tid,
sewardj018f7622002-05-15 21:13:39 +00002991 Int vki_how,
sewardjb48e5002002-05-13 00:16:03 +00002992 vki_ksigset_t* newmask,
2993 vki_ksigset_t* oldmask )
2994{
2995 Char msg_buf[100];
2996 if (VG_(clo_trace_pthread_level) >= 1) {
2997 VG_(sprintf)(msg_buf,
sewardj018f7622002-05-15 21:13:39 +00002998 "pthread_sigmask vki_how %d, newmask %p, oldmask %p",
2999 vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003000 print_pthread_event(tid, msg_buf);
3001 }
3002
3003 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003004 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003005
njn25e49d8e72002-09-23 09:36:25 +00003006 if (newmask)
3007 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3008 "pthread_sigmask: newmask",
3009 (Addr)newmask, sizeof(vki_ksigset_t));
3010 if (oldmask)
3011 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3012 "pthread_sigmask: oldmask",
3013 (Addr)oldmask, sizeof(vki_ksigset_t));
sewardjb48e5002002-05-13 00:16:03 +00003014
sewardj018f7622002-05-15 21:13:39 +00003015 VG_(do_pthread_sigmask_SCSS_upd) ( tid, vki_how, newmask, oldmask );
sewardjb48e5002002-05-13 00:16:03 +00003016
njn25e49d8e72002-09-23 09:36:25 +00003017 if (oldmask)
3018 VG_TRACK( post_mem_write, (Addr)oldmask, sizeof(vki_ksigset_t) );
sewardj3a951cf2002-05-15 22:25:47 +00003019
sewardj018f7622002-05-15 21:13:39 +00003020 /* Success. */
sewardjb48e5002002-05-13 00:16:03 +00003021 SET_EDX(tid, 0);
3022}
3023
3024
3025static
3026void do_sigwait ( ThreadId tid,
3027 vki_ksigset_t* set,
3028 Int* sig )
3029{
sewardj018f7622002-05-15 21:13:39 +00003030 vki_ksigset_t irrelevant_sigmask;
3031 Char msg_buf[100];
3032
sewardjb48e5002002-05-13 00:16:03 +00003033 if (VG_(clo_trace_signals) || VG_(clo_trace_sched)) {
3034 VG_(sprintf)(msg_buf,
3035 "suspend due to sigwait(): set %p, sig %p",
3036 set, sig );
3037 print_pthread_event(tid, msg_buf);
3038 }
3039
3040 vg_assert(VG_(is_valid_tid)(tid)
sewardj018f7622002-05-15 21:13:39 +00003041 && VG_(threads)[tid].status == VgTs_Runnable);
sewardjb48e5002002-05-13 00:16:03 +00003042
sewardj018f7622002-05-15 21:13:39 +00003043 /* Change SCSS */
3044 VG_(threads)[tid].sigs_waited_for = *set;
3045 VG_(threads)[tid].status = VgTs_WaitSIG;
3046
3047 VG_(block_all_host_signals)( &irrelevant_sigmask );
3048 VG_(handle_SCSS_change)( False /* lazy update */ );
3049}
3050
3051
3052static
3053void do_pthread_kill ( ThreadId tid, /* me */
3054 ThreadId thread, /* thread to signal */
3055 Int sig )
3056{
3057 Char msg_buf[100];
3058
3059 if (VG_(clo_trace_signals) || VG_(clo_trace_pthread_level) >= 1) {
3060 VG_(sprintf)(msg_buf,
3061 "pthread_kill thread %d, signo %d",
3062 thread, sig );
3063 print_pthread_event(tid, msg_buf);
3064 }
3065
3066 vg_assert(VG_(is_valid_tid)(tid)
3067 && VG_(threads)[tid].status == VgTs_Runnable);
3068
sewardj4dced352002-06-04 22:54:20 +00003069 if (!VG_(is_valid_tid)(thread)) {
njn25e49d8e72002-09-23 09:36:25 +00003070 VG_(record_pthread_error)( tid,
sewardj4dced352002-06-04 22:54:20 +00003071 "pthread_kill: invalid target thread");
sewardj018f7622002-05-15 21:13:39 +00003072 SET_EDX(tid, -VKI_ESRCH);
3073 return;
3074 }
3075
3076 if (sig < 1 || sig > VKI_KNSIG) {
3077 SET_EDX(tid, -VKI_EINVAL);
3078 return;
3079 }
3080
3081 VG_(send_signal_to_thread)( thread, sig );
3082 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00003083}
3084
3085
sewardj2cb00342002-06-28 01:46:26 +00003086/* -----------------------------------------------------------
3087 FORK HANDLERS.
3088 -------------------------------------------------------- */
3089
3090static
3091void do__set_fhstack_used ( ThreadId tid, Int n )
3092{
3093 Char msg_buf[100];
3094 if (VG_(clo_trace_sched)) {
3095 VG_(sprintf)(msg_buf, "set_fhstack_used to %d", n );
3096 print_pthread_event(tid, msg_buf);
3097 }
3098
3099 vg_assert(VG_(is_valid_tid)(tid)
3100 && VG_(threads)[tid].status == VgTs_Runnable);
3101
3102 if (n >= 0 && n < VG_N_FORKHANDLERSTACK) {
3103 vg_fhstack_used = n;
3104 SET_EDX(tid, 0);
3105 } else {
3106 SET_EDX(tid, -1);
3107 }
3108}
3109
3110
3111static
3112void do__get_fhstack_used ( ThreadId tid )
3113{
3114 Int n;
3115 Char msg_buf[100];
3116 if (VG_(clo_trace_sched)) {
3117 VG_(sprintf)(msg_buf, "get_fhstack_used" );
3118 print_pthread_event(tid, msg_buf);
3119 }
3120
3121 vg_assert(VG_(is_valid_tid)(tid)
3122 && VG_(threads)[tid].status == VgTs_Runnable);
3123
3124 n = vg_fhstack_used;
3125 vg_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
3126 SET_EDX(tid, n);
3127}
3128
3129static
3130void do__set_fhstack_entry ( ThreadId tid, Int n, ForkHandlerEntry* fh )
3131{
3132 Char msg_buf[100];
3133 if (VG_(clo_trace_sched)) {
3134 VG_(sprintf)(msg_buf, "set_fhstack_entry %d to %p", n, fh );
3135 print_pthread_event(tid, msg_buf);
3136 }
3137
3138 vg_assert(VG_(is_valid_tid)(tid)
3139 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003140 VG_TRACK( pre_mem_read, Vg_CorePThread, &VG_(threads)[tid],
3141 "pthread_atfork: prepare/parent/child",
3142 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003143
njn25e49d8e72002-09-23 09:36:25 +00003144 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003145 SET_EDX(tid, -1);
3146 return;
3147 }
3148
3149 vg_fhstack[n] = *fh;
3150 SET_EDX(tid, 0);
3151}
3152
3153
3154static
3155void do__get_fhstack_entry ( ThreadId tid, Int n, /*OUT*/
3156 ForkHandlerEntry* fh )
3157{
3158 Char msg_buf[100];
3159 if (VG_(clo_trace_sched)) {
3160 VG_(sprintf)(msg_buf, "get_fhstack_entry %d", n );
3161 print_pthread_event(tid, msg_buf);
3162 }
3163
3164 vg_assert(VG_(is_valid_tid)(tid)
3165 && VG_(threads)[tid].status == VgTs_Runnable);
njn25e49d8e72002-09-23 09:36:25 +00003166 VG_TRACK( pre_mem_write, Vg_CorePThread, &VG_(threads)[tid],
3167 "fork: prepare/parent/child",
3168 (Addr)fh, sizeof(ForkHandlerEntry));
sewardj2cb00342002-06-28 01:46:26 +00003169
njn25e49d8e72002-09-23 09:36:25 +00003170 if (n < 0 || n >= VG_N_FORKHANDLERSTACK) {
sewardj2cb00342002-06-28 01:46:26 +00003171 SET_EDX(tid, -1);
3172 return;
3173 }
3174
3175 *fh = vg_fhstack[n];
3176 SET_EDX(tid, 0);
3177
njn25e49d8e72002-09-23 09:36:25 +00003178 VG_TRACK( post_mem_write, (Addr)fh, sizeof(ForkHandlerEntry) );
sewardj2cb00342002-06-28 01:46:26 +00003179}
3180
3181
sewardje663cb92002-04-12 10:26:32 +00003182/* ---------------------------------------------------------------------
sewardj124ca2a2002-06-20 10:19:38 +00003183 Handle client requests.
sewardje663cb92002-04-12 10:26:32 +00003184 ------------------------------------------------------------------ */
3185
sewardj124ca2a2002-06-20 10:19:38 +00003186/* Do a client request for the thread tid. After the request, tid may
3187 or may not still be runnable; if not, the scheduler will have to
3188 choose a new thread to run.
3189*/
sewardje663cb92002-04-12 10:26:32 +00003190static
sewardj124ca2a2002-06-20 10:19:38 +00003191void do_client_request ( ThreadId tid )
sewardje663cb92002-04-12 10:26:32 +00003192{
njn25e49d8e72002-09-23 09:36:25 +00003193# define RETURN_WITH(vvv) \
3194 { tst->m_edx = (vvv); \
3195 tst->sh_edx = VG_(written_shadow_reg); \
sewardj124ca2a2002-06-20 10:19:38 +00003196 }
3197
3198 ThreadState* tst = &VG_(threads)[tid];
3199 UInt* arg = (UInt*)(VG_(threads)[tid].m_eax);
3200 UInt req_no = arg[0];
3201
3202 /* VG_(printf)("req no = 0x%x\n", req_no); */
sewardje663cb92002-04-12 10:26:32 +00003203 switch (req_no) {
3204
sewardj124ca2a2002-06-20 10:19:38 +00003205 case VG_USERREQ__MALLOC:
3206 RETURN_WITH(
3207 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocMalloc )
3208 );
3209 break;
3210
3211 case VG_USERREQ__BUILTIN_NEW:
3212 RETURN_WITH(
3213 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNew )
3214 );
3215 break;
3216
3217 case VG_USERREQ__BUILTIN_VEC_NEW:
3218 RETURN_WITH(
3219 (UInt)VG_(client_malloc) ( tst, arg[1], Vg_AllocNewVec )
3220 );
3221 break;
3222
3223 case VG_USERREQ__FREE:
3224 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocMalloc );
3225 RETURN_WITH(0); /* irrelevant */
3226 break;
3227
3228 case VG_USERREQ__BUILTIN_DELETE:
3229 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNew );
3230 RETURN_WITH(0); /* irrelevant */
3231 break;
3232
3233 case VG_USERREQ__BUILTIN_VEC_DELETE:
3234 VG_(client_free) ( tst, (void*)arg[1], Vg_AllocNewVec );
3235 RETURN_WITH(0); /* irrelevant */
3236 break;
3237
3238 case VG_USERREQ__CALLOC:
3239 RETURN_WITH(
3240 (UInt)VG_(client_calloc) ( tst, arg[1], arg[2] )
3241 );
3242 break;
3243
3244 case VG_USERREQ__REALLOC:
3245 RETURN_WITH(
3246 (UInt)VG_(client_realloc) ( tst, (void*)arg[1], arg[2] )
3247 );
3248 break;
3249
3250 case VG_USERREQ__MEMALIGN:
3251 RETURN_WITH(
3252 (UInt)VG_(client_memalign) ( tst, arg[1], arg[2] )
3253 );
3254 break;
3255
3256 case VG_USERREQ__PTHREAD_GET_THREADID:
3257 RETURN_WITH(tid);
3258 break;
3259
3260 case VG_USERREQ__RUNNING_ON_VALGRIND:
3261 RETURN_WITH(1);
3262 break;
3263
3264 case VG_USERREQ__GET_PTHREAD_TRACE_LEVEL:
3265 RETURN_WITH(VG_(clo_trace_pthread_level));
3266 break;
3267
3268 case VG_USERREQ__READ_MILLISECOND_TIMER:
3269 RETURN_WITH(VG_(read_millisecond_timer)());
3270 break;
3271
3272 /* Some of these may make thread tid non-runnable, but the
3273 scheduler checks for that on return from this function. */
3274 case VG_USERREQ__PTHREAD_MUTEX_LOCK:
3275 do_pthread_mutex_lock( tid, False, (void *)(arg[1]) );
3276 break;
3277
3278 case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
3279 do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
3280 break;
3281
3282 case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
3283 do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
3284 break;
3285
sewardj00a66b12002-10-12 16:42:35 +00003286 case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
3287 do_pthread_getspecific_ptr ( tid );
sewardj124ca2a2002-06-20 10:19:38 +00003288 break;
3289
3290 case VG_USERREQ__SET_CANCELTYPE:
3291 do__set_canceltype ( tid, arg[1] );
3292 break;
3293
3294 case VG_USERREQ__CLEANUP_PUSH:
3295 do__cleanup_push ( tid, (CleanupEntry*)(arg[1]) );
3296 break;
3297
3298 case VG_USERREQ__CLEANUP_POP:
3299 do__cleanup_pop ( tid, (CleanupEntry*)(arg[1]) );
3300 break;
3301
3302 case VG_USERREQ__TESTCANCEL:
3303 do__testcancel ( tid );
3304 break;
3305
3306 case VG_USERREQ__GET_N_SIGS_RETURNED:
3307 RETURN_WITH(VG_(threads)[tid].n_signals_returned);
3308 break;
3309
sewardje663cb92002-04-12 10:26:32 +00003310 case VG_USERREQ__PTHREAD_JOIN:
3311 do_pthread_join( tid, arg[1], (void**)(arg[2]) );
3312 break;
3313
sewardj3b5d8862002-04-20 13:53:23 +00003314 case VG_USERREQ__PTHREAD_COND_WAIT:
3315 do_pthread_cond_wait( tid,
3316 (pthread_cond_t *)(arg[1]),
sewardj5f07b662002-04-23 16:52:51 +00003317 (pthread_mutex_t *)(arg[2]),
3318 0xFFFFFFFF /* no timeout */ );
3319 break;
3320
3321 case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
3322 do_pthread_cond_wait( tid,
3323 (pthread_cond_t *)(arg[1]),
3324 (pthread_mutex_t *)(arg[2]),
3325 arg[3] /* timeout millisecond point */ );
sewardj3b5d8862002-04-20 13:53:23 +00003326 break;
3327
3328 case VG_USERREQ__PTHREAD_COND_SIGNAL:
3329 do_pthread_cond_signal_or_broadcast(
3330 tid,
3331 False, /* signal, not broadcast */
3332 (pthread_cond_t *)(arg[1]) );
3333 break;
3334
3335 case VG_USERREQ__PTHREAD_COND_BROADCAST:
3336 do_pthread_cond_signal_or_broadcast(
3337 tid,
3338 True, /* broadcast, not signal */
3339 (pthread_cond_t *)(arg[1]) );
3340 break;
3341
sewardj00a66b12002-10-12 16:42:35 +00003342 case VG_USERREQ__PTHREAD_KEY_VALIDATE:
3343 do_pthread_key_validate ( tid,
3344 (pthread_key_t)(arg[1]) );
3345 break;
3346
sewardj5f07b662002-04-23 16:52:51 +00003347 case VG_USERREQ__PTHREAD_KEY_CREATE:
3348 do_pthread_key_create ( tid,
3349 (pthread_key_t*)(arg[1]),
3350 (void(*)(void*))(arg[2]) );
3351 break;
3352
3353 case VG_USERREQ__PTHREAD_KEY_DELETE:
3354 do_pthread_key_delete ( tid,
3355 (pthread_key_t)(arg[1]) );
3356 break;
3357
sewardj00a66b12002-10-12 16:42:35 +00003358 case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
3359 do_pthread_setspecific_ptr ( tid,
3360 (void**)(arg[1]) );
sewardj5f07b662002-04-23 16:52:51 +00003361 break;
3362
sewardjb48e5002002-05-13 00:16:03 +00003363 case VG_USERREQ__PTHREAD_SIGMASK:
3364 do_pthread_sigmask ( tid,
3365 arg[1],
3366 (vki_ksigset_t*)(arg[2]),
3367 (vki_ksigset_t*)(arg[3]) );
3368 break;
3369
3370 case VG_USERREQ__SIGWAIT:
3371 do_sigwait ( tid,
3372 (vki_ksigset_t*)(arg[1]),
3373 (Int*)(arg[2]) );
3374 break;
3375
sewardj018f7622002-05-15 21:13:39 +00003376 case VG_USERREQ__PTHREAD_KILL:
3377 do_pthread_kill ( tid, arg[1], arg[2] );
3378 break;
3379
sewardjff42d1d2002-05-22 13:17:31 +00003380 case VG_USERREQ__PTHREAD_YIELD:
3381 do_pthread_yield ( tid );
sewardj18a62ff2002-07-12 22:30:51 +00003382 /* On return from do_client_request(), the scheduler will
3383 select a new thread to run. */
sewardjff42d1d2002-05-22 13:17:31 +00003384 break;
sewardj018f7622002-05-15 21:13:39 +00003385
sewardj7989d0c2002-05-28 11:00:01 +00003386 case VG_USERREQ__SET_CANCELSTATE:
3387 do__set_cancelstate ( tid, arg[1] );
3388 break;
3389
sewardj7989d0c2002-05-28 11:00:01 +00003390 case VG_USERREQ__SET_OR_GET_DETACH:
3391 do__set_or_get_detach ( tid, arg[1], arg[2] );
3392 break;
3393
3394 case VG_USERREQ__SET_CANCELPEND:
3395 do__set_cancelpend ( tid, arg[1], (void(*)(void*))arg[2] );
3396 break;
3397
3398 case VG_USERREQ__WAIT_JOINER:
3399 do__wait_joiner ( tid, (void*)arg[1] );
3400 break;
3401
3402 case VG_USERREQ__QUIT:
3403 do__quit ( tid );
3404 break;
3405
3406 case VG_USERREQ__APPLY_IN_NEW_THREAD:
3407 do__apply_in_new_thread ( tid, (void*(*)(void*))arg[1],
3408 (void*)arg[2] );
3409 break;
3410
sewardj870497a2002-05-29 01:06:47 +00003411 case VG_USERREQ__GET_KEY_D_AND_S:
3412 do__get_key_destr_and_spec ( tid,
3413 (pthread_key_t)arg[1],
3414 (CleanupEntry*)arg[2] );
3415 break;
3416
sewardjef037c72002-05-30 00:40:03 +00003417 case VG_USERREQ__NUKE_OTHER_THREADS:
3418 VG_(nuke_all_threads_except) ( tid );
3419 SET_EDX(tid, 0);
3420 break;
3421
sewardj4dced352002-06-04 22:54:20 +00003422 case VG_USERREQ__PTHREAD_ERROR:
njn25e49d8e72002-09-23 09:36:25 +00003423 VG_(record_pthread_error)( tid, (Char*)(arg[1]) );
sewardj4dced352002-06-04 22:54:20 +00003424 SET_EDX(tid, 0);
3425 break;
3426
sewardj2cb00342002-06-28 01:46:26 +00003427 case VG_USERREQ__SET_FHSTACK_USED:
3428 do__set_fhstack_used( tid, (Int)(arg[1]) );
3429 break;
3430
3431 case VG_USERREQ__GET_FHSTACK_USED:
3432 do__get_fhstack_used( tid );
3433 break;
3434
3435 case VG_USERREQ__SET_FHSTACK_ENTRY:
3436 do__set_fhstack_entry( tid, (Int)(arg[1]),
3437 (ForkHandlerEntry*)(arg[2]) );
3438 break;
3439
3440 case VG_USERREQ__GET_FHSTACK_ENTRY:
3441 do__get_fhstack_entry( tid, (Int)(arg[1]),
3442 (ForkHandlerEntry*)(arg[2]) );
3443 break;
3444
sewardj77e466c2002-04-14 02:29:29 +00003445 case VG_USERREQ__SIGNAL_RETURNS:
3446 handle_signal_return(tid);
3447 break;
sewardj69a72a52002-11-03 13:41:41 +00003448
3449 case VG_USERREQ__LOGMESSAGE:
3450 VG_(message)(Vg_UserMsg, "%s", (Char*)(arg[1]));
3451 break;
sewardj54cacf02002-04-12 23:24:59 +00003452
njn25e49d8e72002-09-23 09:36:25 +00003453 /* Requests from the client program */
3454
3455 case VG_USERREQ__DISCARD_TRANSLATIONS:
3456 if (VG_(clo_verbosity) > 2)
3457 VG_(printf)( "client request: DISCARD_TRANSLATIONS,"
3458 " addr %p, len %d\n",
3459 (void*)arg[1], arg[2] );
3460
3461 VG_(invalidate_translations)( arg[1], arg[2] );
3462
3463 SET_EDX( tid, 0 ); /* return value is meaningless */
3464 break;
3465
sewardje663cb92002-04-12 10:26:32 +00003466 default:
njn25e49d8e72002-09-23 09:36:25 +00003467 if (VG_(needs).client_requests) {
sewardj34042512002-10-22 04:14:35 +00003468 UInt ret;
3469
njn25e49d8e72002-09-23 09:36:25 +00003470 if (VG_(clo_verbosity) > 2)
3471 VG_(printf)("client request: code %d, addr %p, len %d\n",
3472 arg[0], (void*)arg[1], arg[2] );
3473
sewardj34042512002-10-22 04:14:35 +00003474 if (SK_(handle_client_request) ( &VG_(threads)[tid], arg, &ret ))
3475 SET_EDX(tid, ret);
njn25e49d8e72002-09-23 09:36:25 +00003476 } else {
sewardj34042512002-10-22 04:14:35 +00003477 static Bool whined = False;
3478
3479 if (!whined) {
3480 VG_(message)(Vg_UserMsg, "Warning:\n"
3481 " unhandled client request: 0x%x (%c%c+%d). Perhaps\n"
3482 " VG_(needs).client_requests should be set?\n",
3483 arg[0], (arg[0] >> 24) & 0xff, (arg[0] >> 16) & 0xff,
3484 arg[0] & 0xffff);
3485 whined = True;
3486 }
njn25e49d8e72002-09-23 09:36:25 +00003487 }
sewardje663cb92002-04-12 10:26:32 +00003488 break;
3489 }
sewardj124ca2a2002-06-20 10:19:38 +00003490
3491# undef RETURN_WITH
sewardje663cb92002-04-12 10:26:32 +00003492}
3493
3494
sewardj6072c362002-04-19 14:40:57 +00003495/* ---------------------------------------------------------------------
3496 Sanity checking.
3497 ------------------------------------------------------------------ */
3498
3499/* Internal consistency checks on the sched/pthread structures. */
3500static
3501void scheduler_sanity ( void )
3502{
sewardj3b5d8862002-04-20 13:53:23 +00003503 pthread_mutex_t* mx;
3504 pthread_cond_t* cv;
sewardj6072c362002-04-19 14:40:57 +00003505 Int i;
sewardj5f07b662002-04-23 16:52:51 +00003506
sewardj6072c362002-04-19 14:40:57 +00003507 /* VG_(printf)("scheduler_sanity\n"); */
3508 for (i = 1; i < VG_N_THREADS; i++) {
sewardj018f7622002-05-15 21:13:39 +00003509 mx = VG_(threads)[i].associated_mx;
3510 cv = VG_(threads)[i].associated_cv;
3511 if (VG_(threads)[i].status == VgTs_WaitMX) {
sewardjbf290b92002-05-01 02:28:01 +00003512 /* If we're waiting on a MX: (1) the mx is not null, (2, 3)
3513 it's actually held by someone, since otherwise this thread
3514 is deadlocked, (4) the mutex's owner is not us, since
3515 otherwise this thread is also deadlocked. The logic in
3516 do_pthread_mutex_lock rejects attempts by a thread to lock
3517 a (non-recursive) mutex which it already owns.
sewardj05553872002-04-20 20:53:17 +00003518
sewardjbf290b92002-05-01 02:28:01 +00003519 (2) has been seen to fail sometimes. I don't know why.
3520 Possibly to do with signals. */
sewardj3b5d8862002-04-20 13:53:23 +00003521 vg_assert(cv == NULL);
sewardj05553872002-04-20 20:53:17 +00003522 /* 1 */ vg_assert(mx != NULL);
3523 /* 2 */ vg_assert(mx->__m_count > 0);
sewardjb48e5002002-05-13 00:16:03 +00003524 /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__m_owner));
sewardj05553872002-04-20 20:53:17 +00003525 /* 4 */ vg_assert(i != (ThreadId)mx->__m_owner);
sewardj3b5d8862002-04-20 13:53:23 +00003526 } else
sewardj018f7622002-05-15 21:13:39 +00003527 if (VG_(threads)[i].status == VgTs_WaitCV) {
sewardj3b5d8862002-04-20 13:53:23 +00003528 vg_assert(cv != NULL);
3529 vg_assert(mx != NULL);
sewardj6072c362002-04-19 14:40:57 +00003530 } else {
sewardj05553872002-04-20 20:53:17 +00003531 /* Unfortunately these don't hold true when a sighandler is
3532 running. To be fixed. */
3533 /* vg_assert(cv == NULL); */
3534 /* vg_assert(mx == NULL); */
sewardj6072c362002-04-19 14:40:57 +00003535 }
sewardjbf290b92002-05-01 02:28:01 +00003536
sewardj018f7622002-05-15 21:13:39 +00003537 if (VG_(threads)[i].status != VgTs_Empty) {
sewardjbf290b92002-05-01 02:28:01 +00003538 Int
sewardj018f7622002-05-15 21:13:39 +00003539 stack_used = (Addr)VG_(threads)[i].stack_highest_word
3540 - (Addr)VG_(threads)[i].m_esp;
sewardjbf290b92002-05-01 02:28:01 +00003541 if (i > 1 /* not the root thread */
3542 && stack_used
3543 >= (VG_PTHREAD_STACK_MIN - 1000 /* paranoia */)) {
3544 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +00003545 "Error: STACK OVERFLOW: "
sewardjbf290b92002-05-01 02:28:01 +00003546 "thread %d: stack used %d, available %d",
3547 i, stack_used, VG_PTHREAD_STACK_MIN );
3548 VG_(message)(Vg_UserMsg,
3549 "Terminating Valgrind. If thread(s) "
3550 "really need more stack, increase");
3551 VG_(message)(Vg_UserMsg,
3552 "VG_PTHREAD_STACK_SIZE in vg_include.h and recompile.");
3553 VG_(exit)(1);
3554 }
sewardjb48e5002002-05-13 00:16:03 +00003555
sewardj018f7622002-05-15 21:13:39 +00003556 if (VG_(threads)[i].status == VgTs_WaitSIG) {
sewardjb48e5002002-05-13 00:16:03 +00003557 vg_assert( ! VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003558 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003559 } else {
3560 vg_assert( VG_(kisemptysigset)(
sewardj018f7622002-05-15 21:13:39 +00003561 & VG_(threads)[i].sigs_waited_for) );
sewardjb48e5002002-05-13 00:16:03 +00003562 }
3563
sewardjbf290b92002-05-01 02:28:01 +00003564 }
sewardj6072c362002-04-19 14:40:57 +00003565 }
sewardj5f07b662002-04-23 16:52:51 +00003566
3567 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
3568 if (!vg_thread_keys[i].inuse)
3569 vg_assert(vg_thread_keys[i].destructor == NULL);
3570 }
sewardj6072c362002-04-19 14:40:57 +00003571}
3572
3573
sewardje663cb92002-04-12 10:26:32 +00003574/*--------------------------------------------------------------------*/
3575/*--- end vg_scheduler.c ---*/
3576/*--------------------------------------------------------------------*/