aboutsummaryrefslogtreecommitdiff
path: root/coregrind/pub_core_threadstate.h
blob: d2aa2514c68b6b8ee69346d4dee40556a49b6f5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

/*--------------------------------------------------------------------*/
/*--- The thread state.                     pub_core_threadstate.h ---*/
/*--------------------------------------------------------------------*/

/*
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.

   Copyright (C) 2000-2015 Julian Seward
      jseward@acm.org

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.

   The GNU General Public License is contained in the file COPYING.
*/

#ifndef __PUB_CORE_THREADSTATE_H
#define __PUB_CORE_THREADSTATE_H

//--------------------------------------------------------------------
// PURPOSE: This module defines the ThreadState type and the
// VG_(threads)[] data structure which holds all the important thread
// state.  It also defines some simple operations on the data structure
// that don't require any external help.  (m_scheduler does the complex
// stuff).
//--------------------------------------------------------------------

#include "pub_tool_threadstate.h"
#include "pub_core_libcsetjmp.h"   // VG_MINIMAL_JMP_BUF
#include "pub_core_vki.h"          // vki_sigset_t
#include "pub_core_guest.h"        // VexGuestArchState
#include "libvex.h"                // LibVEX_N_SPILL_BYTES


/*------------------------------------------------------------*/
/*--- Types                                                ---*/
/*------------------------------------------------------------*/

/* 
   Thread state machine:

   Empty -> Init -> Runnable <=> WaitSys/Yielding
     ^                 |
     \---- Zombie -----/		       
 */
typedef
   enum ThreadStatus { 
      VgTs_Empty,      /* this slot is not in use */
      VgTs_Init,       /* just allocated */
      VgTs_Runnable,   /* ready to run */
      VgTs_WaitSys,    /* waiting for a syscall to complete */
      VgTs_Yielding,   /* temporarily yielding the CPU */
      VgTs_Zombie,     /* transient state just before exiting */
   }
   ThreadStatus;

/* Return codes from the scheduler. */
typedef
   enum { 
      VgSrc_None,	 /* not exiting yet */
      VgSrc_ExitThread,  /* just this thread is exiting */
      VgSrc_ExitProcess, /* this thread is exiting due to another thread
                            calling exit() */
      VgSrc_FatalSig	 /* Killed by the default action of a fatal
			    signal */
   }
   VgSchedReturnCode;


/* Forward declarations */
struct SyscallStatus;
struct SyscallArgs;

/* Architecture-specific thread state */
typedef 
   struct {
      /* --- BEGIN vex-mandated guest state --- */

      /* Note that for code generation reasons, we require that the
         guest state area, its two shadows, and the spill area, are
         aligned on LibVEX_GUEST_STATE_ALIGN and have sizes, such that
         there are no holes in between. This is checked by do_pre_run_checks()
         in scheduler.c. */

      /* Saved machine context. */
      VexGuestArchState vex __attribute__((aligned(LibVEX_GUEST_STATE_ALIGN)));

      /* Saved shadow context (2 copies). */
      VexGuestArchState vex_shadow1
                        __attribute__((aligned(LibVEX_GUEST_STATE_ALIGN)));
      VexGuestArchState vex_shadow2 
                        __attribute__((aligned(LibVEX_GUEST_STATE_ALIGN)));

      /* Spill area. */
      UChar vex_spill[LibVEX_N_SPILL_BYTES]
            __attribute__((aligned(LibVEX_GUEST_STATE_ALIGN)));

      /* --- END vex-mandated guest state --- */
   } 
   ThreadArchState;


/* OS-specific thread state.  IMPORTANT: if you add fields to this,
   you _must_ add code to os_state_clear() to initialise those
   fields. */
typedef
   struct {
      /* who we are */
      Int lwpid;        // PID of kernel task  (Darwin: Mach thread)
      Int threadgroup;  // thread group id

      ThreadId parent;  // parent tid (if any)

      /* runtime details */
      Addr valgrind_stack_base;    // Valgrind's stack (VgStack*)
      Addr valgrind_stack_init_SP; // starting value for SP

      /* exit details */
      Word exitcode; // in the case of exitgroup, set by someone else
      Int  fatalsig; // fatal signal

#     if defined(VGO_darwin)
      // Mach trap POST handler as chosen by PRE
      void (*post_mach_trap_fn)(ThreadId tid,
                                struct SyscallArgs *, struct SyscallStatus *);
    
      // This thread's pthread
      Addr pthread;
    
      // Argument passed when thread started
      Addr func_arg;

      // Synchronization between child thread and parent thread's POST wrapper
      semaphore_t child_go;
      semaphore_t child_done;

      // Workqueue re-entry 
      // (setjmp in PRE(workq_ops), longjmp in wqthread_hijack)
      // DDD: JRS fixme: this comment is no longer correct; wq_jmpbuf is
      // never used, and there is no such setjmp or longjmp pair.
      // I guess we could leave wq_jmpbuf_valid in place though, since
      // it does allow for an assertion in ML_(wqthread_continue_NORETURN).
      Bool wq_jmpbuf_valid;
      //jmp_buf wq_jmpbuf;

      // Values saved from transient Mach RPC messages
      Addr remote_port;  // destination for original message
      Int msgh_id;       // outgoing message id
      union {
         struct {
            Addr port;
         } mach_port;
         struct {
            Int right;
         } mach_port_allocate;
         struct {
            Addr port;
            Int right;
            Int delta;
         } mach_port_mod_refs;
         struct {
            Addr task;
            Addr name;
            Int disposition;
         } mach_port_insert_right;
         struct {
            Addr size;
            int flags;
         } vm_allocate;
         struct {
            Addr address;
            Addr size;
         } vm_deallocate;
         struct {
            Addr src;
            Addr dst;
            Addr size;
         } vm_copy;
         struct {
            Addr address;
            Addr size;
            int set_maximum;
            UWord new_protection;
         } vm_protect;
         struct {
            Addr addr;
            SizeT size;
         } vm_read;
         struct {
            ULong addr;
            ULong size;
         } mach_vm_read;
         struct {
            Addr addr;
            SizeT size;
            Addr data;
         } vm_read_overwrite;
         struct {
            Addr size;
            int copy;
            UWord protection;
         } vm_map;
         struct {
            Addr size;
         } vm_remap;
         struct {
            ULong size;
            int flags;
         } mach_vm_allocate;
         struct {
            ULong address;
            ULong size;
         } mach_vm_deallocate;
         struct {
            ULong address;
            ULong size;
            int set_maximum;
            unsigned int new_protection;
         } mach_vm_protect;
         struct {
            ULong size;
            int copy;
            UWord protection;
         } mach_vm_map;
         struct {
            ULong size;
            int copy;
         } mach_vm_remap;
         struct {
            Addr thread;
            UWord flavor;
         } thread_get_state;
         struct {
            Addr address;
         } io_connect_unmap_memory;
         struct {
            int which_port;
         } task_get_special_port;
         struct {
            int which;
         } host_get_special_port;
         struct {
            char *service_name;
         } bootstrap_look_up;
         struct {
            vki_size_t size;
         } WindowServer_29828;
         struct {
            Int access_rights;
         } WindowServer_29831;
         struct {
            char *path;
         } io_registry_entry_from_path;
      } mach_args;

#     elif defined(VGO_solaris)
#     if defined(VGP_x86_solaris)
      /* A pointer to thread related data. The pointer is used to set up
         a segment descriptor (GDT[VKI_GDT_LWPGS]) when the thread is about to
         be run. A client program sets this value explicitly by calling the
         lwp_private syscall or it can be passed as a part of ucontext_t when
         a new thread is created (the lwp_create syscall). */
      Addr thrptr;
#     elif defined(VGP_amd64_solaris)
      /* GDT is not fully simulated by AMD64/Solaris. The %fs segment
         register is assumed to be always zero and vex->guest_FS_CONST holds
         the 64-bit offset associated with a %fs value of zero. */
#     endif

      /* Stack id (value (UWord)(-1) means that there is no stack). This
         tracks a stack that is set in restore_stack(). */
      UWord stk_id;

      /* Simulation of the kernel's lwp->lwp_ustack. Set in the PRE wrapper
         of the getsetcontext syscall, for SETUSTACK. Used in
         VG_(save_context)(), VG_(restore_context)() and
         VG_(sigframe_create)(). */
      vki_stack_t *ustack;

      /* Flag saying if the current call is in the door_return() variant of
         the door() syscall. */
      Bool in_door_return;

      /* Address of the door server procedure corresponding to the current
         thread. Used to keep track which door call the current thread
         services. Valid only between subsequent door_return() invocations. */
      Addr door_return_procedure;

      /* Simulation of the kernel's lwp->lwp_oldcontext. Set in
         VG_(restore_context)() and VG_(sigframe_create)(). Used in
         VG_(save_context)(). */
      vki_ucontext_t *oldcontext;

      /* Address of sc_shared_t struct shared between kernel and libc.
         Set in POST(sys_schedctl). Every thread gets its own address
         but typically many are squeezed on a singled mapped page.
         Cleaned in the child atfork handler. */
      Addr schedctl_data;

      /* True if this is daemon thread. */
      Bool daemon_thread;
#     endif

   }
   ThreadOSstate;


/* Overall thread state */
typedef struct {
   /* ThreadId == 0 (and hence vg_threads[0]) is NEVER USED.
      The thread identity is simply the index in vg_threads[].
      ThreadId == 1 is the root thread and has the special property
      that we don't try and allocate or deallocate its stack.  For
      convenience of generating error message, we also put the
      ThreadId in this tid field, but be aware that it should
      ALWAYS == the index in vg_threads[]. */
   ThreadId tid;

   /* Current scheduling status. */
   ThreadStatus status;

   /* This is set if the thread is in the process of exiting for any
      reason.  The precise details of the exit are in the OS-specific
      state. */
   VgSchedReturnCode exitreason;

   /* Architecture-specific thread state. */
   ThreadArchState arch;

   /* This thread's blocked-signals mask.  Semantics is that for a
      signal to be delivered to this thread, the signal must not be
      blocked by this signal mask.  If more than one thread accepts a
      signal, then it will be delivered to one at random.  If all
      threads block the signal, it will remain pending until either a
      thread unblocks it or someone uses sigwaitsig/sigtimedwait. */
   vki_sigset_t sig_mask;

   /* tmp_sig_mask is usually the same as sig_mask, and is kept in
      sync whenever sig_mask is changed.  The only time they have
      different values is during the execution of a sigsuspend, where
      tmp_sig_mask is the temporary mask which sigsuspend installs.
      It is only consulted to compute the signal mask applied to a
      signal handler. */
   vki_sigset_t tmp_sig_mask;

   /* A little signal queue for signals we can't get the kernel to
      queue for us.  This is only allocated as needed, since it should
      be rare. */
   struct SigQueue *sig_queue;

   /* Client stacks.  When a thread slot is freed, we don't deallocate its
      stack; we just leave it lying around for the next use of the
      slot.  If the next use of the slot requires a larger stack,
      only then is the old one deallocated and a new one
      allocated. 

      For the main thread (threadid == 1), this mechanism doesn't
      apply.  We don't know the size of the stack since we didn't
      allocate it, and furthermore we never reallocate it. */

   /* The allocated size of this thread's stack */
   SizeT client_stack_szB;

   /* Address of the highest legitimate byte in this stack.  This is
      used for error messages only -- not critical for execution
      correctness.  Is is set for all stacks, specifically including
      ThreadId == 1 (the main thread). */
   Addr client_stack_highest_byte;

   /* Alternate signal stack */
   vki_stack_t altstack;

   /* OS-specific thread state */
   ThreadOSstate os_state;

   /* Error disablement level.  A counter which allows selectively
      disabling error reporting in threads.  When zero, reporting is
      enabled.  When nonzero, it is disabled.  This is controlled by
      the client request 'VG_USERREQ__CHANGE_ERR_DISABLEMENT'.  New
      threads are always created with this as zero (errors
      enabled). */
   UInt err_disablement_level;

   /* Per-thread jmp_buf to resume scheduler after a signal */
   Bool               sched_jmpbuf_valid;
   VG_MINIMAL_JMP_BUF(sched_jmpbuf);

   /* This thread's name. NULL, if no name. */
   HChar *thread_name;
}
ThreadState;


/*------------------------------------------------------------*/
/*--- The thread table.                                    ---*/
/*------------------------------------------------------------*/

/* A statically allocated array of threads.  NOTE: [0] is
   never used, to simplify the simulation of initialisers for
   LinuxThreads. */
extern ThreadState *VG_(threads);

// The running thread.  m_scheduler should be the only other module
// to write to this.
extern ThreadId VG_(running_tid);


/*------------------------------------------------------------*/
/*--- Basic operations on the thread table.                ---*/
/*------------------------------------------------------------*/

/* Initialize the m_threadstate module. */
void VG_(init_Threads)(void);

// Convert a ThreadStatus to a string.
const HChar* VG_(name_of_ThreadStatus) ( ThreadStatus status );

// Convert a VgSchedReturnCode to a string.
const HChar* VG_(name_of_VgSchedReturnCode) ( VgSchedReturnCode retcode );

/* Get the ThreadState for a particular thread */
extern ThreadState *VG_(get_ThreadState) ( ThreadId tid );

/* Check that tid is in range and denotes a non-Empty thread. */
extern Bool VG_(is_valid_tid) ( ThreadId tid );

/* Returns true if a thread is currently running (ie, has the CPU lock) */
extern Bool VG_(is_running_thread)(ThreadId tid);

/* Returns true if the thread is in the process of exiting */
extern Bool VG_(is_exiting)(ThreadId tid);

/* Return the number of non-dead Threads */
extern Int VG_(count_living_threads)(void);

/* Return the number of threads in VgTs_Runnable state */
extern Int VG_(count_runnable_threads)(void);

/* Given an LWP id (ie, real kernel thread id), find the corresponding
   ThreadId */
extern ThreadId VG_(lwpid_to_vgtid)(Int lwpid);

#endif   // __PUB_CORE_THREADSTATE_H

/*--------------------------------------------------------------------*/
/*--- end                                                          ---*/
/*--------------------------------------------------------------------*/