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 @@ argfd(int n, int *pfd, struct file **pf)
|
|||
struct file *f;
|
||||
if (argint(n, &fd) < 0)
|
||||
return -1;
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->ofile[fd]))
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd]))
|
||||
return -1;
|
||||
if (pfd) *pfd = fd;
|
||||
if (pf) *pf = f;
|
||||
|
|
@ -155,13 +155,18 @@ argfd(int n, int *pfd, struct file **pf)
|
|||
int
|
||||
fdalloc(struct file *f)
|
||||
{
|
||||
// Locked: threads share the table, and two picking the same empty slot
|
||||
// would each believe they owned it.
|
||||
files_lock();
|
||||
for (int fd = 0; fd < NOFILE; fd++) {
|
||||
if (!myproc()->ofile[fd]) {
|
||||
myproc()->ofile[fd] = f;
|
||||
myproc()->ofile_flags[fd] = 0;
|
||||
if (!myproc()->files->ofile[fd]) {
|
||||
myproc()->files->ofile[fd] = f;
|
||||
myproc()->files->flags[fd] = 0;
|
||||
files_unlock();
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
files_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +183,7 @@ file_setpath(struct file *f, int dirfd, const char *path)
|
|||
struct file *d;
|
||||
if (dirfd == AT_FDCWD)
|
||||
base = myproc()->cwd_path;
|
||||
else if (dirfd >= 0 && dirfd < NOFILE && (d = myproc()->ofile[dirfd]) && d->path)
|
||||
else if (dirfd >= 0 && dirfd < NOFILE && (d = myproc()->files->ofile[dirfd]) && d->path)
|
||||
base = d->path;
|
||||
else
|
||||
return;
|
||||
|
|
@ -218,8 +223,8 @@ static struct inode *
|
|||
at_dir(int dirfd)
|
||||
{
|
||||
if (dirfd == AT_FDCWD) return myproc()->cwd;
|
||||
if (dirfd < 0 || dirfd >= NOFILE || !myproc()->ofile[dirfd]) return 0;
|
||||
struct file *f = myproc()->ofile[dirfd];
|
||||
if (dirfd < 0 || dirfd >= NOFILE || !myproc()->files->ofile[dirfd]) return 0;
|
||||
struct file *f = myproc()->files->ofile[dirfd];
|
||||
if (f->type != FD_INODE) return 0;
|
||||
return f->ip;
|
||||
}
|
||||
|
|
@ -393,12 +398,12 @@ addr_t sys_dup2(void)
|
|||
int oldfd, newfd;
|
||||
struct file *f;
|
||||
if (argint(0, &oldfd) < 0 || argint(1, &newfd) < 0) return -1;
|
||||
if (oldfd < 0 || oldfd >= NOFILE || !(f = myproc()->ofile[oldfd])) return -EBADF;
|
||||
if (oldfd < 0 || oldfd >= NOFILE || !(f = myproc()->files->ofile[oldfd])) return -EBADF;
|
||||
if (newfd < 0 || newfd >= NOFILE) return -EBADF;
|
||||
if (oldfd == newfd) return newfd;
|
||||
if (myproc()->ofile[newfd]) fileclose(myproc()->ofile[newfd]);
|
||||
myproc()->ofile[newfd] = filedup(f);
|
||||
myproc()->ofile_flags[newfd] = 0; // dup2 never carries FD_CLOEXEC over
|
||||
if (myproc()->files->ofile[newfd]) fileclose(myproc()->files->ofile[newfd]);
|
||||
myproc()->files->ofile[newfd] = filedup(f);
|
||||
myproc()->files->flags[newfd] = 0; // dup2 never carries FD_CLOEXEC over
|
||||
return newfd;
|
||||
}
|
||||
|
||||
|
|
@ -412,9 +417,9 @@ addr_t sys_dup3(void)
|
|||
// Unlike dup2, equal fds are an error (dup3(2)). Without this check we
|
||||
// would fileclose(f) and then filedup() the file we just released.
|
||||
if (oldfd == newfd) return -EINVAL;
|
||||
if (myproc()->ofile[newfd]) fileclose(myproc()->ofile[newfd]);
|
||||
myproc()->ofile[newfd] = filedup(f);
|
||||
myproc()->ofile_flags[newfd] = 0;
|
||||
if (myproc()->files->ofile[newfd]) fileclose(myproc()->files->ofile[newfd]);
|
||||
myproc()->files->ofile[newfd] = filedup(f);
|
||||
myproc()->files->flags[newfd] = 0;
|
||||
return newfd;
|
||||
}
|
||||
|
||||
|
|
@ -423,8 +428,8 @@ addr_t sys_close(void)
|
|||
int fd;
|
||||
struct file *f;
|
||||
if (argfd(0, &fd, &f) < 0) return -EBADF;
|
||||
myproc()->ofile[fd] = 0;
|
||||
myproc()->ofile_flags[fd] = 0;
|
||||
myproc()->files->ofile[fd] = 0;
|
||||
myproc()->files->flags[fd] = 0;
|
||||
lock_close_fd(f);
|
||||
fileclose(f);
|
||||
return 0;
|
||||
|
|
@ -444,23 +449,23 @@ sys_fcntl(void)
|
|||
{
|
||||
int fd, cmd, arg;
|
||||
if (argint(0, &fd) < 0 || argint(1, &cmd) < 0 || argint(2, &arg) < 0) return -1;
|
||||
if (fd < 0 || fd >= NOFILE || !myproc()->ofile[fd]) return -1;
|
||||
struct file *f = myproc()->ofile[fd];
|
||||
if (fd < 0 || fd >= NOFILE || !myproc()->files->ofile[fd]) return -1;
|
||||
struct file *f = myproc()->files->ofile[fd];
|
||||
switch (cmd) {
|
||||
case F_DUPFD:
|
||||
case F_DUPFD_CLOEXEC: {
|
||||
if (arg < 0) return -EINVAL;
|
||||
for (int nfd = arg; nfd < NOFILE; nfd++) {
|
||||
if (!myproc()->ofile[nfd]) {
|
||||
myproc()->ofile[nfd] = filedup(f);
|
||||
myproc()->ofile_flags[nfd] = (cmd == F_DUPFD_CLOEXEC) ? FD_CLOEXEC : 0;
|
||||
if (!myproc()->files->ofile[nfd]) {
|
||||
myproc()->files->ofile[nfd] = filedup(f);
|
||||
myproc()->files->flags[nfd] = (cmd == F_DUPFD_CLOEXEC) ? FD_CLOEXEC : 0;
|
||||
return nfd;
|
||||
}
|
||||
}
|
||||
return -EMFILE;
|
||||
}
|
||||
case F_GETFD: return myproc()->ofile_flags[fd];
|
||||
case F_SETFD: myproc()->ofile_flags[fd] = arg; return 0;
|
||||
case F_GETFD: return myproc()->files->flags[fd];
|
||||
case F_SETFD: myproc()->files->flags[fd] = arg; return 0;
|
||||
case F_GETFL: {
|
||||
int flags = 0;
|
||||
if (f->readable && f->writable) flags = O_RDWR;
|
||||
|
|
@ -592,7 +597,7 @@ addr_t sys_pipe(void)
|
|||
int fd0 = -1, fd1;
|
||||
if (argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0 || pipealloc(&rf, &wf) < 0) return -1;
|
||||
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
|
||||
if (fd0 >= 0) myproc()->ofile[fd0] = 0;
|
||||
if (fd0 >= 0) myproc()->files->ofile[fd0] = 0;
|
||||
fileclose(rf); fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -614,14 +619,14 @@ addr_t sys_pipe2(void)
|
|||
if (!fds || pipealloc(&rf, &wf) < 0) return -1;
|
||||
fd0 = fd1 = -1;
|
||||
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
|
||||
if (fd0 >= 0) myproc()->ofile[fd0] = 0;
|
||||
if (fd0 >= 0) myproc()->files->ofile[fd0] = 0;
|
||||
fileclose(rf); fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
rf->nonblock = wf->nonblock = (flags & O_NONBLOCK) != 0;
|
||||
if (flags & O_CLOEXEC) {
|
||||
myproc()->ofile_flags[fd0] |= FD_CLOEXEC;
|
||||
myproc()->ofile_flags[fd1] |= FD_CLOEXEC;
|
||||
myproc()->files->flags[fd0] |= FD_CLOEXEC;
|
||||
myproc()->files->flags[fd1] |= FD_CLOEXEC;
|
||||
}
|
||||
fds[0] = fd0; fds[1] = fd1;
|
||||
return 0;
|
||||
|
|
@ -1518,7 +1523,7 @@ addr_t sys_ioctl(void)
|
|||
|
||||
if (f->type != FD_INODE || !f->ip || !f->writable)
|
||||
return -EBADF;
|
||||
if (sfd < 0 || sfd >= NOFILE || (sf = pr->ofile[sfd]) == 0)
|
||||
if (sfd < 0 || sfd >= NOFILE || (sf = pr->files->ofile[sfd]) == 0)
|
||||
return -EBADF;
|
||||
if (sf->type != FD_INODE || !sf->ip || !sf->readable)
|
||||
return -EBADF;
|
||||
|
|
@ -2344,8 +2349,8 @@ addr_t sys_fstatat(void)
|
|||
|
||||
// AT_EMPTY_PATH: if path is empty, fstat the dirfd itself.
|
||||
if ((flags & AT_EMPTY_PATH) && path[0] == '\0') {
|
||||
if (dirfd < 0 || dirfd >= NOFILE || !myproc()->ofile[dirfd]) return -1;
|
||||
struct file *f = myproc()->ofile[dirfd];
|
||||
if (dirfd < 0 || dirfd >= NOFILE || !myproc()->files->ofile[dirfd]) return -1;
|
||||
struct file *f = myproc()->files->ofile[dirfd];
|
||||
if (f->type != FD_INODE) return -1;
|
||||
ilock(f->ip);
|
||||
if (myproc()->syscall_map) stati_linux(f->ip, (struct linux_stat*)st);
|
||||
|
|
|
|||
Loading…
Reference in a new issue