Poor-mans async printf support for userspace
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 1 May 2009 23:30:37 +0000 (16:30 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 1 May 2009 23:30:37 +0000 (16:30 -0700)
It's very rudimentary.  Not threadsafe, and it only allows 10
cprintf_asyncs.  Ever.  No tracking of when the async calls are done.
If putch uses more than one buffer, the overall count return is a lie
too.  The userspace side of syscall_async can only send two calls.

kern/init.c
lib/printf.c
lib/syscall.c
user/hello.c

index 47b0520..bf7243a 100644 (file)
@@ -62,8 +62,8 @@ void kernel_init(multiboot_info_t *mboot_info)
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
 
-       test_smp_call_functions();
        /*
+       test_smp_call_functions();
        test_checklists();
        test_barrier();
        test_print_info();
@@ -80,7 +80,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        //ENV_CREATE(user_divzero);
        //ENV_CREATE(user_buggyhello);
        ENV_CREATE(user_hello);
-       ENV_CREATE(user_hello);
+       //ENV_CREATE(user_hello);
        //ENV_CREATE(user_evilhello);
 
        // We only have one user environment for now, so just run it.
@@ -88,7 +88,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        // run_env_handler just runs the first env, like the prev command
        // need a way to have call_func to pass a pointer to a struct for arguments
        smp_call_function_single(2, run_env_handler, &envs[0], 0);
-       smp_call_function_single(4, run_env_handler, &envs[1], 0);
+       //smp_call_function_single(4, run_env_handler, &envs[1], 0);
 
        // wait 5 sec, then print what's in shared mem
        udelay(5000000);
@@ -101,16 +101,19 @@ void kernel_init(multiboot_info_t *mboot_info)
                *(uint32_t*)(envs[0].env_procdata + 12));
                */
 
-       printk("Attempting to run the syscall at the beginning of procdata for env 0:\n\n");
+       printk("Attempting to run two syscalls at the beginning of procdata for env 0:\n\n");
        // need to switch to the right context, so we can handle the user pointer
        // that points to a data payload of the syscall
        lcr3(envs[0].env_cr3);
        syscall_async((syscall_t*)(envs[0].env_procdata));
+       syscall_async(((syscall_t*)(envs[0].env_procdata)) + 1);
        printk("\n");
+       /*
        printk("Attempting to run the syscall at the beginning of procdata for env 1:\n\n");
        lcr3(envs[1].env_cr3);
        syscall_async((syscall_t*)(envs[1].env_procdata));
        printk("\n");
+       */
        panic("Don't Panic");
 }
 
index 07a2a6c..abacd4a 100644 (file)
@@ -61,27 +61,48 @@ cprintf(const char *fmt, ...)
 }
 
 // Temp async varieties
-static void
-putch_async(int ch, printbuf_t *b)
+#define MAX_BUFFERS 10
+printbuf_t async_bufs[MAX_BUFFERS];
+uint32_t full_buffers = 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;
+}
+
+// this buffering is a minor pain in the ass....
+static void putch_async(int ch, printbuf_t *b)
 {
        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);
+               b = get_free_buffer();
                b->idx = 0;
        }
-       b->cnt++;
+       b->cnt++; // supposed to be overall number, not just in one buffer
 }
 
 static int vcprintf_async(const char *fmt, va_list ap)
 {
-       printbuf_t b;
+       // start with an available buffer
+       printbuf_t* b = get_free_buffer();
 
-       b.idx = 0;
-       b.cnt = 0;
-       vprintfmt((void*)putch_async, &b, fmt, ap);
-       sys_cputs_async(b.buf, b.idx);
+       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);
 
-       return b.cnt;
+       return b->cnt; // this is lying if we used more than one buffer
 }
 
 int cprintf_async(const char *fmt, ...)
index 00fe08e..7b9e415 100644 (file)
@@ -36,9 +36,12 @@ syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5
 
 static inline error_t async_syscall(syscall_t *syscall)
 {
-       // testing just one syscall at a time, and just put it at the beginning of
-       // the shared data page
-       memcpy(procdata, syscall, sizeof(syscall_t));
+       // testing just two syscalls at a time, and just put it at the beginning of
+       // the shared data page.  This is EXTREMELY GHETTO....
+       if ( ((syscall_t*)procdata)->args[0] ) // something there, presumably the first syscall
+               memcpy(((void*)procdata) + sizeof(syscall_t), syscall, sizeof(syscall_t));
+       else // nothing there, this is the first one
+               memcpy(procdata, syscall, sizeof(syscall_t));
        return 0;
 }
 
index f12f68f..ea2c0a2 100644 (file)
@@ -13,8 +13,9 @@ 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, coming from env %08x\n", env->env_id);
-
+       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");
        // might as well spin, just to make sure nothing gets deallocated
        // while we're waiting to test the async call
        while (1);