Bring back the ARSC functionality that was removed earlier.
authorDavid Zhu <yuzhu@cs.berkeley.edu>
Wed, 4 Aug 2010 22:17:57 +0000 (15:17 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:51 +0000 (17:35 -0700)
ARSC server are now running on a management core.
Separate lists are maintainted for those processes interested in ARSC.
Need to rebuild crosscompiler because of an addition to syscall numbers.

20 files changed:
Makeconfig
Makelocal.template
kern/include/arsc_server.h [new file with mode: 0644]
kern/include/env.h
kern/include/ros/bits/syscall.h
kern/include/ros/procdata.h
kern/include/ros/ring_syscall.h
kern/include/syscall.h
kern/src/Makefrag
kern/src/arsc.c [new file with mode: 0644]
kern/src/manager.c
kern/src/process.c
kern/src/syscall.c
tests/arsc_test.c [new file with mode: 0644]
user/include/arc.h [new file with mode: 0644]
user/include/parlib.h
user/include/pool.h [new file with mode: 0644]
user/parlib/Makefrag
user/parlib/asynccall.c [new file with mode: 0644]
user/parlib/syscall.c

index c55d21e..3c90e20 100644 (file)
@@ -25,6 +25,7 @@ CONFIG_DISABLE_MPTABLES:=          -D__CONFIG_DISABLE_MPTABLES__
 CONFIG_MONITOR_ON_INT:=            -D__CONFIG_MONITOR_ON_INT__
 CONFIG_DISABLE_SMT:=               -D__CONFIG_DISABLE_SMT__
 CONFIG_BOXBORO:=                   -D__CONFIG_BOXBORO__
+CONFIG_ARSC_SERVER:=               -D__CONFIG_ARSC_SERVER__
 
 # Userspace configuration parameters
 # By default, each of these options will be turned off
index 5fe097f..be1b384 100644 (file)
@@ -1,5 +1,8 @@
 # General Purpose configuration parameters
 #CFLAGS += $(CONFIG_APPSERVER)
+#CFLAGS += $(CONFIG_OSDI)
+#CFLAGS += $(CONFIG_CACHEEFFECT)
+#CFLAGS += $(CONFIG_NOPTHREAD_YIELD)
 
 # Kernel configuration parameters
 #KERN_CFLAGS += $(CONFIG_KFS)
@@ -20,6 +23,8 @@
 #KERN_CFLAGS += $(CONFIG_MONITOR_ON_INT)
 #KERN_CFLAGS += $(CONFIG_DISABLE_SMT)
 #KERN_CFLAGS += $(CONFIG_BOXBORO)
+# Enable this to set up ARSC server
+#KERN_CFLAGS += $(CONFIG_ARSC_SERVER)
 
 #KERN_CFLAGS += -DDEVELOPER_NAME=waterman
 #KERN_CFLAGS += -DDEVELOPER_NAME=brho
diff --git a/kern/include/arsc_server.h b/kern/include/arsc_server.h
new file mode 100644 (file)
index 0000000..72c52fa
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2009 The Regents of the University  of California.  
+ * See the COPYRIGHT files at the top of this source tree for full 
+ * license information.
+ */
+#ifndef _ROS_ARSC_SERVER_H
+#define __ROS_ARSC_SERVER_H
+#include <ros/common.h>
+#include <ros/ring_syscall.h>
+#include <arch/types.h>
+#include <arch/arch.h>
+
+#include <process.h>
+#include <syscall.h>
+#include <error.h>
+
+extern struct proc_list arsc_proc_list;
+extern spinlock_t arsc_proc_lock;
+
+intreg_t sys_init_arsc(struct proc* p);
+intreg_t syscall_async(struct proc* p, syscall_req_t *syscall);
+void arsc_server(trapframe_t *tf);
+
+static intreg_t process_generic_syscalls(struct proc* p, size_t max);
+#endif //ARSC_SERVER
index d36ed41..cdc08b2 100644 (file)
@@ -23,6 +23,7 @@
 // TODO: clean this up.
 struct proc {
        TAILQ_ENTRY(proc) proc_link NOINIT;     // Free list link pointers
+       TAILQ_ENTRY(proc) proc_arsc_link NOINIT; // Free list link pointers for the arsc list
        spinlock_t proc_lock;
        trapframe_t env_tf;                                             // Saved registers
        ancillary_state_t env_ancillary_state;  // State saved when descheduled
index a1d8788..17ae34f 100644 (file)
@@ -38,6 +38,9 @@
 #define SYS_self_notify                                26
 #define SYS_halt_core                          27
 
+/* ARSC call init */
+#define SYS_init_arsc                          28
+
 /* Platform specific syscalls */
 #define SYS_serial_read                                75
 #define SYS_serial_write                       76
index e56f3a4..2d92cf6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <ros/memlayout.h>
 #include <ros/ring_syscall.h>
+#include <ros/sysevent.h>
 #include <ros/arch/arch.h>
 #include <ros/common.h>
 #include <ros/procinfo.h>
index 9f8be05..42d193e 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <ros/common.h>
 #include <ros/ring_buffer.h>
-#include <ros/sysevent.h>
 
 #define NUM_SYSCALL_ARGS 6
 typedef struct syscall_req {
index 82aea0e..a98bb3a 100644 (file)
@@ -14,6 +14,8 @@
 #define MAX_NUM_TRACED                         10
 #define MAX_SYSTRACES                          1024
 
+#define MAX_ASRC_BATCH                         10
+
 /* Consider cache aligning this */
 struct systrace_record {
        uint64_t                timestamp;
@@ -23,10 +25,9 @@ struct systrace_record {
        uint32_t                vcoreid;
 };
 
+
 intreg_t syscall(struct proc *p, uintreg_t num, uintreg_t a1, uintreg_t a2,
                  uintreg_t a3, uintreg_t a4, uintreg_t a5);
-intreg_t syscall_async(env_t* e, syscall_req_t *syscall);
-intreg_t process_generic_syscalls(env_t* e, size_t max);
 
 /* Tracing functions */
 void systrace_start(bool silent);
index 6497799..0bd36fb 100644 (file)
@@ -43,7 +43,8 @@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) \
                  $(KERN_SRC_DIR)/vfs.c \
                  $(KERN_SRC_DIR)/radix.c \
                  $(KERN_SRC_DIR)/umem.c \
-                 $(KERN_SRC_DIR)/testing.c
+                 $(KERN_SRC_DIR)/testing.c \
+                 $(KERN_SRC_DIR)/arsc.c
 
 # Only build files if they exist.
 KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
diff --git a/kern/src/arsc.c b/kern/src/arsc.c
new file mode 100644 (file)
index 0000000..7f6fe37
--- /dev/null
@@ -0,0 +1,112 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+
+#include <ros/common.h>
+#include <ros/ring_syscall.h>
+#include <arch/types.h>
+#include <arch/arch.h>
+#include <arch/mmu.h>
+#include <error.h>
+
+#include <syscall.h>
+#include <kmalloc.h>
+#include <pmap.h>
+#include <stdio.h>
+#include <hashtable.h>
+#include <arsc_server.h>
+
+
+
+struct proc_list arsc_proc_list = TAILQ_HEAD_INITIALIZER(arsc_proc_list);
+spinlock_t arsc_proc_lock = SPINLOCK_INITIALIZER;
+
+intreg_t syscall_async(struct proc *p, syscall_req_t *call)
+{
+       return syscall(p, call->num, call->args[0], call->args[1],
+                      call->args[2], call->args[3], call->args[4]);
+}
+
+intreg_t sys_init_arsc(struct proc* p)
+{
+       spin_lock_irqsave(&arsc_proc_lock);
+       TAILQ_INSERT_TAIL(&arsc_proc_list, p, proc_arsc_link);
+       spin_unlock_irqsave(&arsc_proc_lock);
+       return ESUCCESS;
+}
+
+
+void arsc_server(trapframe_t *tf)
+{
+       struct proc *p = NULL;
+       TAILQ_INIT(&arsc_proc_list);
+       while (true)
+       {
+               while (TAILQ_EMPTY(&arsc_proc_list))
+                       cpu_relax();
+
+               printd ("detected process\n");
+               TAILQ_FOREACH(p, &arsc_proc_list, proc_link)
+               {
+                       // TODO: we may need an atomic swap to inc ref count
+                       if (p->state != PROC_DYING)
+                               process_generic_syscalls (p, MAX_ASRC_BATCH); 
+               }
+       }
+}
+
+static intreg_t process_generic_syscalls(struct proc *p, size_t max)
+{
+       size_t count = 0;
+       syscall_back_ring_t* sysbr = &p->syscallbackring;
+       // looking at a process not initialized to perform arsc. 
+       if (sysbr == NULL) 
+               return count;
+
+       /* make sure the proc is still alive, and keep it from dying from under us
+        * incref will return ESUCCESS on success.  This might need some thought
+        * regarding when the incref should have happened (like by whoever passed us
+        * the *p). */
+       // TODO: ought to be unnecessary, if you called this right, kept here for
+       // now in case anyone actually uses the ARSCs.
+       kref_get(&p->kref, 1);
+
+       // max is the most we'll process.  max = 0 means do as many as possible
+       // TODO: check for initialization of the ring. 
+       while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) {
+               printd ("start processing req %d\n", count);
+               if (!count) {
+                       // ASSUME: one queue per process
+                       // only switch cr3 for the very first request for this queue
+                       // need to switch to the right context, so we can handle the user pointer
+                       // that points to a data payload of the syscall
+                       lcr3(p->env_cr3);
+               }
+               count++;
+               //printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n",
+               //         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_rsp_t rsp;
+               // this assumes we get our answer immediately for the syscall.
+               syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
+               // print req
+               printd("req no %d, req arg %c\n", req->num, *((char*)req->args[0]));
+               rsp.retval = syscall_async(p, req);
+               // write response into the slot it came from
+               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);
+               //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",
+               //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
+       }
+       // load sane page tables (and don't rely on decref to do it for you).
+       lcr3(boot_cr3);
+       kref_put(&p->kref);
+       return (intreg_t)count;
+}
+
index e7c675c..139c90e 100644 (file)
@@ -265,6 +265,24 @@ void manager_pearce()
 
 }
 
+void manager_yuzhu()
+{
+       
+       static uint8_t RACY progress = 0;
+       static struct proc *p;
+
+       // for testing taking cores, check in case 1 for usage
+       uint32_t corelist[MAX_NUM_CPUS];
+       uint32_t num = 3;
+
+       //create_server(init_num_cores, loop);
+
+       monitor(0);
+
+       // quick_proc_run("hello", p);
+
+}
+
 #ifdef __sparc_v8__
 
 static char*
index efdaaaa..0e0100f 100644 (file)
@@ -26,6 +26,7 @@
 #include <monitor.h>
 #include <resource.h>
 #include <elf.h>
+#include <arsc_server.h>
 
 /* Process Lists */
 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
@@ -200,9 +201,16 @@ void proc_init(void)
        assert(!(num_cpus % 2));
        // TODO: consider checking x86 for machines that actually hyperthread
        num_idlecores = num_cpus >> 1;
+#ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(2, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+#endif
        for (int i = 0; i < num_idlecores; i++)
                idlecoremap[i] = (i * 2) + 1;
 #else
+       // __CONFIG_DISABLE_SMT__
        #ifdef __CONFIG_NETWORKING__
        num_mgmtcores++; // Next core is dedicated to the NIC
        assert(num_cpus >= num_mgmtcores);
@@ -215,10 +223,17 @@ void proc_init(void)
        send_kernel_message(num_mgmtcores-1, (amr_t)monitor, 0,0,0, KMSG_ROUTINE);
        #endif
        #endif
+#ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(num_mgmtcores-1, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+#endif
        num_idlecores = num_cpus - num_mgmtcores;
        for (int i = 0; i < num_idlecores; i++)
                idlecoremap[i] = i + num_mgmtcores;
 #endif /* __CONFIG_DISABLE_SMT__ */
+
        spin_unlock(&idle_lock);
        atomic_init(&num_envs, 0);
 }
@@ -271,9 +286,6 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
                kmem_cache_free(proc_cache, p);
                return -ENOFREEPID;
        }
-       spin_lock(&pid_hash_lock);
-       hashtable_insert(pid_hash, (void*)p->pid, p);
-       spin_unlock(&pid_hash_lock);
        /* Set the basic status variables. */
        spinlock_init(&p->proc_lock);
        p->exitcode = 0;
@@ -348,6 +360,11 @@ struct proc *proc_create(struct file *prog, char **argv, char **envp)
                panic("proc_create: %e", r);    /* one of 3 quaint usages of %e */
        procinfo_pack_args(p->procinfo, argv, envp);
        assert(load_elf(p, prog) == 0);
+       
+       // only insert into the global hashtable after all thei initialization is done
+       spin_lock(&pid_hash_lock);
+       hashtable_insert(pid_hash, (void*)p->pid, p);
+       spin_unlock(&pid_hash_lock);
        return p;
 }
 
@@ -450,6 +467,7 @@ void proc_run(struct proc *p)
                         * back to userspace.  */
                        spin_unlock(&p->proc_lock);
                        disable_irq();
+
                        __proc_startcore(p, &p->env_tf);
                        break;
                case (PROC_RUNNABLE_M):
@@ -530,6 +548,7 @@ static void __proc_startcore(struct proc *p, trapframe_t *tf)
         * __startcore.  */
        if (p->state == PROC_RUNNING_S)
                env_pop_ancillary_state(p);
+       
        env_pop_tf(tf);
 }
 
@@ -579,8 +598,16 @@ void proc_restartcore(struct proc *p, trapframe_t *tf)
 void proc_destroy(struct proc *p)
 {
        bool self_ipi_pending = FALSE;
-
+       
+#ifdef __CONFIG_ARSC_SERVER__
+       spin_lock_irqsave(&arsc_proc_lock);
+
+       // remove from ARSC list
+       TAILQ_REMOVE(&arsc_proc_list, p, proc_arsc_link);
+       spin_unlock_irqsave(&arsc_proc_lock);
+#endif 
        spin_lock(&p->proc_lock);
+       
 
        /* TODO: (DEATH) look at this again when we sort the __death IPI */
        if (current == p)
index 21c2df6..1b934a2 100644 (file)
 #include <resource.h>
 #include <frontend.h>
 #include <colored_caches.h>
+#include <hashtable.h>
 #include <arch/bitmask.h>
 #include <kfs.h> // eventually replace this with vfs.h
+#include <arsc_server.h>
 
 
 #ifdef __CONFIG_NETWORKING__
@@ -1071,16 +1073,21 @@ intreg_t sys_tcsetattr(struct proc *p, int fd, int optional_actions,
  * Note tf is passed in, which points to the tf of the context on the kernel
  * stack.  If any syscall needs to block, it needs to save this info, as well as
  * any silly state.
+ * 
+ * This syscall function is used by both local syscall and arsc, and should
+ * remain oblivious of the caller.
  *
- * TODO: Build a dispatch table instead of switching on the syscallno
- * Dispatches to the correct kernel function, passing the arguments.
+ * TODO: Keep in mind that not every syscall has a user trapframe. 
+ * e.g. ARSC
  */
 intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
 {
        // Initialize the return value and error code returned to 0
-       proc_set_syscall_retval(current_tf, 0);
-       set_errno(current_tf,0);
+       if(current_tf != NULL){
+               proc_set_syscall_retval(&p->env_tf, ESUCCESS);
+               set_errno(current_tf,0);
+       }
 
        typedef intreg_t (*syscall_t)(struct proc*,uintreg_t,uintreg_t,
                                      uintreg_t,uintreg_t,uintreg_t);
@@ -1121,6 +1128,10 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                [SYS_eth_get_mac_addr] = (syscall_t)sys_eth_get_mac_addr,
                [SYS_eth_recv_check] = (syscall_t)sys_eth_recv_check,
        #endif
+       #ifdef __CONFIG_ARSC_SERVER__
+               [SYS_init_arsc] = (syscall_t)sys_init_arsc,
+       #endif
+               // Syscalls serviced by the appserver for now.
                [SYS_read] = (syscall_t)sys_read,
                [SYS_write] = (syscall_t)sys_write,
                [SYS_open] = (syscall_t)sys_open,
@@ -1178,58 +1189,6 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
        return syscall_table[syscallno](p,a1,a2,a3,a4,a5);
 }
 
-intreg_t syscall_async(struct proc *p, syscall_req_t *call)
-{
-       return syscall(p, call->num, call->args[0], call->args[1],
-                      call->args[2], call->args[3], call->args[4]);
-}
-
-/* You should already have a refcnt'd ref to p before calling this */
-intreg_t process_generic_syscalls(struct proc *p, size_t max)
-{
-       size_t count = 0;
-       syscall_back_ring_t* sysbr = &p->syscallbackring;
-
-       /* make sure the proc is still alive, and keep it from dying from under us
-        * incref will return ESUCCESS on success.  This might need some thought
-        * regarding when the incref should have happened (like by whoever passed us
-        * the *p). */
-       // TODO: ought to be unnecessary, if you called this right, kept here for
-       // now in case anyone actually uses the ARSCs.
-       kref_get(&p->kref, 1);
-
-       // max is the most we'll process.  max = 0 means do as many as possible
-       while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) {
-               if (!count) {
-                       // ASSUME: one queue per process
-                       // only switch cr3 for the very first request for this queue
-                       // need to switch to the right context, so we can handle the user pointer
-                       // that points to a data payload of the syscall
-                       lcr3(p->env_cr3);
-               }
-               count++;
-               //printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n",
-               //         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_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(p, req);
-               // write response into the slot it came from
-               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);
-               //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",
-               //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
-       }
-       // load sane page tables (and don't rely on decref to do it for you).
-       lcr3(boot_cr3);
-       kref_put(&p->kref);
-       return (intreg_t)count;
-}
-
 /* Syscall tracing */
 static void __init_systrace(void)
 {
diff --git a/tests/arsc_test.c b/tests/arsc_test.c
new file mode 100644 (file)
index 0000000..b31fef4
--- /dev/null
@@ -0,0 +1,29 @@
+#include <parlib.h>
+#include <vcore.h>
+#include <ros/syscall.h>
+#include <arc.h>
+
+int sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,                                              
+                     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_SYSCALL_ARGS-1)] 0} };                          
+    desc->cleanup = cleanup_handler;                                                                                  
+    desc->data = cleanup_data;                                                                                        
+    return async_syscall(&syscall, desc);                                                                             
+}     
+int main(int argc, char** argv){
+       int pid = sys_getpid();
+       char testme = 't';
+       printf ("single thread - init arsc \n");
+       init_arc();
+       async_desc_t desc1;
+       async_rsp_t rsp1;
+       syscall_rsp_t sysrsp;
+
+       syscall_desc_t* sysdesc = get_sys_desc (&desc1);
+       // cprintf_async(&desc1, "Cross-Core call 1, coming from process %08x\n", pid);
+       sys_cputs_async(&testme, 1, sysdesc, NULL, NULL);
+       waiton_syscall(sysdesc, &sysrsp);
+       printf ("single thread - dummy call \n");       
+}
diff --git a/user/include/arc.h b/user/include/arc.h
new file mode 100644 (file)
index 0000000..772f5ac
--- /dev/null
@@ -0,0 +1,87 @@
+// Header for Asynch Remote Call, currently only support remote syscalls.
+#ifndef _ARC_H
+#define _ARC_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#include <parlib.h>
+#include <error.h>
+#include <pool.h>
+#include <assert.h>
+#include <sys/queue.h>
+#include <ros/ring_syscall.h>
+
+extern syscall_front_ring_t syscallfrontring;
+extern sysevent_back_ring_t syseventbackring;
+
+/*
+ * Syscall Descriptor: This helps userspace track a specific syscall.  Includes
+ * a cleanup function to be run when this syscall is complete.  Linked list of
+ * these for now. (Tail Queue)
+ */
+typedef struct syscall_desc syscall_desc_t;
+struct syscall_desc {
+       TAILQ_ENTRY(syscall_desc) next;
+       syscall_front_ring_t* sysfr;
+       uint32_t idx;
+       // cleanup
+       void (*cleanup)(void* data);
+       void* data;
+};
+TAILQ_HEAD(syscall_desc_list, syscall_desc);
+typedef struct syscall_desc_list syscall_desc_list_t;
+
+
+// TODO: where to declare async syscalls?
+
+// async callback
+#define MAX_SYSCALLS 100
+#define MAX_ASYNCCALLS 100
+
+// The high-level object a process waits on, with multiple syscalls within.
+typedef struct async_desc {
+       syscall_desc_list_t syslist;
+       void (*cleanup)(void* data);
+       void* data;
+} async_desc_t;
+
+// Response to an async call.  Should be some sort of aggregation of the
+// syscall responses.
+typedef struct async_rsp_t {
+       int32_t retval;
+} async_rsp_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;
+
+// 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 asynccall.c
+extern syscall_desc_pool_t syscall_desc_pool;
+extern async_desc_pool_t async_desc_pool;
+
+/* Initialize front and back rings of syscall/event ring */
+void init_arc();
+
+/* Generic Async Call */
+int waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp);
+
+/* Async group call */
+int waiton_async_call(async_desc_t* desc, async_rsp_t* rsp);
+
+int async_syscall(syscall_req_t* req, syscall_desc_t* desc);
+
+async_desc_t* get_async_desc(void);
+syscall_desc_t* get_sys_desc(async_desc_t* desc);
+int get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index f9312df..aab0181 100644 (file)
@@ -49,6 +49,9 @@ int         sys_self_notify(uint32_t vcoreid, unsigned int notif,
                             struct notif_event *ne);
 int         sys_halt_core(unsigned int usec);
 
+/* ARSC */
+int                    sys_init_arsc();
+
 #endif // !ASSEMBLER
 
 #endif // !ROS_INC_PARLIB_H
diff --git a/user/include/pool.h b/user/include/pool.h
new file mode 100644 (file)
index 0000000..948fbe8
--- /dev/null
@@ -0,0 +1,75 @@
+/* See COPYRIGHT for copyright information. */
+/* Kevin Klues <klueska@cs.berkeley.edu>       */
+
+#ifndef ROS_INC_POOL_H
+#define ROS_INC_POOL_H
+
+#include <string.h>
+
+#define POOL_TYPE_DEFINE(_type, p, sz)                                                \
+typedef struct struct_##p {                                                             \
+       uint32_t size;                                                         \
+       uint32_t free;                                                         \
+       uint32_t index;                                                        \
+       _type*COUNT(1) queue[(sz)];                                                       \
+       _type pool[(sz)];                                                         \
+} p##_t;
+
+#define POOL_INIT(p, sz)                                                       \
+({                                                                             \
+       (p)->size = (sz);                                                          \
+       (p)->free = (sz);                                                          \
+       (p)->index = 0;                                                            \
+       memset((p)->pool, 0, (sz) * sizeof((p)->pool[0]));                         \
+       for(int i=0; i<(p)->size; i++) {                                           \
+               (p)->queue[i] = &((p)->pool[i]);                                       \
+       }                                                                          \
+})
+// removed unnecessary (p)->queue[(p)->index] = NULL;
+#define POOL_GET(p)                                            \
+({                                                             \
+       void* rval = NULL;                                         \
+       if((p)->free) {                                            \
+               rval = (p)->queue[(p)->index];                         \
+               (p)->free--;                                           \
+               (p)->index++;                                          \
+               if((p)->index == (p)->size) {                          \
+               (p)->index = 0;                                    \
+       }                                                      \
+       }                                                          \
+       rval;                                                      \
+})
+
+// emptyIndex is also the first element that has been allocated, iterate thru to index-1
+
+#define POOL_FOR_EACH(p, func)                                                                 \
+({                                                                                                                             \
+       int emptyIndex = ((p)->index + (p)->free);                  \
+       if (emptyIndex >= (p)->size) {                                          \
+               emptyIndex -= (p)->size;                                        \
+       }                                                                   \
+       for(int _i = emptyIndex;  _i < (p)->index; _i++){                       \
+               func((p)->queue[_i]);                                                           \
+       }                                                                                                                       \
+})                                                                                                                             \
+
+#define POOL_PUT(p, val)                                                       \
+({                                                                             \
+       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++;                                                   \
+               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_INC_POOL_H
index 384c751..5c310e8 100644 (file)
@@ -18,7 +18,8 @@ USER_PARLIB_SRCFILES := \
                  $(USER_PARLIB_DIR)/syscall.c \
                  $(USER_PARLIB_DIR)/debugfmt.c \
                  $(USER_PARLIB_DIR)/timing.c \
-                 $(USER_PARLIB_DIR)/debug.c
+                 $(USER_PARLIB_DIR)/debug.c \
+                 $(USER_PARLIB_DIR)/asynccall.c
 
 # Only build files if they exist.
 USER_PARLIB_SRCFILES := $(wildcard $(USER_PARLIB_SRCFILES))
diff --git a/user/parlib/asynccall.c b/user/parlib/asynccall.c
new file mode 100644 (file)
index 0000000..f9aefd9
--- /dev/null
@@ -0,0 +1,158 @@
+#include <stdlib.h>
+
+#include <ros/common.h>
+#include <ros/syscall.h>
+#include <ros/ring_syscall.h>
+#include <ros/sysevent.h>
+#include <arc.h>
+#include <errno.h>
+#include <arch/arch.h>
+
+syscall_front_ring_t syscallfrontring;
+sysevent_back_ring_t syseventbackring;
+syscall_desc_pool_t syscall_desc_pool;
+async_desc_pool_t async_desc_pool;
+async_desc_t* current_async_desc;
+
+// use globals for now
+void init_arc()
+{
+       // Set up the front ring for the general syscall ring
+       // and the back ring for the general sysevent ring
+       // TODO: Reorganize these global variables
+       FRONT_RING_INIT(&syscallfrontring, &(__procdata.syscallring), SYSCALLRINGSIZE);
+       BACK_RING_INIT(&syseventbackring, &(__procdata.syseventring), SYSEVENTRINGSIZE);
+       POOL_INIT(&syscall_desc_pool, MAX_SYSCALLS);
+       POOL_INIT(&async_desc_pool, MAX_ASYNCCALLS);
+       sys_init_arsc();
+
+
+}
+// Wait on all syscalls within this async call.  TODO - timeout or something?
+int waiton_async_call(async_desc_t* desc, async_rsp_t* rsp)
+{
+       syscall_rsp_t syscall_rsp;
+       syscall_desc_t* d;
+       int err = 0;
+       if (!desc) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       while (!(TAILQ_EMPTY(&desc->syslist))) {
+               d = TAILQ_FIRST(&desc->syslist);
+               err = waiton_syscall(d, &syscall_rsp);
+               // TODO: processing the retval out of rsp here.  might be specific to
+               // the async call.  do we want to accumulate?  return any negative
+               // values?  depends what we want from the return value, so we might
+               // have to pass in a function that is used to do the processing and
+               // pass the answer back out in rsp.
+               //rsp->retval += syscall_rsp.retval; // For example
+               rsp->retval = MIN(rsp->retval, syscall_rsp.retval);
+               // remove from the list and free the syscall desc
+               TAILQ_REMOVE(&desc->syslist, d, next);
+               POOL_PUT(&syscall_desc_pool, d);
+       }
+       // run a cleanup function for this desc, if available
+       if (desc->cleanup)
+               desc->cleanup(desc->data);
+       // free the asynccall desc
+       POOL_PUT(&async_desc_pool, desc);
+       return err;
+}
+
+// Finds a free async_desc_t, on which you can wait for a series of syscalls
+async_desc_t* get_async_desc(void)
+{
+       async_desc_t* desc = POOL_GET(&async_desc_pool);
+       if (desc) {
+               // Clear out any data that was in the old desc
+               memset(desc, 0, sizeof(*desc));
+               TAILQ_INIT(&desc->syslist);
+       }
+       return 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_desc_t* d = POOL_GET(&syscall_desc_pool);
+       if (d) {
+               // Clear out any data that was in the old desc
+               memset(d, 0, sizeof(*d));
+       TAILQ_INSERT_TAIL(&desc->syslist, d, next);
+       }
+       return d;
+}
+
+// Gets an async and a sys desc, with the sys bound to async.  Also sets
+// current_async_desc.  This is meant as an easy wrapper when there is only one
+// syscall for an async call.
+int get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc)
+{
+       assert(a_desc && s_desc);
+       if ((current_async_desc = get_async_desc()) == NULL){
+               errno = EBUSY;
+               return -1;
+       }
+       *a_desc = current_async_desc;
+       if ((*s_desc = get_sys_desc(current_async_desc)))
+               return 0;
+       // in case we could get an async, but not a syscall desc, then clean up.
+       POOL_PUT(&async_desc_pool, current_async_desc);
+       current_async_desc = NULL;
+       errno = EBUSY;
+       return -1;
+}
+
+// This runs one syscall instead of a group. 
+int async_syscall(syscall_req_t* req, syscall_desc_t* desc)
+{
+       // Note that this assumes one global frontring (TODO)
+       // abort if there is no room for our request.  ring size is currently 64.
+       // we could spin til it's free, but that could deadlock if this same thread
+       // is supposed to consume the requests it is waiting on later.
+       if (RING_FULL(&syscallfrontring)) {
+               errno = EBUSY;
+               return -1;
+       }
+       // 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.
+       // at some point, we need to listen for the responses.
+       desc->idx = ++(syscallfrontring.req_prod_pvt);
+       desc->sysfr = &syscallfrontring;
+       syscall_req_t* r = RING_GET_REQUEST(&syscallfrontring, desc->idx);
+       memcpy(r, req, sizeof(syscall_req_t));
+       // push our updates to syscallfrontring.req_prod_pvt
+       RING_PUSH_REQUESTS(&syscallfrontring);
+       //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", 
+       //   syscallfrontring.sring->req_prod, syscallfrontring.sring->rsp_prod);
+       return 0;
+}
+
+// consider a timeout too
+int waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
+{
+       // Make sure we were given a desc with a non-NULL frontring.  This could
+       // happen if someone forgot to check the error code on the paired syscall.
+       if (!desc->sysfr){
+               errno = EFAIL;
+               return -1;
+       }
+       // this forces us to call wait in the order in which the syscalls are made.
+       if (desc->idx != desc->sysfr->rsp_cons + 1){
+               errno = EDEADLOCK;
+               return -1;
+       }
+       while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
+               cpu_relax();
+       memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
+       desc->sysfr->rsp_cons++;
+    // run a cleanup function for this desc, if available
+    if (desc->cleanup)
+       desc->cleanup(desc->data);
+       return 0;
+}
+
+
index 0b04e7a..fded922 100644 (file)
@@ -141,3 +141,8 @@ int sys_halt_core(unsigned int usec)
 {
        return ros_syscall(SYS_halt_core, usec, 0, 0, 0, 0);
 }
+
+int sys_init_arsc()
+{
+       return ros_syscall(SYS_init_arsc, 0, 0, 0, 0, 0);
+}