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
|
|
@ -32,10 +32,12 @@ sys_enable_linux_abi(void)
|
|||
addr_t
|
||||
sys_set_tid_address(void)
|
||||
{
|
||||
// The word zeroed and woken when this thread exits -- what pthread_join
|
||||
// waits on. It used to be *written*, with the tid, which is CHILD_SETTID's
|
||||
// job and not this one's.
|
||||
addr_t tidp;
|
||||
argaddr(0, &tidp);
|
||||
if (tidp)
|
||||
put_user(myproc()->pid, tidp);
|
||||
myproc()->clear_child_tid = tidp;
|
||||
return myproc()->pid;
|
||||
}
|
||||
|
||||
|
|
@ -46,12 +48,15 @@ addr_t sys_set_robust_list(void) { return 0; }
|
|||
addr_t
|
||||
sys_futex(void)
|
||||
{
|
||||
int op;
|
||||
addr_t uaddr, utime, uaddr2;
|
||||
int op, val, val3;
|
||||
argaddr(0, &uaddr);
|
||||
argint(1, &op);
|
||||
op &= ~(FUTEX_WAIT_PRIVATE - FUTEX_WAIT);
|
||||
if (op == FUTEX_WAKE || op == FUTEX_WAKE_PRIVATE)
|
||||
return 0;
|
||||
return -EAGAIN; // no blocking, musl retries
|
||||
argint(2, &val);
|
||||
argaddr(3, &utime);
|
||||
argaddr(4, &uaddr2);
|
||||
argint(5, &val3);
|
||||
return futex_op(uaddr, op, val, utime, uaddr2, val3);
|
||||
}
|
||||
|
||||
// arch_prctl: save FS_BASE for TLS.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ static struct vma *
|
|||
vma_free_slot(struct proc *p)
|
||||
{
|
||||
for (int i = 0; i < NVMA; i++)
|
||||
if (!p->vma[i].used)
|
||||
return &p->vma[i];
|
||||
if (!p->mm->vma[i].used)
|
||||
return &p->mm->vma[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ static int
|
|||
vma_note_anon(struct proc *p, uint64 va, uint64 len)
|
||||
{
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
if (vma_anon(v) && v->addr + v->length == va) {
|
||||
v->length += len;
|
||||
return 0;
|
||||
|
|
@ -81,7 +81,7 @@ static int
|
|||
range_free(struct proc *p, uint64 va, uint64 len)
|
||||
{
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
if (v->used && va < v->addr + v->length && v->addr < va + len)
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -104,21 +104,21 @@ range_free(struct proc *p, uint64 va, uint64 len)
|
|||
static uint64
|
||||
mmap_va(struct proc *p, uint64 len, int mergeable)
|
||||
{
|
||||
if (p->mmap_next == 0)
|
||||
p->mmap_next = 0x40000000;
|
||||
if (p->mm->mmap_next == 0)
|
||||
p->mm->mmap_next = 0x40000000;
|
||||
if (mergeable) {
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
uint64 e = v->addr + v->length;
|
||||
if (vma_anon(v) && e >= 0x40000000 && e + len <= p->mmap_next &&
|
||||
if (vma_anon(v) && e >= 0x40000000 && e + len <= p->mm->mmap_next &&
|
||||
range_free(p, e, len))
|
||||
return e;
|
||||
}
|
||||
}
|
||||
uint64 va = p->mmap_next;
|
||||
uint64 va = p->mm->mmap_next;
|
||||
if (bad_user_range(va, len))
|
||||
return 0;
|
||||
p->mmap_next += len;
|
||||
p->mm->mmap_next += len;
|
||||
return va;
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ vma_cover_anon(struct proc *p, uint64 va, uint64 len)
|
|||
uint64 next = end;
|
||||
int inside = -1;
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
if (!v->used)
|
||||
continue;
|
||||
if (v->addr <= cur && cur < v->addr + v->length)
|
||||
|
|
@ -147,7 +147,7 @@ vma_cover_anon(struct proc *p, uint64 va, uint64 len)
|
|||
next = v->addr;
|
||||
}
|
||||
if (inside >= 0) {
|
||||
cur = p->vma[inside].addr + p->vma[inside].length;
|
||||
cur = p->mm->vma[inside].addr + p->mm->vma[inside].length;
|
||||
continue;
|
||||
}
|
||||
if (vma_note_anon(p, cur, next - cur) < 0)
|
||||
|
|
@ -180,8 +180,8 @@ sys_brk(void)
|
|||
return myproc()->sz;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_mmap(void)
|
||||
static addr_t
|
||||
mmap_locked(void)
|
||||
{
|
||||
uint64 addr, length, offset;
|
||||
int prot, flags, fd;
|
||||
|
|
@ -193,7 +193,7 @@ sys_mmap(void)
|
|||
return -1;
|
||||
|
||||
if (fd >= 0 && fd < NOFILE)
|
||||
f = myproc()->ofile[fd];
|
||||
f = myproc()->files->ofile[fd];
|
||||
|
||||
length = PGROUNDUP(length);
|
||||
uint64 va = addr;
|
||||
|
|
@ -425,8 +425,8 @@ sys_mmap(void)
|
|||
return va;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_munmap(void)
|
||||
static addr_t
|
||||
munmap_locked(void)
|
||||
{
|
||||
uint64 addr, length;
|
||||
struct proc *p = myproc();
|
||||
|
|
@ -441,7 +441,7 @@ sys_munmap(void)
|
|||
// Part of one is refused: unmapping it the anonymous way below would kfree
|
||||
// pages that are the framebuffer's or another process's.
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
if (!v->used || vma_anon(v))
|
||||
continue;
|
||||
if (v->addr == addr) {
|
||||
|
|
@ -466,7 +466,7 @@ sys_munmap(void)
|
|||
// are not there, and the bump allocator never hands the addresses out
|
||||
// again.
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
struct vma *v = &p->mm->vma[i];
|
||||
if (!vma_anon(v))
|
||||
continue;
|
||||
uint64 vs = v->addr, ve = v->addr + v->length;
|
||||
|
|
@ -835,8 +835,8 @@ sys_shmget(void)
|
|||
return -ENOSPC;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_shmat(void)
|
||||
static addr_t
|
||||
shmat_locked(void)
|
||||
{
|
||||
int id, flags;
|
||||
addr_t addr;
|
||||
|
|
@ -859,15 +859,15 @@ sys_shmat(void)
|
|||
|
||||
struct vma *v = 0;
|
||||
for (int i = 0; i < NVMA; i++)
|
||||
if (!myproc()->vma[i].used) { v = &myproc()->vma[i]; break; }
|
||||
if (!myproc()->mm->vma[i].used) { v = &myproc()->mm->vma[i]; break; }
|
||||
if (!v) { shm_detach(id); return -ENOMEM; }
|
||||
|
||||
// Ignore the hint and take a fresh range, the same way mmap does.
|
||||
if (myproc()->mmap_next == 0)
|
||||
myproc()->mmap_next = 0x40000000;
|
||||
uint64 va = myproc()->mmap_next;
|
||||
if (myproc()->mm->mmap_next == 0)
|
||||
myproc()->mm->mmap_next = 0x40000000;
|
||||
uint64 va = myproc()->mm->mmap_next;
|
||||
if (bad_user_range(va, len)) { shm_detach(id); return -ENOMEM; }
|
||||
myproc()->mmap_next += len;
|
||||
myproc()->mm->mmap_next += len;
|
||||
|
||||
for (int pg = 0; pg < npages; pg++) {
|
||||
if (mappages(myproc()->pgdir, (void*)(va + (uint64)pg * PGSIZE), PGSIZE,
|
||||
|
|
@ -895,35 +895,36 @@ sys_shmat(void)
|
|||
//
|
||||
// Called from exit() and from exec() before the old address space goes away.
|
||||
void
|
||||
proc_release_shared(struct proc *p)
|
||||
mm_release_shared(struct mm *m)
|
||||
{
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
if (!p->vma[i].used || !p->vma[i].no_free)
|
||||
if (!m->vma[i].used || !m->vma[i].no_free)
|
||||
continue;
|
||||
vm_unmap_norelease(p->pgdir, p->vma[i].addr, p->vma[i].length);
|
||||
if (p->vma[i].shmid >= 0)
|
||||
shm_detach(p->vma[i].shmid);
|
||||
p->vma[i].used = 0;
|
||||
p->vma[i].no_free = 0;
|
||||
p->vma[i].shmid = -1;
|
||||
if (m->pgdir)
|
||||
vm_unmap_norelease(m->pgdir, m->vma[i].addr, m->vma[i].length);
|
||||
if (m->vma[i].shmid >= 0)
|
||||
shm_detach(m->vma[i].shmid);
|
||||
m->vma[i].used = 0;
|
||||
m->vma[i].no_free = 0;
|
||||
m->vma[i].shmid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_shmdt(void)
|
||||
static addr_t
|
||||
shmdt_locked(void)
|
||||
{
|
||||
addr_t addr;
|
||||
if (argaddr(0, &addr) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
if (myproc()->vma[i].used && myproc()->vma[i].addr == addr &&
|
||||
myproc()->vma[i].shmid >= 0) {
|
||||
vm_unmap_norelease(myproc()->pgdir, addr, myproc()->vma[i].length);
|
||||
shm_detach(myproc()->vma[i].shmid);
|
||||
myproc()->vma[i].used = myproc()->vma[i].addr = myproc()->vma[i].length = 0;
|
||||
myproc()->vma[i].no_free = 0;
|
||||
myproc()->vma[i].shmid = -1;
|
||||
if (myproc()->mm->vma[i].used && myproc()->mm->vma[i].addr == addr &&
|
||||
myproc()->mm->vma[i].shmid >= 0) {
|
||||
vm_unmap_norelease(myproc()->pgdir, addr, myproc()->mm->vma[i].length);
|
||||
shm_detach(myproc()->mm->vma[i].shmid);
|
||||
myproc()->mm->vma[i].used = myproc()->mm->vma[i].addr = myproc()->mm->vma[i].length = 0;
|
||||
myproc()->mm->vma[i].no_free = 0;
|
||||
myproc()->mm->vma[i].shmid = -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -981,3 +982,21 @@ sys_setpriority(void)
|
|||
return -EINVAL;
|
||||
return (addr_t)proc_setnice(who, nice);
|
||||
}
|
||||
|
||||
// One mapping change at a time per address space: threads share the VMA table
|
||||
// and the page tables, and two of them allocating the same missing page-table
|
||||
// level at once would each install their own and lose the other's mappings.
|
||||
#define MM_LOCKED(name) \
|
||||
addr_t \
|
||||
sys_##name(void) \
|
||||
{ \
|
||||
struct mm *m = myproc()->mm; \
|
||||
mm_lock(m); \
|
||||
addr_t r = name##_locked(); \
|
||||
mm_unlock(m); \
|
||||
return r; \
|
||||
}
|
||||
MM_LOCKED(mmap)
|
||||
MM_LOCKED(munmap)
|
||||
MM_LOCKED(shmat)
|
||||
MM_LOCKED(shmdt)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ sock_to_fd(struct socket *s, int sflags)
|
|||
f->off = 0;
|
||||
f->nonblock = (sflags & SOCK_NONBLOCK) != 0;
|
||||
if (sflags & SOCK_CLOEXEC)
|
||||
myproc()->ofile_flags[fd] |= FD_CLOEXEC;
|
||||
myproc()->files->flags[fd] |= FD_CLOEXEC;
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ argsock(int n, struct socket **ps)
|
|||
|
||||
if (argint(n, &fd) < 0)
|
||||
return -EBADF;
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->ofile[fd]))
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd]))
|
||||
return -EBADF;
|
||||
if (f->type != FD_SOCKET)
|
||||
return -ENOTSOCK;
|
||||
|
|
@ -471,7 +471,7 @@ SYSCALL_DEFINE(socketpair)
|
|||
return fd0;
|
||||
}
|
||||
if ((fd1 = sock_to_fd(b, sflags)) < 0) {
|
||||
myproc()->ofile[fd0] = 0;
|
||||
myproc()->files->ofile[fd0] = 0;
|
||||
sockclose(a);
|
||||
sockclose(b);
|
||||
return fd1;
|
||||
|
|
@ -479,8 +479,8 @@ SYSCALL_DEFINE(socketpair)
|
|||
|
||||
int sv[2] = { fd0, fd1 };
|
||||
if (copy_to_user(usv, sv, sizeof(sv)) < 0) {
|
||||
myproc()->ofile[fd0] = 0;
|
||||
myproc()->ofile[fd1] = 0;
|
||||
myproc()->files->ofile[fd0] = 0;
|
||||
myproc()->files->ofile[fd1] = 0;
|
||||
sockclose(a);
|
||||
sockclose(b);
|
||||
return -EFAULT;
|
||||
|
|
@ -808,7 +808,7 @@ argsockfile(int n, struct socket **ps, struct file **pf)
|
|||
|
||||
if (argint(n, &fd) < 0)
|
||||
return -EBADF;
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->ofile[fd]))
|
||||
if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd]))
|
||||
return -EBADF;
|
||||
if (f->type != FD_SOCKET)
|
||||
return -ENOTSOCK;
|
||||
|
|
@ -879,7 +879,7 @@ scm_gather(struct msghdr *m, struct file **fs, int *nfp)
|
|||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (ufd < 0 || ufd >= NOFILE || !(f = myproc()->ofile[ufd])) {
|
||||
if (ufd < 0 || ufd >= NOFILE || !(f = myproc()->files->ofile[ufd])) {
|
||||
r = -EBADF;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -1078,7 +1078,7 @@ SYSCALL_DEFINE(recvmsg)
|
|||
if (d < 0)
|
||||
break;
|
||||
if (flags & MSG_CMSG_CLOEXEC)
|
||||
myproc()->ofile_flags[d] |= FD_CLOEXEC;
|
||||
myproc()->files->flags[d] |= FD_CLOEXEC;
|
||||
ufd[installed++] = d;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,12 +79,12 @@ do_poll(struct pollfd *fds, int nfds, int timeout_ticks)
|
|||
fds[i].revents = 0;
|
||||
if (fds[i].fd < 0)
|
||||
continue; // negative fd: ignore, per poll(2)
|
||||
if (fds[i].fd >= NOFILE || !myproc()->ofile[fds[i].fd]) {
|
||||
if (fds[i].fd >= NOFILE || !myproc()->files->ofile[fds[i].fd]) {
|
||||
fds[i].revents = POLLNVAL;
|
||||
nready++;
|
||||
continue;
|
||||
}
|
||||
int rev = file_poll(myproc()->ofile[fds[i].fd], fds[i].events);
|
||||
int rev = file_poll(myproc()->files->ofile[fds[i].fd], fds[i].events);
|
||||
if (rev) {
|
||||
fds[i].revents = (short)rev;
|
||||
nready++;
|
||||
|
|
@ -217,7 +217,7 @@ sys_select(void)
|
|||
int want_w = fdset_isset(wr, fd);
|
||||
if (!want_r && !want_w)
|
||||
continue;
|
||||
struct file *f = myproc()->ofile[fd];
|
||||
struct file *f = myproc()->files->ofile[fd];
|
||||
if (!f)
|
||||
return -EBADF;
|
||||
int rev = file_poll(f, (want_r ? POLLIN : 0) | (want_w ? POLLOUT : 0));
|
||||
|
|
@ -292,7 +292,7 @@ sys_pselect6(void)
|
|||
int want_w = fdset_isset(wr, fd);
|
||||
if (!want_r && !want_w)
|
||||
continue;
|
||||
struct file *f = myproc()->ofile[fd];
|
||||
struct file *f = myproc()->files->ofile[fd];
|
||||
if (!f)
|
||||
return -EBADF;
|
||||
int rev = file_poll(f, (want_r ? POLLIN : 0) | (want_w ? POLLOUT : 0));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -115,12 +115,12 @@ sys_rt_sigaction(void)
|
|||
|
||||
struct proc *p = myproc();
|
||||
if (oldactp) {
|
||||
put_user(p->sig_handler[sig], oldactp + SA_HANDLER_OFF);
|
||||
put_user(p->sig_restorer[sig], oldactp + SA_RESTORER_OFF(p));
|
||||
put_user(p->sighand->handler[sig], oldactp + SA_HANDLER_OFF);
|
||||
put_user(p->sighand->restorer[sig], oldactp + SA_RESTORER_OFF(p));
|
||||
if (p->syscall_map) {
|
||||
put_user(p->sig_flags[sig], oldactp + SA_FLAGS_OFF(p));
|
||||
put_user(p->sighand->flags[sig], oldactp + SA_FLAGS_OFF(p));
|
||||
} else {
|
||||
uint32 fl = (uint32)p->sig_flags[sig];
|
||||
uint32 fl = (uint32)p->sighand->flags[sig];
|
||||
put_user(fl, oldactp + SA_FLAGS_OFF(p));
|
||||
}
|
||||
}
|
||||
|
|
@ -134,9 +134,9 @@ sys_rt_sigaction(void)
|
|||
// SIGKILL and SIGSTOP cannot be caught or ignored.
|
||||
if (sig == SIGKILL || sig == SIGSTOP)
|
||||
return -EINVAL;
|
||||
p->sig_handler[sig] = h;
|
||||
p->sig_restorer[sig] = r;
|
||||
p->sig_flags[sig] = fl;
|
||||
p->sighand->handler[sig] = h;
|
||||
p->sighand->restorer[sig] = r;
|
||||
p->sighand->flags[sig] = fl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -218,16 +218,16 @@ deliver_signals(struct trapframe *tf)
|
|||
// SIGSTOP cannot be caught or ignored; the other three stop only by
|
||||
// default. Stopped here and resumed here, by SIGCONT or SIGKILL.
|
||||
if (sig == SIGSTOP ||
|
||||
(sig_default_stops(sig) && myproc()->sig_handler[sig] == 0)) {
|
||||
(sig_default_stops(sig) && myproc()->sighand->handler[sig] == 0)) {
|
||||
myproc()->pending_signals &= ~(1ULL << sig);
|
||||
proc_stop(sig);
|
||||
if (myproc()->killed)
|
||||
exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL));
|
||||
continue;
|
||||
}
|
||||
if (myproc()->sig_handler[sig] <= 1) {
|
||||
if (myproc()->sighand->handler[sig] <= 1) {
|
||||
myproc()->pending_signals &= ~(1ULL << sig);
|
||||
if (myproc()->sig_handler[sig] == 0 && sig_default_kills(sig)) {
|
||||
if (myproc()->sighand->handler[sig] == 0 && sig_default_kills(sig)) {
|
||||
myproc()->killed = 1;
|
||||
if (myproc()->killsig == 0)
|
||||
myproc()->killsig = sig;
|
||||
|
|
@ -283,8 +283,8 @@ deliver_signals(struct trapframe *tf)
|
|||
// shifted rsp, and its ret fell into the sigreturn trampoline,
|
||||
// silently undoing everything. exec() handles this same quirk by
|
||||
// setting tf->rcx = elf.entry.
|
||||
tf->rip = myproc()->sig_handler[sig];
|
||||
tf->rcx = myproc()->sig_handler[sig];
|
||||
tf->rip = myproc()->sighand->handler[sig];
|
||||
tf->rcx = myproc()->sighand->handler[sig];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@ addr_t sys_rt_sigsuspend(void)
|
|||
uint64 deliverable = myproc()->pending_signals & ~myproc()->signal_mask;
|
||||
int will_deliver = 0;
|
||||
for (int sig = 1; sig < 32; sig++)
|
||||
if ((deliverable & (1ULL << sig)) && myproc()->sig_handler[sig])
|
||||
if ((deliverable & (1ULL << sig)) && myproc()->sighand->handler[sig])
|
||||
{ will_deliver = 1; break; }
|
||||
|
||||
if (will_deliver && !myproc()->in_signal) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue