Skip to content

Commit

Permalink
Moved uspace field from thread_t to proc_t (#289)
Browse files Browse the repository at this point in the history
* Moved uspace field from thread_t to proc_t
* Moved uspace vm_map ptr to pcpu struct
* Terminating other threads on 'exec'
* Set process parent on fork
* Introduced the assumption of single thread per process
  • Loading branch information
rafalcieslak authored and cahirwpz committed May 11, 2017
1 parent 0a83067 commit a8f0b4b
Show file tree
Hide file tree
Showing 13 changed files with 70 additions and 44 deletions.
2 changes: 2 additions & 0 deletions include/pcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

typedef struct thread thread_t;
typedef struct pmap pmap_t;
typedef struct vm_map vm_map_t;

typedef struct pcpu {
thread_t *curthread;
thread_t *idle_thread;
pmap_t *curpmap;
vm_map_t *uspace;
} pcpu_t;

extern pcpu_t _pcpu_data[1];
Expand Down
5 changes: 5 additions & 0 deletions include/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <common.h>
#include <queue.h>
#include <mutex.h>
#include <vm_map.h>

typedef struct thread thread_t;
typedef struct proc proc_t;
Expand All @@ -14,9 +15,13 @@ typedef TAILQ_HEAD(, proc) proc_list_t;
struct proc {
mtx_t p_lock; /* Process lock */
TAILQ_ENTRY(proc) p_all; /* A link on all processes list */
/* XXX: At the moment we don't support multiple threads in a single process!
*/
unsigned p_nthreads;
thread_list_t p_threads; /* Threads belonging to this process */
pid_t p_pid; /* Process ID */
proc_t *p_parent; /* Parent process */
vm_map_t *p_uspace; /* process' user space map */
/* file descriptors table */
fdtab_t *p_fdtable;
};
Expand Down
1 change: 0 additions & 1 deletion include/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ typedef struct thread {
intptr_t td_onfault; /* program counter for copyin/copyout faults */
vm_page_t *td_kstack_obj;
stack_t td_kstack;
vm_map_t *td_uspace; /* thread's user space map */
/* waiting channel */
sleepq_t *td_sleepqueue;
void *td_wchan;
Expand Down
2 changes: 1 addition & 1 deletion include/vm_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ typedef struct vm_map {
*
* vm_map_entry_t* vm_map_allocate_space(vm_map_t* map, size_t length) */

vm_map_t *vm_map_activate(vm_map_t *map);
void vm_map_activate(vm_map_t *map);
vm_map_t *get_user_vm_map();
vm_map_t *get_kernel_vm_map();
vm_map_t *get_active_vm_map_by_addr(vm_addr_t addr);
Expand Down
5 changes: 4 additions & 1 deletion mips/genassym.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
#include <context.h>
#include <thread.h>
#include <pcpu.h>
#include <proc.h>
#include <mips/ctx.h>
#include <mips/exc.h>

ASSYM(TDF_NEEDSWITCH, TDF_NEEDSWITCH);

ASSYM(TD_PROC, offsetof(thread_t, td_proc));
ASSYM(TD_UCTX, offsetof(thread_t, td_uctx));
ASSYM(TD_UCTX_FPU, offsetof(thread_t, td_uctx_fpu));
ASSYM(TD_KFRAME, offsetof(thread_t, td_kframe));
ASSYM(TD_KCTX, offsetof(thread_t, td_kctx));
ASSYM(TD_KSTACK, offsetof(thread_t, td_kstack));
ASSYM(TD_FLAGS, offsetof(thread_t, td_flags));
ASSYM(TD_USPACE, offsetof(thread_t, td_uspace));
ASSYM(TD_ONFAULT, offsetof(thread_t, td_onfault));

ASSYM(STK_BASE, offsetof(stack_t, stk_base));
Expand Down Expand Up @@ -85,4 +86,6 @@ ASSYM(EXC_CAUSE, offsetof(exc_frame_t, cause));

ASSYM(EXC_FRAME_SIZ, sizeof(exc_frame_t) + CALLFRAME_SIZ);

ASSYM(P_USPACE, offsetof(proc_t, p_uspace));

ASSYM(PCPU_CURTHREAD, offsetof(pcpu_t, curthread));
7 changes: 5 additions & 2 deletions mips/switch.S
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ ctx_resume:
LOAD_PCPU($t0)
sw $s0, PCPU_CURTHREAD($t0)

lw $a0, TD_USPACE($s0)
jal vm_map_activate
lw $a0, TD_PROC($s0)
beqz $a0, 1f # switching to kernel thread ?
nop
lw $a0, P_USPACE($a0)
1: jal vm_map_activate
nop

addu $a1, $s0, TD_KCTX
Expand Down
47 changes: 27 additions & 20 deletions sys/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,35 @@ int do_exec(const exec_args_t *args) {
return -ENOEXEC;
}

thread_t *td = thread_self();

/* If this is a kernel thread becoming a user thread, then we need to create
* (the first!) process. */
if (!td->td_proc) {
proc_t *p = proc_create();
proc_populate(p, td);

/* Prepare file descriptor table */
fdtab_t *fdt = fdtab_alloc();
fdtab_ref(fdt);
td->td_proc->p_fdtable = fdt;
}

/* We assume process may only have a single thread. But if there were more
than one thread in the process that called exec, all other threads must be
forcefully terminated. */

/*
* We can not destroy the current vm map, because exec can still fail,
* and in that case we must be able to return to the original address space.
*/
vm_map_t *vmap = vm_map_new();
vm_map_t *old_vmap = vm_map_activate(vmap);
vm_map_t *old_vmap = td->td_proc ? td->td_proc->p_uspace : NULL;

/* We are the only live thread in this process. We can safely give it a new
* uspace. */
td->td_proc->p_uspace = vmap;
vm_map_activate(vmap);

/* Iterate over prog headers */
log("ELF has %d program headers", eh.e_phnum);
Expand Down Expand Up @@ -215,26 +238,12 @@ int do_exec(const exec_args_t *args) {
log("Stack real bottom at %p", (void *)stack_bottom);
prepare_program_stack(args, &stack_bottom);

thread_t *td = thread_self();

/* ... sbrk segment ... */
sbrk_create(vmap);

/* ... and user context. */
uctx_init(thread_self(), eh.e_entry, stack_bottom);

/* If this is a kernel thread becoming a user thread, then we need to create
* (the first!) process. */
if (!td->td_proc) {
proc_t *proc = proc_create();
proc_populate(proc, td);

/* Prepare file descriptor table */
fdtab_t *fdt = fdtab_alloc();
fdtab_ref(fdt);
td->td_proc->p_fdtable = fdt;
}

/* Before we have a working fork, let's initialize file descriptors required
by the standard library. */
int ignore;
Expand All @@ -243,11 +252,8 @@ int do_exec(const exec_args_t *args) {
do_open(td, "/dev/cons", O_WRONLY, 0, &ignore);

/*
* At this point we are certain that exec suceeds.
* We can safely destroy the previous vm map.
*
* One can use do_exec() to start new user program from kernel space,
* in such case there is no old user vm space to dismantle.
* At this point we are certain that exec succeeds. We can safely destroy the
* previous vm map, and permanently assign this one to the current process.
*/
if (old_vmap)
vm_map_delete(old_vmap);
Expand All @@ -262,6 +268,7 @@ int do_exec(const exec_args_t *args) {

exec_fail:
/* Return to the previous map, unmodified by exec. */
td->td_proc->p_uspace = old_vmap;
vm_map_activate(old_vmap);
/* Destroy the vm map we began preparing. */
vm_map_delete(vmap);
Expand Down
9 changes: 5 additions & 4 deletions sys/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ int do_fork() {
thread_t *td = thread_self();

/* Cannot fork non-user threads. */
assert(td->td_uspace);
assert(td->td_proc);

thread_t *newtd = thread_create(td->td_name, NULL, NULL);

Expand All @@ -38,9 +38,6 @@ int do_fork() {
starting from user_exc_leave (which serves as fork_trampoline). */
ctx_init(newtd, user_exc_leave, NULL);

/* Clone the entire process memory space. */
newtd->td_uspace = vm_map_clone(td->td_uspace);

newtd->td_sleepqueue = sleepq_alloc();
newtd->td_wchan = NULL;
newtd->td_wmesg = NULL;
Expand All @@ -50,8 +47,12 @@ int do_fork() {
/* Now, prepare a new process. */
assert(td->td_proc);
proc_t *proc = proc_create();
proc->p_parent = td->td_proc;
proc_populate(proc, newtd);

/* Clone the entire process memory space. */
proc->p_uspace = vm_map_clone(td->td_proc->p_uspace);

/* Copy the parent descriptor table. */
/* TODO: Optionally share the descriptor table between processes. */
proc->p_fdtable = fdtab_copy(td->td_proc->p_fdtable);
Expand Down
4 changes: 3 additions & 1 deletion sys/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vm_map.h>
#include <vm_pager.h>
#include <rwlock.h>
#include <proc.h>

int sys_mmap(thread_t *td, syscall_args_t *args) {
vm_addr_t addr = args->args[0];
Expand All @@ -25,7 +26,8 @@ int sys_mmap(thread_t *td, syscall_args_t *args) {
vm_addr_t do_mmap(vm_addr_t addr, size_t length, vm_prot_t prot, int flags,
int *error) {
thread_t *td = thread_self();
vm_map_t *vmap = td->td_uspace;
assert(td->td_proc);
vm_map_t *vmap = td->td_proc->p_uspace;

assert(vmap);

Expand Down
2 changes: 2 additions & 0 deletions sys/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ proc_t *proc_create() {
proc_t *proc = kmalloc(M_PROC, sizeof(proc_t), M_ZERO);
mtx_init(&proc->p_lock, MTX_DEF);
TAILQ_INIT(&proc->p_threads);
proc->p_nthreads = 0;

mtx_lock(&all_proc_list_mtx);
TAILQ_INSERT_TAIL(&all_proc_list, proc, p_all);
Expand All @@ -38,6 +39,7 @@ void proc_populate(proc_t *p, thread_t *td) {
mtx_scoped_lock(&td->td_lock);
td->td_proc = p;
TAILQ_INSERT_TAIL(&p->p_threads, td, td_procq);
p->p_nthreads += 1;
}

proc_t *proc_find(pid_t pid) {
Expand Down
4 changes: 2 additions & 2 deletions sys/sysent.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ int sys_sbrk(thread_t *td, syscall_args_t *args) {
return -ENOMEM;
}

assert(td->td_uspace);
assert(td->td_proc);

return sbrk_resize(td->td_uspace, increment);
return sbrk_resize(td->td_proc->p_uspace, increment);
}

/* This is just a stub. A full implementation of this syscall will probably
Expand Down
24 changes: 12 additions & 12 deletions sys/vm_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,23 @@
#include <vm_object.h>
#include <vm_map.h>
#include <errno.h>
#include <proc.h>
#include <mips/mips.h>
#include <pcpu.h>

static MALLOC_DEFINE(M_VMMAP, "vm-map", 1, 2);

static vm_map_t kspace;

vm_map_t *vm_map_activate(vm_map_t *map) {
vm_map_t *old;

void vm_map_activate(vm_map_t *map) {
critical_enter();
thread_t *td = thread_self();
old = td->td_uspace;
td->td_uspace = map;
PCPU_SET(uspace, map);
pmap_activate(map ? map->pmap : NULL);
critical_leave();

return old;
}

vm_map_t *get_user_vm_map() {
return thread_self()->td_uspace;
return PCPU_GET(uspace);
}

vm_map_t *get_kernel_vm_map() {
Expand Down Expand Up @@ -240,14 +236,17 @@ void vm_map_dump(vm_map_t *map) {
/* This entire function is a nasty hack, but we'll live with it until proper COW
is implemented. */
vm_map_t *vm_map_clone(vm_map_t *map) {
thread_t *td = thread_self();
assert(td->td_proc);
assert(td->td_proc->p_nthreads == 1);

vm_map_t *orig_current_map = get_user_vm_map();
vm_map_t *newmap = vm_map_new();

rw_scoped_enter(&map->rwlock, RW_READER);

/* Temporarily switch to the new map, so that we may write contents. Note that
it's okay if we get preempted - the working vm map will be restored on
context switch. */
/* Temporarily switch to the new map, so that we may write contents. */
td->td_proc->p_uspace = newmap;
vm_map_activate(newmap);

vm_map_entry_t *it;
Expand All @@ -263,6 +262,7 @@ vm_map_t *vm_map_clone(vm_map_t *map) {
}

/* Return to original vm map. */
td->td_proc->p_uspace = orig_current_map;
vm_map_activate(orig_current_map);

return newmap;
Expand Down
2 changes: 2 additions & 0 deletions tests/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ void main() {
}
#endif

#if 0
static struct {
intptr_t start, end;
} range[] = {
Expand Down Expand Up @@ -91,3 +92,4 @@ static int test_sched() {
}

KTEST_ADD(sched, test_sched, KTEST_FLAG_NORETURN);
#endif

0 comments on commit a8f0b4b

Please sign in to comment.