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
|
|
@ -143,7 +143,7 @@ ev_open(struct evobj *o, int flags, int readable, int writable)
|
|||
return -EMFILE;
|
||||
}
|
||||
if (flags & O_CLOEXEC)
|
||||
myproc()->ofile_flags[fd] |= FD_CLOEXEC;
|
||||
myproc()->files->flags[fd] |= FD_CLOEXEC;
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ ev_arg(int n, int kind, struct file **pf)
|
|||
{
|
||||
int fd;
|
||||
struct file *f;
|
||||
if (argint(n, &fd) < 0 || fd < 0 || fd >= NOFILE || !(f = myproc()->ofile[fd]))
|
||||
if (argint(n, &fd) < 0 || fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd]))
|
||||
return 0;
|
||||
if (f->type != FD_EVENT || f->ev->kind != kind)
|
||||
return 0;
|
||||
|
|
@ -497,7 +497,7 @@ signalfd_common(int fd, addr_t umask, uint64 size, int flags)
|
|||
// An existing signalfd: change its mask, keep the descriptor.
|
||||
if (fd != -1) {
|
||||
struct file *f;
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->ofile[fd]) ||
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd]) ||
|
||||
f->type != FD_EVENT || f->ev->kind != EV_SIGNALFD)
|
||||
return -EINVAL;
|
||||
acquiresleep(&f->ev->lock);
|
||||
|
|
@ -606,9 +606,9 @@ sys_epoll_ctl(void)
|
|||
return -EBADF;
|
||||
if (argint(1, &op) < 0 || argint(2, &fd) < 0 || argaddr(3, &uev) < 0)
|
||||
return -EINVAL;
|
||||
if (fd < 0 || fd >= NOFILE || !myproc()->ofile[fd])
|
||||
if (fd < 0 || fd >= NOFILE || !myproc()->files->ofile[fd])
|
||||
return -EBADF;
|
||||
struct file *tf = myproc()->ofile[fd];
|
||||
struct file *tf = myproc()->files->ofile[fd];
|
||||
// A set cannot watch itself. (Nor contain a set that contains it; that
|
||||
// check is the deep one Linux does, and nothing here builds such loops.)
|
||||
if (tf == ef)
|
||||
|
|
@ -662,7 +662,7 @@ ep_ready(struct evobj *o, struct epoll_event *out, int max)
|
|||
acquiresleep(&o->lock);
|
||||
for (int i = 0; i < o->ep.n && got < max; ) {
|
||||
struct epitem *it = &o->ep.items[i];
|
||||
struct file *now = (it->fd >= 0 && it->fd < NOFILE) ? myproc()->ofile[it->fd] : 0;
|
||||
struct file *now = (it->fd >= 0 && it->fd < NOFILE) ? myproc()->files->ofile[it->fd] : 0;
|
||||
if (now != it->f) {
|
||||
ep_drop(o, i); // closed: it leaves the set
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Reference in a new issue