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
|
|
@ -24,13 +24,27 @@ addr_t sys_wait(void) { return wait(); }
|
|||
// wait() reports back through WEXITSTATUS.
|
||||
addr_t
|
||||
sys_exit(void)
|
||||
{
|
||||
int code = 0;
|
||||
argint(0, &code);
|
||||
// Linux's exit is one thread's: pthread_exit, and a thread returning
|
||||
// from its start function. The program ends with exit_group -- or here,
|
||||
// when this is the last thread, or the native ABI, which has no threads.
|
||||
struct proc *p = myproc();
|
||||
if (p->syscall_map && p->tgid != p->pid && proc_thread_count(p->tgid) > 1)
|
||||
thread_exit();
|
||||
exit(W_EXITCODE(code, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_exit_group(void)
|
||||
{
|
||||
int code = 0;
|
||||
argint(0, &code);
|
||||
exit(W_EXITCODE(code, 0));
|
||||
return 0;
|
||||
}
|
||||
addr_t sys_exit_group(void) { return sys_exit(); }
|
||||
|
||||
|
||||
addr_t
|
||||
|
|
@ -62,9 +76,10 @@ sys_kill(void)
|
|||
// Defined with getrusage() further down; wait4() needs it too.
|
||||
static void rusage_fill(struct rusage *ru, uint64 ut, uint64 st);
|
||||
|
||||
addr_t sys_getpid(void) { return myproc()->pid; }
|
||||
addr_t sys_getppid(void) { return myproc()->parent ? myproc()->parent->pid : 1; }
|
||||
addr_t sys_gettid(void) { return myproc()->pid; } // single-threaded: tid == pid
|
||||
// A process is its thread group: getpid is the group's id, gettid the thread's.
|
||||
addr_t sys_getpid(void) { return myproc()->tgid; }
|
||||
addr_t sys_getppid(void) { return myproc()->parent ? myproc()->parent->tgid : 1; }
|
||||
addr_t sys_gettid(void) { return myproc()->pid; }
|
||||
|
||||
addr_t
|
||||
sys_waitpid(void)
|
||||
|
|
@ -122,11 +137,13 @@ sys_wait4(void)
|
|||
addr_t
|
||||
sys_clone(void)
|
||||
{
|
||||
int flags;
|
||||
argint(0, &flags);
|
||||
if (flags & (CLONE_VM | CLONE_THREAD | CLONE_SIGHAND))
|
||||
return -ENOSYS;
|
||||
return fork();
|
||||
uint64 flags, stack, ptid, ctid, tls;
|
||||
argaddr(0, &flags);
|
||||
argaddr(1, &stack);
|
||||
argaddr(2, &ptid);
|
||||
argaddr(3, &ctid);
|
||||
argaddr(4, &tls);
|
||||
return clone_proc(flags, stack, ptid, ctid, tls);
|
||||
}
|
||||
|
||||
addr_t
|
||||
|
|
@ -424,10 +441,11 @@ addr_t sys_tgkill(void)
|
|||
{
|
||||
int tgid, tid, sig;
|
||||
argint(0, &tgid); argint(1, &tid); argint(2, &sig);
|
||||
// In our single-threaded model tgid == tid == pid.
|
||||
if (tgid <= 0) return 0;
|
||||
if (sig == 0) return proc_exists(tgid) ? 0 : -ESRCH;
|
||||
return sigsend(tgid, sig) < 0 ? -ESRCH : 0;
|
||||
// To one thread: musl's pthread_kill, and raise(), which is tgkill on
|
||||
// the calling thread.
|
||||
if (tid <= 0) return -EINVAL;
|
||||
if (sig == 0) return proc_exists(tid) ? 0 : -ESRCH;
|
||||
return sigsend(tid, sig) < 0 ? -ESRCH : 0;
|
||||
}
|
||||
|
||||
addr_t sys_tkill(void)
|
||||
|
|
|
|||
Loading…
Reference in a new issue