Can wait on async library calls
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 7 May 2009 06:22:12 +0000 (23:22 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 7 May 2009 06:22:12 +0000 (23:22 -0700)
Also uses Pools for the allocation of bookkeeping for the syscall and
async call returns.  Still can't free, and printfing more than 256
doesn't work right.

inc/lib.h
inc/pool.h
inc/queue.h
inc/stdio.h
inc/syscall.h
lib/asynccall.c
lib/libmain.c
lib/printf.c
user/hello.c

index 01c46dd..d0dd09c 100644 (file)
--- a/inc/lib.h
+++ b/inc/lib.h
@@ -8,14 +8,16 @@
 #define ROS_INC_LIB_H 1
 
 #include <inc/types.h>
-#include <inc/stdio.h>
 #include <inc/stdarg.h>
 #include <inc/string.h>
 #include <inc/error.h>
-#include <inc/assert.h>
 #include <inc/env.h>
 #include <inc/memlayout.h>
 #include <inc/syscall.h>
+#include <inc/pool.h>
+// These two are included below because of dependency issues.
+//#include <inc/stdio.h>
+//#include <inc/assert.h>
 
 #define USED(x)                (void)(x)
 
@@ -43,24 +45,32 @@ 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;
+#define MAX_SYSCALLS 100
+#define MAX_ASYNCCALLS 10
+// This is the high-level object a process waits, with multiple syscalls within.
+typedef syscall_desc_list_t async_desc_t;
+// This is per-thread, and used when entering a async library call to properly
+// group syscall_desc_t used during the processing of that async call
+extern async_desc_t* current_async_desc;
+// stdio.h needs to be included after async_desc_t.  assert.h includes stdio.h.
+#include <inc/stdio.h>
+#include <inc/assert.h>
 
-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); 
+// This pooltype contains syscall_desc_t, which is how you wait on one syscall.
+POOL_TYPE_DEFINE(syscall_desc_t, syscall_desc_pool, MAX_SYSCALLS);
+POOL_TYPE_DEFINE(async_desc_t, async_desc_pool, MAX_ASYNCCALLS);
+// These are declared in libmain.c
+extern syscall_desc_pool_t syscall_desc_pool;
+extern async_desc_pool_t async_desc_pool;
+// Finds a free async_desc_t, on which you can wait for a series of syscalls
+async_desc_t* get_async_desc(void);
+// Wait on all syscalls within this async call.  TODO - timeout or something?
+error_t waiton_async_call(async_desc_t* desc);
+// Finds a free sys_desc_t, on which you can wait for a specific syscall, and
+// binds it to the group desc.
+syscall_desc_t* get_sys_desc(async_desc_t* desc);
 
-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 0dda192..46c8733 100644 (file)
@@ -1,58 +1,60 @@
 /* See COPYRIGHT for copyright information. */
 /* Kevin Klues <klueska@cs.berkeley.edu>       */
 
-#ifndef ROS_POOL_H
-#define ROS_POOL_H   
+#ifndef ROS_INC_POOL_H
+#define ROS_INC_POOL_H   
 
-#define POOL_DECLARE(_t, p, sz)                                                \
-struct {                                                                       \
+#define POOL_TYPE_DEFINE(_type, p, sz)                                                \
+typedef struct struct_##p {                                                             \
        uint32_t size;                                                         \
        uint32_t free;                                                         \
        uint32_t index;                                                        \
-       _t* queue[(sz)];                                                       \
-       _t pool[(sz)];                                                         \
-} p = {(sz), (sz), 0, {[0 ... ((sz)-1)] 0}, {[0 ... ((sz)-1)] 0}};
+       _type* queue[(sz)];                                                       \
+       _type pool[(sz)];                                                         \
+} p##_t;
 
-#define POOL_INIT(p)                                                           \
+#define POOL_INIT(p, sz)                                                       \
 ({                                                                             \
-       for(int i=0; i<(p)->size; i++) {                                       \
-               (p)->queue[i] = &((p)->pool[i]);                               \
-       }                                                                      \
+       (p)->size = (sz);                                                          \
+       (p)->free = (sz);                                                          \
+       (p)->index = 0;                                                            \
+       for(int i=0; i<(p)->size; i++) {                                           \
+               (p)->queue[i] = &((p)->pool[i]);                                       \
+       }                                                                          \
 })
 
-#define POOL_GET(p)                                                            \
-({                                                                             \
-       if((p)->free) {                                                        \
-               void* rval = (p)->queue[(p)->index];                           \
-               (p)->queue[(p)->index] = NULL;                                 \
-               (p)->free--;                                                   \
-               (p)->index++;                                                  \
-               if((p)->index == (p)->size) {                                  \
-               (p)->index = 0;                                                \
-       }                                                                      \
-               rval;                                                          \
-       }                                                                      \
-       NULL;                                                                  \
+#define POOL_GET(p)                                            \
+({                                                             \
+       void* rval = NULL;                                         \
+       if((p)->free) {                                            \
+               rval = (p)->queue[(p)->index];                         \
+               (p)->queue[(p)->index] = NULL;                         \
+               (p)->free--;                                           \
+               (p)->index++;                                          \
+               if((p)->index == (p)->size) {                          \
+               (p)->index = 0;                                    \
+       }                                                      \
+       }                                                          \
+       rval;                                                      \
 })
 
 #define POOL_PUT(p, val)                                                       \
 ({                                                                             \
-       if((p)->free >= (p)->size) {                                           \
-               -1;                                                            \
-       }                                                                      \
-       else {                                                                 \
+       int rval = -1;                                                            \
+       if((p)->free < (p)->size) {                                           \
                int emptyIndex = ((p)->index + (p)->free);                     \
                if (emptyIndex >= (p)->size) {                                 \
                        emptyIndex -= (p)->size;                               \
                }                                                              \
                (p)->queue[emptyIndex] = val;                                  \
                (p)->free++;                                                   \
-               1;                                                             \
+               rval = 1;                                                             \
        }                                                                      \
+       rval;                                                                 \
 })
 
 #define POOL_EMPTY(p) ((p)->free == 0)
 #define POOL_SIZE(p) ((p)->free))
 #define POOL_MAX_SIZE(p) ((p)->size))
 
-#endif //ROS_POOL_H
+#endif //ROS_INC_POOL_H
index cc903d5..1102ed4 100644 (file)
@@ -109,6 +109,7 @@ LIST_INSERT_HEAD(&flist, g, frob_link);     /* add g as first element in list */
 #define        LIST_HEAD(name, type)                                   \
 typedef struct {                                                               \
        type *lh_first; /* first element */                     \
+       type *lh_last;  /* last element */                      \
 } name;
 
 /*
@@ -116,7 +117,7 @@ typedef struct {                                                            \
  * to reset it to the empty list.
  */
 #define        LIST_HEAD_INITIALIZER(head)                                     \
-       { NULL }
+       { NULL, NULL }
 
 /*
  * Use this inside a structure "LIST_ENTRY(type) field" to use
@@ -147,6 +148,11 @@ struct {                                                           \
 #define        LIST_FIRST(head)        ((head)->lh_first)
 
 /*
+ * Return the last element in the list named "head".
+ */
+#define        LIST_LAST(head) ((head)->lh_last)
+
+/*
  * Return the element after "elm" in the list.
  * The "field" name is the link element as above.
  */
@@ -167,13 +173,14 @@ struct {                                                          \
  */
 #define        LIST_INIT(head) do {                                            \
        LIST_FIRST((head)) = NULL;                                      \
+       LIST_LAST((head)) = NULL;                                       \
 } while (0)
 
 /*
+ * TODO : DON'T USE THIS because of tail pointer issues
  * Insert the element "elm" *after* the element "listelm" which is
  * already in the list.  The "field" name is the link element
  * as above.
- */
 #define        LIST_INSERT_AFTER(listelm, elm, field) do {                     \
        if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
                LIST_NEXT((listelm), field)->field.le_prev =            \
@@ -181,18 +188,21 @@ struct {                                                          \
        LIST_NEXT((listelm), field) = (elm);                            \
        (elm)->field.le_prev = &LIST_NEXT((listelm), field);            \
 } while (0)
+ */
 
 /*
+ * TODO : DON'T USE THIS because of tail pointer issues
+ * Insert the element "elm" *after* the element "listelm" which is
  * Insert the element "elm" *before* the element "listelm" which is
  * already in the list.  The "field" name is the link element
  * as above.
- */
 #define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
        (elm)->field.le_prev = (listelm)->field.le_prev;                \
        LIST_NEXT((elm), field) = (listelm);                            \
        *(listelm)->field.le_prev = (elm);                              \
        (listelm)->field.le_prev = &LIST_NEXT((elm), field);            \
 } while (0)
+ */
 
 /*
  * Insert the element "elm" at the head of the list named "head".
@@ -201,11 +211,30 @@ struct {                                                          \
 #define        LIST_INSERT_HEAD(head, elm, field) do {                         \
        if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)     \
                LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+       else                                                       \
+               LIST_LAST((head)) = (elm);                                      \
        LIST_FIRST((head)) = (elm);                                     \
        (elm)->field.le_prev = &LIST_FIRST((head));                     \
 } while (0)
 
 /*
+ * TODO : DO NOT USE THIS AFTER YOU'VE REMOVED AN ITEM!!
+ * Insert the element "elm" at the tail of the list named "head".
+ * The "field" name is the link element as above.
+ * (you have been warned) ((sorry))
+ */
+#define        LIST_INSERT_TAIL(head, elm, field) do {                                            \
+       if (LIST_EMPTY((head)))                                                    \
+               LIST_INSERT_HEAD((head), (elm), field);                                \
+       else {                                                                     \
+               (elm)->field.le_prev = &(LIST_LAST((head))->field.le_next);            \
+               LIST_LAST((head))->field.le_next = (elm);                              \
+               LIST_LAST((head)) = (elm);                                             \
+               (elm)->field.le_next = NULL;                                           \
+       }                                                                          \
+} while (0)
+
+/*
  * Remove the element "elm" from the list.
  * The "field" name is the link element as above.
  */
index 395cb7a..be32bcd 100644 (file)
@@ -26,7 +26,6 @@ void  vprintfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *NTS fmt, va_
 
 // lib/printf.c
 int    cprintf(const char * NTS fmt, ...);
-int    cprintf_async(const char * NTS fmt, ...);
 int    vcprintf(const char * NTS fmt, va_list);
 
 // lib/sprintf.c
@@ -41,4 +40,13 @@ int  vfprintf(int fd, const char *fmt, va_list);
 // lib/readline.c
 char *NTS readline(const char *NTS prompt);
 
+/* USERSPACE ONLY */
+#ifndef ROS_KERNEL
+
+#include <inc/lib.h>
+
+int    cprintf_async(async_desc_t** desc, const char * NTS fmt, ...);
+
+#endif /* USERSPACE ONLY */
+
 #endif /* !ROS_INC_STDIO_H */
index 6ba4d7c..85c8c02 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <inc/types.h>
 #include <inc/ring_buffer.h>
+#include <inc/queue.h>
 
 /* system call numbers */
 enum
@@ -31,9 +32,12 @@ typedef struct SyscallResponse {
 // Generic Syscall Ring Buffer
 DEFINE_RING_TYPES(syscall, syscall_req_t, syscall_rsp_t);
 
-typedef struct SyscallRespDesc {
+typedef struct syscall_desc syscall_desc_t;
+struct syscall_desc {
+       LIST_ENTRY(syscall_desc_t) next;
        syscall_front_ring_t* sysfr;
        uint32_t idx;
-} syscall_desc_t;
+};
+LIST_HEAD(syscall_desc_list_t, syscall_desc_t); 
 
 #endif /* !ROS_INC_SYSCALL_H */
index 8ae5a7c..29de80b 100644 (file)
@@ -1,11 +1,27 @@
 #include <inc/lib.h>
 #include <inc/syscall.h>
+#include <inc/queue.h>
 
-// assumes all calls are to the same ring buffer
-syscall_desc_t ALL_ASYNC_CALLS[20][20];
+async_desc_t* get_async_desc(void)
+{
+       return POOL_GET(&async_desc_pool);
+}
 
-error_t waiton_async_call(async_desc desc)
+error_t waiton_async_call(async_desc_t* desc)
 {
+       syscall_rsp_t rsp;
+       while (!(LIST_EMPTY(desc))) {
+               waiton_syscall(LIST_FIRST(desc), &rsp);
+               // consider processing the retval out of rsp
+               LIST_REMOVE(LIST_FIRST(desc), next);
+       }
        return 0;
 }
 
+syscall_desc_t* get_sys_desc(async_desc_t* desc)
+{
+       syscall_desc_t* d = POOL_GET(&syscall_desc_pool);
+       if (d)
+       LIST_INSERT_TAIL(desc, d, next);
+       return d;
+}
index 933fa51..430d63d 100644 (file)
@@ -9,6 +9,10 @@ extern void umain(int argc, char **argv);
 volatile env_t *env;
 char *binaryname = "(PROGRAM NAME UNKNOWN)";
 syscall_front_ring_t sysfrontring;
+syscall_desc_pool_t syscall_desc_pool;
+async_desc_pool_t async_desc_pool;
+// This is meant to be PER USER THREAD!!! (TODO (benh))
+async_desc_t* current_async_desc;
 
 void
 libmain(int argc, char **argv)
@@ -20,6 +24,8 @@ libmain(int argc, char **argv)
 
        // Set up the front ring for the general syscall ring
        FRONT_RING_INIT(&sysfrontring, (syscall_sring_t*)procdata, PGSIZE);     
+       POOL_INIT(&syscall_desc_pool, MAX_SYSCALLS);            
+       POOL_INIT(&async_desc_pool, MAX_ASYNCCALLS);            
 
        // save the name of the program so that panic() can use it
        if (argc > 0)
index 1b26f37..e1bc29a 100644 (file)
@@ -62,34 +62,30 @@ cprintf(const char *fmt, ...)
 
 // Temp async varieties
 #define MAX_BUFFERS 10
-printbuf_t async_bufs[MAX_BUFFERS];
-uint32_t full_buffers = 0;
+POOL_TYPE_DEFINE(printbuf_t, print_buf_pool, MAX_BUFFERS);
+print_buf_pool_t print_buf_pool;
+
+static error_t init_printf(void)
+{
+       POOL_INIT(&print_buf_pool, MAX_BUFFERS);
+       return 0;
+}
 
 static printbuf_t* get_free_buffer(void)
 {
-       // reserve a buffer.  if we actually get one, return it.  o/w, bail out.
-       // want to do this atomically eventually.
-       full_buffers++;
-       if (full_buffers <= MAX_BUFFERS)
-               return &async_bufs[full_buffers - 1];
-       full_buffers--;
-       // synchronously warn.  could consider blocking in the future
-       cprintf("Out of buffers!!!\n");
-       return NULL;
+       return POOL_GET(&print_buf_pool);
+       //cprintf("Out of buffers!!!\n");
 }
 
 // this buffering is a minor pain in the ass....
+// TODO - it will be a pain in the ass to put the buffers back after we waited.
 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, &desc);
-
-// push this up a few layers
-syscall_rsp_t rsp;
-waiton_syscall(&desc, &rsp);
+               sys_cputs_async(b->buf, b->idx, get_sys_desc(current_async_desc));
+               // TODO - this isn't getting passed back properly
                b = get_free_buffer();
                b->idx = 0;
        }
@@ -98,26 +94,28 @@ waiton_syscall(&desc, &rsp);
 
 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();
 
        b->idx = 0;
        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, &desc);
-// push this up a few layers
-syscall_rsp_t rsp;
-waiton_syscall(&desc, &rsp);
+       sys_cputs_async(b->buf, b->idx, get_sys_desc(current_async_desc));
 
        return b->cnt; // this is lying if we used more than one buffer
 }
 
-int cprintf_async(const char *fmt, ...)
+int cprintf_async(async_desc_t** desc, const char *fmt, ...)
 {
        va_list ap;
        int cnt;
+       static bool initialized = 0;
+       if (!initialized) {
+               init_printf();
+       initialized = TRUE;
+       }
+       current_async_desc = get_async_desc();
+       *desc = current_async_desc;
 
        va_start(ap, fmt);
        cnt = vcprintf_async(fmt, ap);
index 9227a06..8ff24e6 100644 (file)
@@ -1,6 +1,10 @@
 // hello, world
 #include <inc/lib.h>
 
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
 void umain(void)
 {
        cprintf("goodbye, world!\n");
@@ -13,10 +17,18 @@ void umain(void)
        // since the library functions use the same buffer.  the last used string
        // 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);
+       async_desc_t *desc1, *desc2, *desc3;
+       cprintf_async(&desc1, "Cross-Core call 1, coming from env %08x\n", env->env_id);
        cprintf("Call 1 is sent!\n");
-       cprintf_async("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXCross-Core call 2, coming from env %08x\n", env->env_id);
+       //cprintf_async(&desc2, "Cross-Core call 2, coming from env %08x\n", env->env_id);
+       cprintf_async(&desc2, "1111111111111111111111111111111122222222222222222222222222222222333333333333333333333333333333334444444444444444444444444444444455555555555555555555555555555555666666666666666666666666666666667777777777777777777777777777777788888888888888888888888888888888Cross-Core call 2, coming from env %08x\n", env->env_id);
        cprintf("Call 2 is sent!\n");
+       cprintf("Waiting on Call 1 and 2\n");
+       waiton_async_call(desc1);
+       cprintf("Received 1\n");
+       waiton_async_call(desc2);
+       cprintf_async(&desc3, "Cross-Core call 3, coming from env %08x\n", env->env_id);
+       cprintf("Call 3 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);