Process management work, yield syscall
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 29 Jun 2009 04:46:56 +0000 (21:46 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 29 Jun 2009 04:46:56 +0000 (21:46 -0700)
Very basic mechanisms to yield a core, as well as a rudimentary
'schedule' function to pick the next process to run.  Adds shells for
proc_create and proc_run.  Also moved around some syscalls, to keep them
in the same order throughout the different files.  Haven't added
anything to parlib.

12 files changed:
include/env.h
include/ros/syscall.h
kern/src/Makefrag
kern/src/env.c
kern/src/manager.c
kern/src/syscall.c
kern/src/trap.c
user/apps/roslib/proctests.c [new file with mode: 0644]
user/roslib/inc/lib.h
user/roslib/inc/syswrapper.h
user/roslib/src/syscall.c
user/roslib/src/syswrapper.c

index b21e66f..d6adb2c 100644 (file)
@@ -21,9 +21,11 @@ error_t      env_incref(env_t* e);
 void   env_decref(env_t *SAFE e);
 env_t* env_create(uint8_t *COUNT(size) binary, size_t size);
 void   (IN_HANDLER env_destroy)(env_t *SAFE e);        // Does not return if e == curenv
+// Temporary scheduler function
+void   schedule(void);
 
 int    envid2env(envid_t envid, env_t **env_store, bool checkperm);
-// The following two functions do not return
+// The following three functions do not return
 void   (IN_HANDLER env_run)(env_t *e) __attribute__((noreturn));
 void   env_pop_tf(trapframe_t *tf) __attribute__((noreturn));
 void   env_pop_tf_sysexit(trapframe_t *tf) __attribute__((noreturn));
index 7fbbafc..e7e4520 100644 (file)
@@ -14,11 +14,14 @@ enum
        SYS_cache_invalidate,
        SYS_cputs,
        SYS_cgetc,
-       SYS_getenvid,
        SYS_getcpuid,
-       SYS_env_destroy,
        SYS_serial_write,
        SYS_serial_read,
+       SYS_getenvid,
+       SYS_env_destroy,
+       SYS_yield,
+       SYS_proc_create,
+       SYS_proc_run,
 
        SYS_endofcalls //Should always be last
 };
index 82c9101..b391eee 100644 (file)
@@ -43,6 +43,7 @@ KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
 KERN_APPFILES :=    $(USER_APPS_PARLIB_DIR)/matrix \
                     $(USER_APPS_ROSLIB_DIR)/null \
                     $(USER_APPS_ROSLIB_DIR)/hello \
+                    $(USER_APPS_ROSLIB_DIR)/proctests \
                     $(USER_APPS_ROSLIB_DIR)/measurements
 #                    $(USER_APPS_PARLIB_DIR)/draw_nanwan
 #                    $(USER_APPS_PARLIB_DIR)/open_read \
index f0d09e5..5a694da 100644 (file)
@@ -556,23 +556,33 @@ env_destroy(env_t *e)
         */
        manager();
        assert(0); // never get here
+}
 
-       // ugly, but for now just linearly search through all possible
-       // environments for a runnable one.
-       for (int i = 0; i < NENV; i++) {
-               e = &envs[ENVX(i)];
+/* ugly, but for now just linearly search through all possible
+ * environments for a runnable one.
+ * the current *policy* is to round-robin the search
+ */
+void schedule(void)
+{
+       env_t *e;
+       static int last_picked = 0;
+       
+       for (int i = 0, j = last_picked + 1; i < NENV; i++, j = (j + 1) % NENV) {
+               e = &envs[ENVX(j)];
                // TODO: race here, if another core is just about to start this env.
                // Fix it by setting the status in something like env_dispatch when
                // we have multi-contexted processes
-               if (e && e->env_status == ENV_RUNNABLE)
+               if (e && e->env_status == ENV_RUNNABLE) {
+                       last_picked = j;
                        env_run(e);
+               }
        }
+
        cprintf("Destroyed the only environment - nothing more to do!\n");
        while (1)
                monitor(NULL);
 }
 
-
 //
 // Restores the register values in the Trapframe with the 'iret' instruction.
 // This exits the kernel and starts executing some environment's code.
@@ -591,7 +601,6 @@ void env_pop_tf(trapframe_t *tf)
        panic("iret failed");  /* mostly to placate the compiler */
 }
 
-
 void env_pop_tf_sysexit(trapframe_t *tf)
 {
        __asm __volatile(
index 9e87df7..22c7409 100644 (file)
 void manager(void)
 {
        static uint8_t progress = 0;
-       
+       env_t *envs[256];
+
        switch (progress++) {
                case 0:
+                       envs[0] = ENV_CREATE(roslib_proctests);
+                       envs[1] = ENV_CREATE(roslib_proctests);
+                       envs[2] = ENV_CREATE(roslib_proctests);
+                       envs[3] = ENV_CREATE(roslib_proctests);
+                       env_run(envs[0]);
+                       break;
+               case 1:
+               case 2:
+               case 3:
+               #if 0
+               case 0:
                        printk("Beginning Tests\n");
                        test_run_measurements(progress-1);  // should never return
                        break;
@@ -48,8 +60,10 @@ void manager(void)
                case 14:
                        test_run_measurements(progress-1);
                        break;
+               #endif
                default:
-                       panic("Don't Panic");
+                       printk("Manager Progress: %d\n", progress);
+                       schedule();
        }
        panic("If you see me, then you probably screwed up");
 
index 0018394..7ff66cb 100644 (file)
 #include <trap.h>
 #include <syscall.h>
 
+/* This is called from sysenter's asm, with the tf on the kernel stack */
 void syscall_wrapper(struct Trapframe *tf)
 {
        env_t* curenv = curenvs[lapic_get_id()];
     curenv->env_tf = *tf;
+       // TODO: sort this interrupts shit better
        //Re enable interrupts. sysenter disables them.
        enable_irq();
        
-       curenv->env_tf.tf_regs.reg_eax =
-           (intreg_t) syscall(curenv,
-                              tf->tf_regs.reg_eax,
-                              tf->tf_regs.reg_edx,
-                              tf->tf_regs.reg_ecx,
-                              tf->tf_regs.reg_ebx,
-                              tf->tf_regs.reg_edi,
-                              0);
+       // The trapframe on the stack should be ignored from here on.
+       tf = &curenv->env_tf;
+    tf->tf_regs.reg_eax = (intreg_t) syscall(curenv,
+                                                tf->tf_regs.reg_eax,
+                                                tf->tf_regs.reg_edx,
+                                                tf->tf_regs.reg_ecx,
+                                                tf->tf_regs.reg_ebx,
+                                                tf->tf_regs.reg_edi,
+                                                0);
        env_run(curenv);
 }
 
@@ -211,6 +214,18 @@ static error_t sys_env_destroy(env_t* e, envid_t envid)
        return 0;
 }
 
+/*
+ * Current process yields its remaining "time slice".  Currently works for
+ * single-core processes.
+ */
+static void sys_yield(env_t *e)
+{
+       // TODO: watch for races throughout anything related to process statuses
+       // and schedule/yielding
+       assert(e->env_status == ENV_RUNNING);
+       e->env_status = ENV_RUNNABLE;
+       schedule();
+}
 
 // TODO: Build a dispatch table instead of switching on the syscallno
 // Dispatches to the correct kernel function, passing the arguments.
@@ -233,27 +248,32 @@ intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
                case SYS_null:
                        sys_null();
                        return 0;
-               case SYS_serial_write:
-                       //printk("I am here\n");
-                       return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
-               case SYS_serial_read:
-                       return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
-               case SYS_cache_invalidate:
-                       sys_cache_invalidate();
-                       return 0;
                case SYS_cache_buster:
                        sys_cache_buster(e, a1, a2, a3);
                        return 0;
+               case SYS_cache_invalidate:
+                       sys_cache_invalidate();
+                       return 0;
                case SYS_cputs:
                        return sys_cputs(e, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_cgetc:
                        return sys_cgetc(e);
-               case SYS_getenvid:
-                       return sys_getenvid(e);
                case SYS_getcpuid:
                        return sys_getcpuid();
+               case SYS_serial_write:
+                       return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_serial_read:
+                       return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_getenvid:
+                       return sys_getenvid(e);
                case SYS_env_destroy:
                        return sys_env_destroy(e, (envid_t)a1);
+               case SYS_yield:
+                       sys_yield(e);
+                       return 0;
+               case SYS_proc_create:
+               case SYS_proc_run:
+                       panic("Not implemented");
                default:
                        // or just return -E_INVAL
                        panic("Invalid syscall number %d for env %x!", syscallno, *e);
index de62fcf..b89c32f 100644 (file)
@@ -316,6 +316,7 @@ page_fault_handler(trapframe_t *tf)
        print_trapframe(tf);
        env_destroy(curenv);
 }
+
 void sysenter_init(void)
 {
        write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
diff --git a/user/apps/roslib/proctests.c b/user/apps/roslib/proctests.c
new file mode 100644 (file)
index 0000000..50fb8cf
--- /dev/null
@@ -0,0 +1,14 @@
+#include <lib.h>
+#include <syswrapper.h>
+
+int main(int argc, char** argv)
+{
+       cprintf("Process %x, Starting and yielding.\n", env->env_id);
+       yield();
+       cprintf("Process %x, Return from yield1, starting yield2.\n", env->env_id);
+       yield();
+       cprintf("Process %x, Return from yield2, starting yield3.\n", env->env_id);
+       yield();
+       cprintf("Process %x, Return from yield3, exiting.\n", env->env_id);
+       return 0;
+}
index d9a85da..677f0d1 100644 (file)
@@ -51,18 +51,23 @@ typedef struct syscall_desc_list syscall_desc_list_t;
 // syscall.c
 void        sys_null();
 error_t     sys_null_async(syscall_desc_t* desc);
-void        sys_cache_invalidate();
 void        sys_cache_buster(uint32_t num_writes, uint32_t num_pages,
                              uint32_t flags);
 error_t     sys_cache_buster_async(syscall_desc_t* desc, uint32_t num_writes,
                                    uint32_t num_pages, uint32_t flags);
+void        sys_cache_invalidate();
 ssize_t     sys_cputs(const char *string, size_t len);
 error_t     sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
                             void (*cleanup_handler)(void*), void* cleanup_data);
 uint16_t    sys_cgetc(void);
-envid_t     sys_getenvid(void);
 envid_t     sys_getcpuid(void);
+/* Process Management */
+envid_t     sys_getenvid(void);
 error_t     sys_env_destroy(envid_t);
+void           sys_yield(void);
+int                    sys_proc_create(char* path);
+error_t                sys_proc_run(int pid);
+/* Generic Async Call */
 error_t     waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp);
 
 // async callback
index 509c7e5..89a5298 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ROS_INC_NULL_H
-#define ROS_INC_NULL_H
+#ifndef ROS_INC_SYSWRAPPER_H
+#define ROS_INC_SYSWRAPPER_H
 
 #include <lib.h>
 
@@ -9,5 +9,8 @@ void cache_buster(uint32_t num_writes, uint32_t num_pages, uint32_t flags);
 error_t cache_buster_async(async_desc_t** desc, uint32_t num_writes,
                            uint32_t num_pages, uint32_t flags);
 uint32_t getcpuid(void);
+void yield(void);
+int proc_create(char* path);
+error_t proc_run(int pid);
 
-#endif // ROS_INC_NULL_H
+#endif // ROS_INC_SYSWRAPPER_H
index 5977321..37a800c 100644 (file)
@@ -8,7 +8,7 @@
 #include <ros/syscall.h>
 #include <lib.h>
 
-// TODO: modift to take only four parameters
+// TODO: fix sysenter to take all 5 params
 static intreg_t syscall_sysenter(uint16_t num, intreg_t a1,
                                  intreg_t a2, intreg_t a3,
                                  intreg_t a4, intreg_t a5)
@@ -122,6 +122,11 @@ error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
        return 0;
 }
 
+void sys_null()
+{
+       syscall(SYS_null,0,0,0,0,0);
+}
+
 error_t sys_null_async(syscall_desc_t* desc)
 {
        syscall_req_t syscall = {SYS_null, 0, {[0 ... (NUM_SYS_ARGS-1)] 0}};
@@ -147,8 +152,18 @@ error_t    sys_cache_buster_async(syscall_desc_t* desc, uint32_t num_writes,
        return async_syscall(&syscall, desc);
 }
 
+void sys_cache_invalidate()
+{
+       syscall(SYS_cache_invalidate, 0, 0, 0, 0, 0);
+}
+
+ssize_t sys_cputs(const char *s, size_t len)
+{
+       return syscall(SYS_cputs, (uintreg_t)s,  len, 0, 0, 0);
+}
+
 error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
-                     void (*cleanup_handler)(void*), void* cleanup_data)
+                        void (*cleanup_handler)(void*), void* cleanup_data)
 {
        // could just hardcode 4 0's, will eventually wrap this marshaller anyway
        syscall_req_t syscall = {SYS_cputs, 0, {(uint32_t)s, len, [2 ... (NUM_SYS_ARGS-1)] 0} };
@@ -157,24 +172,19 @@ error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
        return async_syscall(&syscall, desc);
 }
 
-void sys_null()
-{
-       syscall(SYS_null,0,0,0,0,0);
-}
-
-void sys_cache_invalidate()
+uint16_t sys_cgetc(void)
 {
-       syscall(SYS_cache_invalidate, 0, 0, 0, 0, 0);
+       return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
 }
 
-ssize_t sys_cputs(const char *s, size_t len)
+envid_t sys_getcpuid(void)
 {
-       return syscall(SYS_cputs, (intreg_t)s,  len, 0, 0, 0);
+       return syscall(SYS_getcpuid, 0, 0, 0, 0, 0);
 }
 
-uint16_t sys_cgetc(void)
+envid_t sys_getenvid(void)
 {
-       return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
+       return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
 }
 
 error_t sys_env_destroy(envid_t envid)
@@ -182,14 +192,19 @@ error_t sys_env_destroy(envid_t envid)
        return syscall(SYS_env_destroy, envid, 0, 0, 0, 0);
 }
 
-envid_t sys_getenvid(void)
+void sys_yield(void)
 {
-        return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
+       syscall(SYS_yield, 0, 0, 0, 0, 0);
+       return;
 }
 
-envid_t sys_getcpuid(void)
+int sys_proc_create(char* path)
 {
-        return syscall(SYS_getcpuid, 0, 0, 0, 0, 0);
+       return syscall(SYS_proc_create, (uintreg_t)path, 0, 0, 0, 0);
 }
 
+error_t sys_proc_run(int pid)
+{
+       return syscall(SYS_proc_run, pid, 0, 0, 0, 0);
+}
 
index 1078534..2f7dc4e 100644 (file)
@@ -39,3 +39,19 @@ uint32_t getcpuid(void)
 {
        return sys_getcpuid();
 }
+
+void yield(void)
+{
+       sys_yield();
+       return;
+}
+
+int proc_create(char* path)
+{
+       return sys_proc_create(path);
+}
+
+error_t proc_run(int pid)
+{
+       return sys_proc_run(pid);
+}