Async waiting right above the kernel
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 6 May 2009 22:06:30 +0000 (15:06 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 6 May 2009 23:12:42 +0000 (16:12 -0700)
Can wait on a descriptor for an async syscall from any frontring.
Currently waits manually in cprintf_async right after making the calls.

inc/error.h
inc/lib.h
inc/syscall.h
kern/init.c
kern/syscall.c
lib/Makefrag
lib/asynccall.c [new file with mode: 0644]
lib/libmain.c
lib/printf.c
lib/syscall.c
user/hello.c

index 75d0778..28fa1f9 100644 (file)
@@ -4,6 +4,7 @@
 #define ROS_INC_ERROR_H
 
 typedef enum {
+       E_DEADLOCK      =       -3,
        E_BUSY          =       -2,
        E_FAIL          =       -1,
        E_SUCCESS       =       0,
index ea29bb4..01c46dd 100644 (file)
--- a/inc/lib.h
+++ b/inc/lib.h
@@ -36,12 +36,31 @@ char*       readline(const char *buf);
 // syscall.c
 void sys_null();
 void sys_cputs(const char *string, size_t len);
-void sys_cputs_async(const char *string, size_t len);
+void sys_cputs_async(const char *string, size_t len, syscall_desc_t* desc);
 int    sys_cgetc(void);
 envid_t        sys_getenvid(void);
 int    sys_env_destroy(envid_t);
+error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp);
 
+// async callback
+typedef uint32_t async_desc;
 
+extern syscall_desc_t ALL_ASYNC_CALLS[][];
+error_t waiton_async_call(async_desc desc);
+//get_free_async_desc
+
+/*
+typedef syscall_waiter_t;
+typedef struct syscall_waiter {
+       syscall_desc_t desc;    
+       LIST_ENTRY(syscall_waiter_t) next;
+} syscall_waiter_t;
+LIST_HEAD(syscall_waiter_list_t, syscall_waiter_t); 
+
+syscall_waiter_list_t ALL_ASYNC_CALLS[256];
+sys_cpit_async (desc)
+put_syscalls_on_a_fucking_async_callback(async_desc, desc);
+*/
 
 /* File open modes */
 #define        O_RDONLY        0x0000          /* open for reading only */
index b8ea258..6ba4d7c 100644 (file)
@@ -14,6 +14,8 @@ enum
        SYS_env_destroy,
 };
 #define NSYSCALLS (SYS_env_destroy)
+// syscall number starts at 1 and goes up to NSYSCALLS, without holes.
+#define INVALID_SYSCALL(syscallno) ((syscallno) > NSYSCALLS)
 
 #define NUM_SYS_ARGS 6
 typedef struct SyscallRequest {
@@ -23,11 +25,15 @@ typedef struct SyscallRequest {
 } syscall_req_t;
 
 typedef struct SyscallResponse {
-       uint32_t retval;
-} syscall_resp_t;
-
+       int32_t retval;
+} syscall_rsp_t;
 
 // Generic Syscall Ring Buffer
-DEFINE_RING_TYPES(syscall, syscall_req_t, syscall_resp_t);
+DEFINE_RING_TYPES(syscall, syscall_req_t, syscall_rsp_t);
+
+typedef struct SyscallRespDesc {
+       syscall_front_ring_t* sysfr;
+       uint32_t idx;
+} syscall_desc_t;
 
 #endif /* !ROS_INC_SYSCALL_H */
index 1da0ebe..37b2afb 100644 (file)
@@ -80,9 +80,9 @@ void kernel_init(multiboot_info_t *mboot_info)
        //ENV_CREATE(user_badsegment);
        //ENV_CREATE(user_divzero);
        //ENV_CREATE(user_buggyhello);
+       ENV_CREATE(user_hello);
        //ENV_CREATE(user_hello);
-       //ENV_CREATE(user_hello);
-       ENV_CREATE(user_null);
+       //ENV_CREATE(user_null);
        //ENV_CREATE(user_evilhello);
 
        // We only have one user environment for now, so just run it.
@@ -94,14 +94,12 @@ void kernel_init(multiboot_info_t *mboot_info)
 
        // wait 5 sec, then print what's in shared mem
        udelay(5000000);
-       /*
        printk("Attempting to run two syscalls at the beginning of procdata for env 0 and 1:\n\n");
        while (1) {
                process_generic_syscalls(&envs[0], 1);
                //process_generic_syscalls(&envs[1], 1);
                cpu_relax();
        }
-       */
        panic("Don't Panic");
 }
 
index e29e384..904641d 100644 (file)
@@ -88,7 +88,7 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
 
        //cprintf("Incoming syscall number: %d\n    a1: %x\n    a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", syscallno, a1, a2, a3, a4, a5);
 
-       if (syscallno >= NSYSCALLS)
+       if (INVALID_SYSCALL(syscallno))
                return -E_INVAL;
        
        switch (syscallno) {
@@ -132,12 +132,12 @@ uint32_t process_generic_syscalls(env_t* e, uint32_t max)
                           sysbr->sring->req_prod, sysbr->sring->rsp_prod);
                // might want to think about 0-ing this out, if we aren't
                // going to explicitly fill in all fields
-               syscall_resp_t rsp;
+               syscall_rsp_t rsp;
                // this assumes we get our answer immediately for the syscall.
                syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
                rsp.retval = syscall_async(req);
                // write response into the slot it came from
-               memcpy(req, &rsp, sizeof(syscall_resp_t));
+               memcpy(req, &rsp, sizeof(syscall_rsp_t));
                // update our counter for what we've produced (assumes we went in order!)
                (sysbr->rsp_prod_pvt)++;
                RING_PUSH_RESPONSES(sysbr);
index 35ad63b..0382476 100644 (file)
@@ -10,7 +10,8 @@ LIB_SRCFILES :=               lib/console.c \
                        lib/printfmt.c \
                        lib/readline.c \
                        lib/string.c \
-                       lib/syscall.c
+                       lib/syscall.c \
+                       lib/asynccall.c
 
 
 
diff --git a/lib/asynccall.c b/lib/asynccall.c
new file mode 100644 (file)
index 0000000..8ae5a7c
--- /dev/null
@@ -0,0 +1,11 @@
+#include <inc/lib.h>
+#include <inc/syscall.h>
+
+// assumes all calls are to the same ring buffer
+syscall_desc_t ALL_ASYNC_CALLS[20][20];
+
+error_t waiton_async_call(async_desc desc)
+{
+       return 0;
+}
+
index 3f02cb4..933fa51 100644 (file)
@@ -31,4 +31,3 @@ libmain(int argc, char **argv)
        // exit gracefully
        exit();
 }
-
index abacd4a..1b26f37 100644 (file)
@@ -81,10 +81,15 @@ static printbuf_t* get_free_buffer(void)
 // this buffering is a minor pain in the ass....
 static void putch_async(int ch, printbuf_t *b)
 {
+       syscall_desc_t desc;
        b->buf[b->idx++] = ch;
        if (b->idx == 256-1) {
                // will need some way to track the result of the syscall
-               sys_cputs_async(b->buf, b->idx);
+               sys_cputs_async(b->buf, b->idx, &desc);
+
+// push this up a few layers
+syscall_rsp_t rsp;
+waiton_syscall(&desc, &rsp);
                b = get_free_buffer();
                b->idx = 0;
        }
@@ -93,6 +98,7 @@ static void putch_async(int ch, printbuf_t *b)
 
 static int vcprintf_async(const char *fmt, va_list ap)
 {
+       syscall_desc_t desc;
        // start with an available buffer
        printbuf_t* b = get_free_buffer();
 
@@ -100,7 +106,10 @@ static int vcprintf_async(const char *fmt, va_list ap)
        b->cnt = 0;
        vprintfmt((void*)putch_async, b, fmt, ap);
        // will need some way to track the result of the syscall
-       sys_cputs_async(b->buf, b->idx);
+       sys_cputs_async(b->buf, b->idx, &desc);
+// push this up a few layers
+syscall_rsp_t rsp;
+waiton_syscall(&desc, &rsp);
 
        return b->cnt; // this is lying if we used more than one buffer
 }
index cf45c1d..3b5548e 100644 (file)
@@ -35,29 +35,44 @@ syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5
        return ret;
 }
 
-static inline error_t async_syscall(syscall_req_t *syscall)
+static inline error_t async_syscall(syscall_req_t* req, syscall_desc_t* desc)
 {
+       // Note that this assumes one global frontring (TODO)
        // spin til there is room for our request.  ring size is currently 64.
-       while (RING_FULL(&sysfrontring))
-               cpu_relax();
+       if (RING_FULL(&sysfrontring))
+               return E_BUSY;
        // req_prod_pvt comes in as the previously produced item.  need to
        // increment to the next available spot, which is the one we'll work on.
-       syscall_req_t* req = RING_GET_REQUEST(&sysfrontring, ++(sysfrontring.req_prod_pvt));
-       memcpy(req, syscall, sizeof(syscall_req_t));
+       // at some point, we need to listen for the responses.
+       desc->idx = ++(sysfrontring.req_prod_pvt);
+       desc->sysfr = &sysfrontring;
+       syscall_req_t* r = RING_GET_REQUEST(&sysfrontring, desc->idx);
+       memcpy(r, req, sizeof(syscall_req_t));
        // push our updates to sysfrontring.req_prod_pvt
        RING_PUSH_REQUESTS(&sysfrontring);
        //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", \
                sysfrontring.sring->req_prod, sysfrontring.sring->rsp_prod);
        return 0;
-       // at some point, we need to listen for the responses.  pass back a
-       // reference of some sort, probably via a parameter.
 }
 
-void sys_cputs_async(const char *s, size_t len)
+// consider a timeout too
+error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
+{
+       // this forces us to call wait in the order in which they are called
+       if (desc->idx != desc->sysfr->rsp_cons + 1)
+               return E_DEADLOCK;
+       while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
+               cpu_relax();
+       memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
+       desc->sysfr->rsp_cons++;
+       return 0;
+}
+
+void sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc)
 {
        // 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} };
-       async_syscall(&syscall);
+       async_syscall(&syscall, desc);
 }
 
 void sys_null()
index ea2c0a2..9227a06 100644 (file)
@@ -14,9 +14,12 @@ void umain(void)
        // will be the one printed when the syscall is serviced, regardless of
        // whether the actual syscall can handle multiples in flight.
        cprintf_async("Cross-Core call 1, coming from env %08x\n", env->env_id);
-       cprintf_async("Cross-Core call 2, coming from env %08x\n", env->env_id);
-       cprintf("Calls are sent!\n");
+       cprintf("Call 1 is sent!\n");
+       cprintf_async("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXCross-Core call 2, coming from env %08x\n", env->env_id);
+       cprintf("Call 2 is sent!\n");
        // might as well spin, just to make sure nothing gets deallocated
        // while we're waiting to test the async call
        while (1);
+
+       //check that my shit is done
 }