Threads
A thread is a struct proc that shares three counted objects with others of its group: the address space (struct mm: page tables, heap top, VMAs and a lock for changing them), the descriptor table, and the signal dispositions. clone() shares what its flags say and fork() copies. - clone(): pthread_create's shape (VM, FILES, SIGHAND, THREAD, SETTLS, PARENT_SETTID, CHILD_CLEARTID) and posix_spawn's (VM, VFORK, a stack). - futex: WAIT, WAIT_BITSET with timeouts, WAKE, REQUEUE, CMP_REQUEUE, keyed by the word's kernel address so shared pages meet. set_tid_address keeps the word that exit zeroes and wakes, for pthread_join. - exit ends a thread; exit_group, a fatal signal, or the leader exiting ends them all. reapd frees exited threads; the leader is reaped by its parent once the rest are gone. getpid is the group, gettid the thread. - Stops and resumes reach every thread; other process signals the leader. - exec kills the other threads and unshares the dispositions. - No TLB shootdown, so pages unmapped from a shared address space are freed only once every CPU has reloaded CR3 or is idle. - procfs: /proc lists processes, task/ lists threads, comm, Threads:, Tgid. - The console honours VMIN 0 / VTIME (btop's input drain hung on it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
2372806862
commit
f4d7f9100d
19 changed files with 1300 additions and 248 deletions
|
|
@ -31,6 +31,40 @@ struct vma {
|
|||
int shmid; // shared segment this came from, or -1
|
||||
};
|
||||
|
||||
// --- What threads share ---------------------------------------------------
|
||||
//
|
||||
// A thread is a struct proc like any other, scheduled like any other. What
|
||||
// makes several of them one program is that they point at the same three
|
||||
// objects below, each counted, each freed with its last user: clone() with
|
||||
// CLONE_VM, CLONE_FILES and CLONE_SIGHAND shares them, fork() copies them.
|
||||
|
||||
// The address space. pgdir is mirrored in every struct proc that uses it,
|
||||
// because the scheduler, trapasm and half the kernel read it from there; it
|
||||
// only changes at exec, which makes a new mm.
|
||||
struct mm {
|
||||
int ref;
|
||||
int locked; // mm_lock(): one mmap/munmap/brk at a time
|
||||
uint64 sz; // top of the heap; p->sz mirrors it
|
||||
uint64 mmap_next; // next free mmap VA (bump allocator, see sys_mmap)
|
||||
pml4e_t *pgdir;
|
||||
struct vma vma[NVMA]; // VMA tracking for mmap
|
||||
};
|
||||
|
||||
// The descriptor table, and FD_CLOEXEC beside it.
|
||||
struct files {
|
||||
int ref;
|
||||
struct file *ofile[NOFILE];
|
||||
char flags[NOFILE];
|
||||
};
|
||||
|
||||
// Signal dispositions: what sigaction() sets.
|
||||
struct sighand {
|
||||
int ref;
|
||||
uint64 handler[32]; // 0 SIG_DFL, 1 SIG_IGN, else an address
|
||||
uint64 restorer[32];
|
||||
uint64 flags[32]; // sa_flags; SA_RESTART is the one read
|
||||
};
|
||||
|
||||
// Per-CPU state
|
||||
struct cpu {
|
||||
uchar id;
|
||||
|
|
@ -176,6 +210,8 @@ struct procinfo {
|
|||
char exe[64]; // full path, for /proc/<pid>/exe
|
||||
int kthread; // a kernel thread, not a program
|
||||
int stopped; // stopped by a signal (ps shows T)
|
||||
int tgid; // the process this thread belongs to
|
||||
int nthreads; // threads in that process
|
||||
};
|
||||
|
||||
struct proc {
|
||||
|
|
@ -191,7 +227,7 @@ struct proc {
|
|||
void *chan; // [+0x40]
|
||||
int killed; // [+0x48]
|
||||
int _pad; // [+0x4c]
|
||||
struct file *ofile[NOFILE]; // Open files [+0x50]
|
||||
struct files *files; // Open files, shared by threads [+0x50]
|
||||
struct inode *cwd; // follows
|
||||
char name[16]; //
|
||||
// The path exec() was given. `name` is only the last component and only 15
|
||||
|
|
@ -238,7 +274,6 @@ struct proc {
|
|||
// alarmd, in kernel/proc/proc.c, is what posts it.
|
||||
uint alarm_at;
|
||||
uint alarm_every;
|
||||
char ofile_flags[NOFILE];
|
||||
|
||||
// Real signal delivery (added for SIGCHLD — see kernel/sys/syscall.c's
|
||||
// deliver_signals() and kernel/proc/proc.c's exit()). sig_handler[sig]/
|
||||
|
|
@ -247,9 +282,7 @@ struct proc {
|
|||
// the pre-signal trapframe so sys_rt_sigreturn() can restore it; in_signal
|
||||
// prevents re-entering a handler while one is already running (we don't
|
||||
// support nested signal delivery).
|
||||
uint64 sig_handler[32];
|
||||
uint64 sig_restorer[32];
|
||||
uint64 sig_flags[32]; // sa_flags; SA_RESTART is the one read
|
||||
struct sighand *sighand; // dispositions, shared by threads
|
||||
struct trapframe saved_sigtf;
|
||||
int in_signal;
|
||||
|
||||
|
|
@ -260,8 +293,7 @@ struct proc {
|
|||
uint64 sigsusp_oldmask;
|
||||
int sigsusp_active;
|
||||
|
||||
struct vma vma[NVMA]; // VMA tracking for mmap
|
||||
uint64 mmap_next; // next free mmap VA (bump allocator, see sys_mmap)
|
||||
struct mm *mm; // address space, shared by threads
|
||||
|
||||
// ABI translation (Linux compat syscall number map)
|
||||
int *syscall_map;
|
||||
|
|
@ -339,6 +371,19 @@ struct proc {
|
|||
int stopsig;
|
||||
int stop_report;
|
||||
int cont_report;
|
||||
|
||||
// Threads. tgid is the pid of the thread group's leader -- what getpid()
|
||||
// returns -- and equal to pid for every ordinary process.
|
||||
int tgid;
|
||||
uint64 clear_child_tid; // CLONE_CHILD_CLEARTID: zeroed and woken at exit
|
||||
void *futex_key; // the futex word this thread waits on, or 0
|
||||
int futex_woken;
|
||||
int autoreap; // a thread: reapd frees it, nobody waits for it
|
||||
struct proc *vfork_parent; // CLONE_VFORK: released at exec or exit
|
||||
int vfork_wait; // the vfork child this process is waiting on
|
||||
int thread_dying; // killed with its group: exits as a thread
|
||||
int group_status; // a thread's exit_group status, for the leader
|
||||
int group_status_set;
|
||||
};
|
||||
#define FD_CLOEXEC 1
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue