Massive renaming/cleanup of harts->vcores
authorKevin Klues <klueska@ros-dev.(none)>
Thu, 15 Apr 2010 06:18:43 +0000 (23:18 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:42 +0000 (17:35 -0700)
We also changed a few of the semantics between the way that vcores
interact with the kernel and expose an API to an end user/thread library.

Also fixed up some bugs in the way tests were pulling in stdio.h

Oh, and don't forget to rebuild your cross compiler
(and busybox / any user apps that you plan to run)

49 files changed:
Documentation/processes.txt
kern/arch/i686/ros/hart.h [deleted file]
kern/arch/sparc/ros/hart.h [deleted file]
kern/include/ros/procinfo.h
kern/include/stdio.h
kern/src/process.c
tests/divzero.c
tests/draw_nanwan.c
tests/faultread.c
tests/faultreadkernel.c
tests/fp_test.c
tests/hart_test.c
tests/hello.c
tests/manycore_test.c
tests/mhello.c
tests/mproctests.c
tests/proctests.c
tests/pthread_test.c
tests/spawn.c
tests/syscall_speed.c
tests/testbss.c
tests/tlstest.c
tools/compilers/gcc-glibc/Makefile
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/i386/tls.h
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/lowlevellock.h
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/start.c
user/include/debug.h [deleted file]
user/include/hart.h [deleted file]
user/include/i686/arch.h
user/include/i686/hart.h [deleted file]
user/include/i686/vcore.h [new file with mode: 0644]
user/include/mcs.h [new file with mode: 0644]
user/include/parlib.h
user/include/pthread.h
user/include/rstdio.h [new file with mode: 0644]
user/include/sparc/arch.h
user/include/sparc/atomic.h
user/include/sparc/hart.h [deleted file]
user/include/sparc/vcore.h [new file with mode: 0644]
user/include/stdio.h [deleted file]
user/include/vcore.h [new file with mode: 0644]
user/parlib/Makefrag
user/parlib/debug.c
user/parlib/debugfmt.c
user/parlib/hart.c [deleted file]
user/parlib/mcs.c [new file with mode: 0644]
user/parlib/pthread.c
user/parlib/vcore.c [new file with mode: 0644]
user/pthread/Makefrag

index 8f3bc22..621a22c 100644 (file)
@@ -170,7 +170,7 @@ TLS/TCB descriptor and the floating point/silly state (if applicable) in the
 user-thread control block, and do whatever is needed to signal vcore0 to run the
 _S context when it starts up.  One way would be to mark vcore0's "active thread"
 variable to point to the _S thread.  When vcore0 starts up at
-_start/hart_entry() (like all vcores), it will see a thread was running there
+_start/vcore_entry() (like all vcores), it will see a thread was running there
 and restart it.  This will need to have some special casing for the FP/silly
 state.
 
@@ -233,7 +233,7 @@ to _S.  The kernel will rip it out of your vcore list.  A process can yield its
 cores in any order.  The kernel will "fill in the holes of the vcoremap" for any
 future new cores requested (e.g., proc A has 4 vcores, yields vcore2, and then
 asks for another vcore.  The new one will be vcore2).  When any core starts in
-_M mode, even after a yield, it will come back at the hart_entry()/_start point.
+_M mode, even after a yield, it will come back at the vcore_entry()/_start point.
 
 Yield will normally adjust your desired amount of vcores to the amount after the
 calling core is taken.  This is the way a process gives its cores back.
diff --git a/kern/arch/i686/ros/hart.h b/kern/arch/i686/ros/hart.h
deleted file mode 100644 (file)
index 9eebfa7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _ROS_ARCH_HART_H
-#define _ROS_ARCH_HART_H
-
-#ifndef ROS_KERNEL
-
-#include <ros/syscall.h>
-
-#define HART_CL_SIZE 64
-
-// this is how we get our thread id on entry.
-#define __hart_self_on_entry \
-({ \
-       register int temp asm ("eax"); \
-       temp; \
-})
-
-// The actual hart_self() function is a global symbol that invokes this routine.
-static inline int
-__hart_self()
-{
-       // TODO: use some kind of thread-local storage to speed this up!
-       return (int)ros_syscall(SYS_getvcoreid,0,0,0,0,0);
-}
-
-static inline void
-__hart_set_stack_pointer(void* sp)
-{
-       asm volatile ("mov %0,%%esp" : : "r"(sp) : "memory","esp");
-}
-
-static inline void
-__hart_relax()
-{
-       asm volatile ("pause" : : : "memory");
-}
-
-static inline int
-__hart_swap(int* addr, int val)
-{
-       asm volatile ("xchg %0, (%2)" : "=r"(val) : "0"(val),"r"(addr) : "memory");
-       return val;
-}
-
-#endif
-
-#endif
diff --git a/kern/arch/sparc/ros/hart.h b/kern/arch/sparc/ros/hart.h
deleted file mode 100644 (file)
index 258aa0d..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _ROS_ARCH_HART_H
-#define _ROS_ARCH_HART_H
-
-#define __RAMP__
-double do_fdiv(double,double);
-double do_fsqrt(double);
-double do_recip(double);
-double do_rsqrt(double);
-
-#define HART_CL_SIZE 128
-#define HART_ATOMIC_HASHTABLE_SIZE 17
-
-#define __hart_self_on_entry (__hart_self())
-
-static inline int
-__hart_self()
-{
-       int id;
-       asm ("mov %%asr13,%0" : "=r"(id));
-       return id;
-}
-
-static inline void
-__hart_set_stack_pointer(void* sp)
-{
-       __asm__ __volatile__ ("mov %0,%%sp" : : "r"(sp));
-}
-
-static inline void
-__hart_relax()
-{
-       // TODO: relax
-}
-
-static inline int
-__hart_swap(int* addr, int val)
-{
-       __asm__ __volatile__ ("swap [%2],%0" :"=r"(val) :"0"(val),"r"(addr) :"memory");
-       return val;
-}
-
-extern int __hart_atomic_hash_locks[HART_CL_SIZE*HART_ATOMIC_HASHTABLE_SIZE];
-static inline int*
-__hart_atomic_hash_lock(int* addr)
-{
-       int hash = ((unsigned int)addr/sizeof(int*))/HART_ATOMIC_HASHTABLE_SIZE;
-       return &__hart_atomic_hash_locks[HART_CL_SIZE/sizeof(int)*hash];
-}
-
-static inline int
-__hart_fetch_and_add(int* addr, int addend)
-{
-       int * lock = __hart_atomic_hash_lock(addr);
-       while(__hart_swap(lock,1));
-
-       int old = *addr;
-       *addr = old+addend;
-
-       *lock = 0;
-       return old;
-}
-
-static inline int
-__hart_compare_and_swap(int* addr, int testval, int newval)
-{
-       int * lock = __hart_atomic_hash_lock(addr);
-       while(__hart_swap(lock,1));
-
-       int old = *addr;
-       if(old == testval)
-               *addr = newval;
-
-       *lock = 0;
-       return old;
-}
-
-#endif
index 20b7b55..91a0dcb 100644 (file)
@@ -29,7 +29,7 @@ struct pcore {
 typedef struct procinfo {
        pid_t pid;
        pid_t ppid;
-       size_t max_harts;
+       size_t max_vcores;
        uint64_t tsc_freq;
        void* heap_bottom;
        char* argp[PROCINFO_MAX_ARGP];
index 81a9b09..257bda7 100644 (file)
@@ -8,6 +8,7 @@
 #define NULL   ((void *) 0)
 #endif /* !NULL */
 
+//#define DEBUG
 #ifdef DEBUG
 #define printd(args...) cprintf(args)
 #else
index 906e720..2675607 100644 (file)
@@ -218,7 +218,7 @@ proc_init_procinfo(struct proc* p)
        p->procinfo->ppid = p->ppid;
        p->procinfo->tsc_freq = system_timing.tsc_freq;
        // TODO: maybe do something smarter here
-       p->procinfo->max_harts = MAX(1,num_cpus-1);
+       p->procinfo->max_vcores = MAX(1,num_cpus-1);
 }
 
 /* Allocates and initializes a process, with the given parent.  Currently
@@ -1283,3 +1283,52 @@ void print_proc_info(pid_t pid)
        spin_unlock_irqsave(&p->proc_lock);
        proc_decref(p, 1); /* decref for the pid2proc reference */
 }
+
+void proc_preempt_core(struct proc *p, uint32_t vcoreid)
+{
+    uint32_t pcoreid;
+    bool self_ipi_pending = FALSE;
+    spin_lock_irqsave(&p->proc_lock);
+    p->procinfo->vcoremap[vcoreid].preempt_served = TRUE;
+    pcoreid = p->procinfo->vcoremap[vcoreid].pcoreid;
+    // expects a pcorelist.  assumes pcore is mapped and running_m
+    self_ipi_pending = __proc_take_cores(p, &pcoreid, 1, __preempt, p, 0, 0);
+    __proc_unlock_ipi_pending(p, self_ipi_pending);
+}
+
+void proc_give(struct proc *p, uint32_t pcoreid)
+{
+    bool self_ipi_pending = FALSE;
+    spin_lock_irqsave(&p->proc_lock);
+    // expects a vcorelist.  assumes vcore is mapped and running_m
+    self_ipi_pending = __proc_give_cores(p, &pcoreid, 1);
+    __proc_unlock_ipi_pending(p, self_ipi_pending);
+}
+
+void do_it(void)
+{
+    struct proc *p = 0xfe500000;
+    proc_preempt_core(p, 0);
+    //print_proc_info(1);
+    udelay(2000000);
+    p->procdata->vcore_preempt_data[0].notif_pending = 1;
+    proc_give(p, 4);
+    //print_proc_info(1);
+}
+
+void do_it2(void)
+{
+    struct proc *p = 0xfe500000;
+    bool self_ipi_pending = FALSE;
+    uint32_t pcorelist[4] = {7, 6, 5, 4};
+
+    spin_lock_irqsave(&p->proc_lock);
+    self_ipi_pending = __proc_take_allcores(p, __preempt, p, 0, 0);
+    __proc_unlock_ipi_pending(p, self_ipi_pending);
+    udelay(2000000);
+
+    print_proc_info(1);
+    udelay(5000000);
+
+}
+
index 59dbf18..3c9fe99 100644 (file)
@@ -1,6 +1,6 @@
 // buggy program - causes a divide by zero exception
 
-#include <stdio.h>
+#include <rstdio.h>
 
 int zero;
 
index 16f6663..4f2bcca 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv)
 {
index 3cf8a3f..5ad2c27 100644 (file)
@@ -1,6 +1,6 @@
 // buggy program - faults with a read from location zero
 
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv)
 { 
index cef359f..5188378 100644 (file)
@@ -1,6 +1,6 @@
 // buggy program - faults with a read from kernel space
 
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv)
 {
index eaf8fb2..fd03d4f 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv) 
 {
index 51fb0d4..04b4bfc 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv) 
 {
index db008b1..c012457 100644 (file)
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include <stdio.h>
+#include <rstdio.h>
 
 int main(int argc, char** argv)
 {
index 04de64c..b286e41 100644 (file)
@@ -1,29 +1,30 @@
-#include <stdio.h>
+#include <rstdio.h>
 #include <assert.h>
-#include <hart.h>
+#include <vcore.h>
 #include <parlib.h>
+#include <mcs.h>
 
-hart_barrier_t b;
+mcs_barrier_t b;
 
 void do_work_son(int vcoreid)
 {
        int cpuid = sys_getcpuid();
        int pid = sys_getpid();
        printf("Hello! My Process ID: %d My VCoreID: %d My CPU: %d\n", pid, vcoreid, cpuid);
-       hart_barrier_wait(&b,vcoreid);
+       mcs_barrier_wait(&b,vcoreid);
 }
 
-void hart_entry()
+void vcore_entry()
 {
-       assert(hart_self() > 0);
-       do_work_son(hart_self());
+       assert(vcore_id() > 0);
+       do_work_son(vcore_id());
 }
 
 int main(int argc, char** argv)
 {
-       assert(hart_self() == 0);
-       hart_barrier_init(&b,hart_max_harts());
-       hart_request(hart_max_harts()-1);
+       assert(vcore_id() == 0);
+       mcs_barrier_init(&b,max_vcores());
+       vcore_request(max_vcores()-1);
        do_work_son(0);
        return 0;
 }
index 7e0e494..a2507f6 100644 (file)
@@ -5,12 +5,13 @@
 #include <ros/notification.h>
 #include <ros/bcq.h>
 #include <arch/arch.h>
-#include <stdio.h>
-#include <hart.h>
+#include <rstdio.h>
+#include <vcore.h>
+#include <mcs.h>
 #include <timing.h>
 #include <rassert.h>
 
-hart_barrier_t b;
+mcs_barrier_t b;
 
 __thread int temp;
 void *core0_tls = 0;
@@ -20,11 +21,11 @@ int main(int argc, char** argv)
        uint32_t vcoreid;
        int retval;
 
-       hart_barrier_init(&b,hart_max_harts()-1);
+       mcs_barrier_init(&b, max_vcores() - 1);
 
 /* begin: stuff userspace needs to do before switching to multi-mode */
-       if (hart_init())
-               printf("Harts failed, we're fucked!\n");
+       if (vcore_init())
+               printf("vcore_init() failed, we're fucked!\n");
 
        /* tell the kernel where and how we want to receive notifications */
        struct notif_method *nm;
@@ -47,7 +48,7 @@ int main(int argc, char** argv)
        
 /* end: stuff userspace needs to do before switching to multi-mode */
 
-       if ((vcoreid = hart_self())) {
+       if ((vcoreid = vcore_id())) {
                printf("Should never see me! (from vcore %d)\n", vcoreid);
        } else { // core 0
                temp = 0xdeadbeef;
@@ -55,10 +56,9 @@ int main(int argc, char** argv)
                       vcoreid, &temp, temp);
                printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid());
                //retval = sys_resource_req(RES_CORES, 2, 0);
-               //retval = hart_request(hart_max_harts()-2);
-               retval = hart_request(2); // doesn't do what you think.  this gives 3.
-               //printf("retval = %d\n", retval);
-               printf("This is vcore0, right after hart_request\n");
+               //retval = vcore_request(vcore_max_vcores()-2);
+               retval = vcore_request(3);
+               printf("This is vcore0, right after vcore_request, retval=%d\n", retval);
        }
 
 #if 0
@@ -85,16 +85,16 @@ int main(int argc, char** argv)
        }
 
        printf("Vcore %d Done!\n", vcoreid);
-       hart_barrier_wait(&b,hart_self());
+       mcs_barrier_wait(&b,vcore_id());
 
        printf("All Cores Done!\n", vcoreid);
        while(1); // manually kill from the monitor
        return 0;
 }
 
-void hart_entry(void)
+void vcore_entry(void)
 {
-       uint32_t vcoreid = hart_self();
+       uint32_t vcoreid = vcore_id();
        static bool first_time = TRUE;
 
        temp = 0xcafebabe;
@@ -146,8 +146,8 @@ void hart_entry(void)
        
 /* end: stuff userspace needs to do to handle notifications */
 
-       printf("Hello from hart_entry in vcore %d with temp addr %p and temp %p\n",
+       printf("Hello from vcore_entry in vcore %d with temp addr %p and temp %p\n",
               vcoreid, &temp, temp);
-       hart_barrier_wait(&b,hart_self());
+       mcs_barrier_wait(&b,vcore_id());
        while(1);
 }
index b3e2ae3..211151d 100644 (file)
@@ -2,10 +2,10 @@
 #include <parlib.h>
 #include <rassert.h>
 #include <stdlib.h>
-#include <hart.h>
+#include <vcore.h>
 #include <ros/mman.h>
 #include <ros/resource.h>
-#include <stdio.h>
+#include <rstdio.h>
 #include <timing.h>
 
 #define TEST_MMAP                                       1
@@ -27,9 +27,9 @@ int main(int argc, char** argv)
 {
        uint32_t vcoreid;
        int retval;
-       hart_init();
+       vcore_init();
 
-       if ((vcoreid = hart_self())) {
+       if ((vcoreid = vcore_id())) {
                printf("Should never see me! (from vcore %d)\n", vcoreid);
        } else { // core 0
                printf("Hello from else vcore 0\n");
@@ -54,19 +54,19 @@ int main(int argc, char** argv)
                                printf("Should not see me!!!!!!!!!!!!!!!!!!\n");
                                while(1);
                        case TEST_ONE_CORE:
-                               retval = hart_request(1);
+                               retval = vcore_request(1);
                                printf("One core test's core0's retval: %d\n", retval);
                                printf("Check to see it's on a worker core.\n");
                                while(1);
                        case TEST_ASK_FOR_TOO_MANY_CORES:
-                               retval = hart_request(12);
+                               retval = vcore_request(12);
                                printf("Asked for too many, retval: %d\n", retval);
                                return 0;
                        case TEST_INCREMENTAL_CHANGES:
-                               retval = hart_request(4);
+                               retval = vcore_request(4);
                                break;
                        default:
-                               retval = hart_request(5);
+                               retval = vcore_request(5);
                }
                if (retval)
                        panic("failed to allocate cores!");
@@ -79,7 +79,7 @@ int main(int argc, char** argv)
                case TEST_YIELD_OUT_OF_ORDER:
                        udelay(10000000);
                        printf("Core 2 should have yielded, asking for another\n");
-                       retval = hart_request(5);
+                       retval = vcore_request(5);
                        break;
                case TEST_YIELD_0_OUT_OF_ORDER:
                        udelay(5000000);
@@ -94,14 +94,14 @@ int main(int argc, char** argv)
        return 0;
 }
 
-void hart_entry(void)
+void vcore_entry(void)
 {
        uint32_t vcoreid;
        static int first_time = 1; // used by vcore2
        int retval;
 
-       vcoreid = hart_self();
-       printf("Hello from hart_entry in vcore %d\n", vcoreid);
+       vcoreid = vcore_id();
+       printf("Hello from vcore_entry in vcore %d\n", vcoreid);
 
        if ((vcoreid == 2) && first_time) {
                first_time = 0;
@@ -110,12 +110,12 @@ void hart_entry(void)
                                // Testing asking for less than we already have
                                udelay(1000000);
                                printf("Asking for too few:\n");
-                               retval = hart_request(2);
+                               retval = vcore_request(2);
                                printf("Should be -EINVAL(7): %d\n", retval);
                                // Testing getting more while running
                                printf("Asking for more while running:\n");
                                udelay(1000000);
-                               retval = hart_request(5);
+                               retval = vcore_request(5);
                                printf("core2's retval: %d\n", retval);
                                break;
                        case TEST_YIELD_OUT_OF_ORDER:
@@ -125,7 +125,7 @@ void hart_entry(void)
                        case TEST_YIELD_0_OUT_OF_ORDER:
                                udelay(7500000);
                                printf("Core 0 should have yielded, asking for another\n");
-                               retval = hart_request(5);
+                               retval = vcore_request(5);
                }
        }
        global_tests(vcoreid);
@@ -145,7 +145,7 @@ static void global_tests(uint32_t vcoreid)
                        if (vcoreid == 2) {
                                printf("Core %d trying to request 0/ switch to _S\n", vcoreid);
                                udelay(3000000);
-                               retval = hart_request(0);
+                               retval = vcore_request(0);
                                // will only see this if we are scheduled()
                                printf("Core %d back up! (retval:%d)\n", vcoreid, retval);
                                printf("And exiting\n");
@@ -154,7 +154,7 @@ static void global_tests(uint32_t vcoreid)
                        while(1);
                case TEST_CRAZY_YIELDS:
                        udelay(300000*vcoreid);
-                       hart_request(5);
+                       vcore_request(5);
                        sys_yield(0);
                        printf("should  never see me, unless you slip into *_S\n");
                        break;
index f7ad8d2..1507df7 100644 (file)
@@ -1,5 +1,5 @@
 #include <parlib.h>
-#include <stdio.h>
+#include <rstdio.h>
 
 /* This runs a variety of process tests.  For now, it just tests single-core
  * yielding among a bunch of processes (which it creates).  It needs the
index 7abbdc4..2229f12 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 #include <pthread.h>
 
 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
index ad1bb35..933e0a2 100644 (file)
@@ -1,5 +1,5 @@
 
-#include <stdio.h>
+#include <rstdio.h>
 #include <parlib.h>
 
 int main(int argc, char** argv)
index 7895732..5c55299 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 #include <parlib.h>
 #include <arch/arch.h>
 
index 1dba334..c650315 100644 (file)
@@ -1,7 +1,7 @@
 // test reads and writes to a large bss
 
 #include <stdint.h>
-#include <stdio.h>
+#include <rstdio.h>
 #include <rassert.h>
 
 #define ARRAYSIZE (1024*1024)
index 9e47bd2..f47a5ba 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <rstdio.h>
 
 volatile __thread int foo;
 volatile __thread int bar;
index 07cc415..bf3542a 100644 (file)
@@ -221,7 +221,7 @@ $(BINARY_PREFIX)gcc-stage2-builddir: gcc-$(GCC_VERSION)
        cp bits/stdio_lim.h $(INSTDIR)/$(ARCH)-ros/include/bits/
 
 .$(BINARY_PREFIX)ros-headers-install: $(ROSDIR)
-       rm -rf $(INSTDIR)/$(ARCH)-ros/sys-include/ros/*
+       rm -rf $(INSTDIR)/$(ARCH)-ros/sys-include/*
        mkdir -p $(INSTDIR)/$(ARCH)-ros/sys-include
        cp -r $(ROSDIR)/kern/include/ros \
           $(INSTDIR)/$(ARCH)-ros/sys-include/
@@ -229,6 +229,10 @@ $(BINARY_PREFIX)gcc-stage2-builddir: gcc-$(GCC_VERSION)
        mkdir $(INSTDIR)/$(ARCH)-ros/sys-include/ros/arch
        cp -r $(ROSDIR)/kern/arch/$(ROS_ARCH_DIR)/ros/* \
           $(INSTDIR)/$(ARCH)-ros/sys-include/ros/arch/
+       cp -r $(ROSDIR)/user/include/* \
+          $(INSTDIR)/$(ARCH)-ros/sys-include/
+       rm -rf $(INSTDIR)/$(ARCH)-ros/sys-include/arch
+       ln -s $(ARCH) $(INSTDIR)/$(ARCH)-ros/sys-include/arch 
 
 .$(BINARY_PREFIX)gcc-stage1-configure: 
        $(MAKE) $(BINARY_PREFIX)gcc-stage1-builddir
index 6035504..3bddff7 100644 (file)
@@ -439,13 +439,18 @@ static const char* tls_init_tp(void* thrdescr)
   head->tcb = thrdescr;
   head->self = thrdescr;
 
+  //TODO: think about how to avoid this. Probably add a field to the 
+  // rthreads struct that we manually fill in in _start(). 
   int core_id = __syscall_sysenter(SYS_getvcoreid,0,0,0,0,0,NULL);
 
   /* Bug with this whole idea (TODO: (TLSV))*/
   if(__procdata.ldt == NULL)
   {
-    size_t sz= (sizeof(segdesc_t)*__procinfo.max_harts+PGSIZE-1)/PGSIZE*PGSIZE;
+    size_t sz= (sizeof(segdesc_t)*__procinfo.max_vcores+PGSIZE-1)/PGSIZE*PGSIZE;
     
+    // Can't directly call mmap because it tries to set errno, and errno doesn't
+    // exist yet (it relies on tls, and we are currently in the process of setting 
+    // it up...)
     intreg_t params[3] = { MAP_ANONYMOUS | MAP_POPULATE, -1, 0 };
     void* ldt = (void*) __syscall_sysenter(SYS_mmap, 0,
                                            sz, PROT_READ | PROT_WRITE, 
@@ -461,7 +466,7 @@ static const char* tls_init_tp(void* thrdescr)
   // Build the segment
   segdesc_t tmp = SEG(STA_W, (uint32_t)thrdescr, 0xffffffff, 3);
 
-  // Setup the correct LDT entry for this hart
+  // Setup the correct LDT entry for this vcore
   __procdata.ldt[core_id] = tmp;
 
   // Create the GS register.
index 61b0aba..7fc21c5 100644 (file)
@@ -2,7 +2,7 @@
 #define _LOWLEVELLOCK_H
 
 #include <atomic.h>
-#include <ros/arch/hart.h>
+#include <arch/atomic.h>
 
 #define LLL_PRIVATE 0
 #define LLL_SHARED 1
@@ -11,7 +11,7 @@
 
 #define lll_lock(l,p) do { } while(lll_trylock(l))
 #define lll_unlock(l,p) ({ (l) = 0; 0; })
-#define lll_trylock(l) __hart_swap(&(l),1)
+#define lll_trylock(l) atomic_swap(&(l),1)
 
 #define lll_futex_wait(m,v,p) do { assert("NO FUTEX_WAIT FOR YOU!" == 0); } while(0)
 #define lll_futex_wake(m,n,p) do { assert("NO FUTEX_WAKE FOR YOU!" == 0); } while(0)
index a968e5f..1b06222 100644 (file)
@@ -1,40 +1,34 @@
 #include <abort-instr.h>
 #include <string.h>
-#include <ros/arch/hart.h>
+#include <vcore.h>
 #include <stdio.h>
 #include <ros/syscall.h>
 #include <ros/procinfo.h>
 #include <unistd.h>
 #include <tls.h>
 
-void** __hart_thread_control_blocks = NULL;
-weak_alias(__hart_thread_control_blocks,hart_thread_control_blocks)
+void** __vcore_thread_control_blocks = NULL;
+weak_alias(__vcore_thread_control_blocks,vcore_thread_control_blocks)
 
 void
-__hart_entry(void)
+__vcore_entry(void)
 {
-       fputs("define a hart_entry() function, foo!",stderr);
+       fputs("define a vcore_entry() function, foo!",stderr);
        abort();
 }
-weak_alias(__hart_entry,hart_entry)
-
-void
-__hart_yield(void)
-{
-}
-weak_alias(__hart_yield,hart_yield)
+weak_alias(__vcore_entry,vcore_entry)
 
 #define failmsg(str) write(2,str"\n",sizeof(str"\n")-1)
 
 void
 _start(void)
 {
-       // WARNING: __hart_self_on_entry must be read before
+       // WARNING: __vcore_self_on_entry must be read before
        // anything is register-allocated!
-       int id = __hart_self_on_entry;
+       int id = __vcore_id_on_entry;
        static int init = 0;
        // For dynamically-linked programs, the first time through,
-       // __hart_self_on_entry could be clobbered (on x86), because
+       // __vcore_self_on_entry could be clobbered (on x86), because
        // the linker will have overwritten eax.  Happily, the first
        // time through, we know we are vcore 0.  Subsequent entries
        // into this routine do not have this problem.
@@ -45,10 +39,9 @@ _start(void)
        // acquire a TCB.
        if(init || (id != 0))
        {
-               TLS_INIT_TP(__hart_thread_control_blocks[id],0);
-               hart_entry();
-               hart_yield();
-               failmsg("why did hart_yield() return?");
+               TLS_INIT_TP(__vcore_thread_control_blocks[id],0);
+               vcore_entry();
+               failmsg("why did vcore_entry() return?");
                goto diediedie;
        }
 
diff --git a/user/include/debug.h b/user/include/debug.h
deleted file mode 100644 (file)
index 632ff4c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef PARLIB_INC_DEBUG_H
-#define PARLIB_INC_DEBUG_H
-
-#include <ros/noivy.h>
-#include <stdio.h>
-
-#ifndef __va_list__
-typedef __builtin_va_list va_list;
-#endif
-
-#define va_start(v,l)   __builtin_va_start(v,l)
-#define va_end(v)      __builtin_va_end(v)
-#define va_arg(v,l)     __builtin_va_arg(v,l)
-
-size_t strnlen(const char *NTS s, size_t size);
-#ifdef __DEPUTY__
-void debugfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *NTS fmt, ...);
-void vdebugfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *NTS fmt, va_list);
-#else
-void debugfmt(void (*putch)(int, void**), void **putdat, const char *NTS fmt, ...);
-void vdebugfmt(void (*putch)(int, void**), void **putdat, const char *NTS fmt, va_list);
-#endif
-
-int    debug(const char * NTS fmt, ...);
-int    vdebug(const char * NTS fmt, va_list);
-
-#endif /* !PARLIB_INC_DEBUG_H */
diff --git a/user/include/hart.h b/user/include/hart.h
deleted file mode 100644 (file)
index ac7b5a5..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef _HART_H
-#define _HART_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <ros/arch/hart.h>
-#include <arch/hart.h>
-#include <string.h>
-
-#define HART_LOG2_MAX_MAX_HARTS 6
-#define HART_MAX_MAX_HARTS (1 << HART_LOG2_MAX_MAX_HARTS)
-
-typedef struct hart_lock_qnode
-{
-       volatile struct hart_lock_qnode* volatile next;
-       volatile int locked;
-       char pad[HART_CL_SIZE-sizeof(void*)-sizeof(int)];
-} hart_lock_qnode_t;
-
-typedef struct
-{
-       hart_lock_qnode_t* lock;
-       char pad[HART_CL_SIZE-sizeof(hart_lock_qnode_t*)];
-       hart_lock_qnode_t qnode[HART_MAX_MAX_HARTS] __attribute__((aligned(8)));
-} hart_lock_t;
-
-#define HART_LOCK_INIT {0}
-
-typedef struct
-{
-       volatile int myflags[2][HART_LOG2_MAX_MAX_HARTS];
-       volatile int* partnerflags[2][HART_LOG2_MAX_MAX_HARTS];
-       int parity;
-       int sense;
-       char pad[HART_CL_SIZE];
-} hart_dissem_flags_t;
-
-typedef struct
-{
-       size_t nprocs;
-       hart_dissem_flags_t* allnodes;
-       size_t logp;
-} hart_barrier_t;
-
-extern void hart_entry();
-
-int hart_barrier_init(hart_barrier_t* b, size_t nprocs);
-void hart_barrier_wait(hart_barrier_t* b, size_t vcoreid);
-
-void hart_lock_init(hart_lock_t* lock);
-void hart_lock_unlock(hart_lock_t* lock);
-void hart_lock_lock(hart_lock_t* l);
-
-// "int" rather than size_t because of a newlib compiling issue
-int hart_self();
-void hart_relax();
-int hart_swap(int* addr, int val);
-
-int hart_init();
-int hart_request(size_t k);
-void hart_yield();
-size_t hart_max_harts();
-size_t hart_current_harts();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
index e2b5386..dba795e 100644 (file)
@@ -3,6 +3,14 @@
 
 #include <ros/common.h>
 
+#define ARCH_CL_SIZE 64
+
+static __inline void
+set_stack_pointer(void* sp)
+{
+       asm volatile ("mov %0,%%esp" : : "r"(sp) : "memory","esp");
+}
+
 static __inline void
 breakpoint(void)
 {
@@ -22,4 +30,5 @@ cpu_relax(void)
 {
        asm volatile("pause" : : : "memory");
 }
+
 #endif /* PARLIB_ARCH_H */
diff --git a/user/include/i686/hart.h b/user/include/i686/hart.h
deleted file mode 100644 (file)
index 0b3876b..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef PARLIB_ARCH_HART_H
-#define PARLIB_ARCH_HART_H
-
-#include <ros/common.h>
-#include <ros/arch/trapframe.h>
-#include <ros/procdata.h>
-#include <ros/arch/mmu.h>
-
-/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
- * A Userspace scheduler can call this when transitioning off the transition
- * stack.
- *
- * Make sure you clear the notif_pending flag, and then check the queue before
- * calling this.  If notif_pending is not clear, this will self_notify this
- * core, since it should be because we missed a notification message while
- * notifs were disabled. 
- *
- * Basically, it sets up the future stack pointer to have extra stuff after it,
- * and then it pops the registers, then pops the new context's stack
- * pointer.  Then it uses the extra stuff (the new PC is on the stack, the
- * location of notif_enabled, and a clobbered work register) to enable notifs,
- * make sure notif IPIs weren't pending, restore the work reg, and then "ret".
- *
- * This is what the target notif_tf's stack will look like (growing down):
- *
- * Target ESP -> |   u_thread's old stuff   |
- *               |   new eip                |
- *               |   eax save space         |
- *               |   vcoreid                |
- *               |   notif_pending_loc      |
- *               |   notif_enabled_loc      |
- *
- * The important thing is that it can handle a notification after it enables
- * notifications, and when it gets resumed it can ultimately run the new
- * context.  Enough state is saved in the running context and stack to continue
- * running. */
-static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
-{
-       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
-       if (!tf->tf_cs) { /* sysenter TF.  esp and eip are in other regs. */
-               tf->tf_esp = tf->tf_regs.reg_ebp;
-               tf->tf_eip = tf->tf_regs.reg_edx;
-       }
-       asm volatile ("movl %2,-0x04(%1);    " /* push the PC */
-                     "movl %3,-0x0c(%1);    " /* room for eax, push vcoreid */
-                     "movl %4,-0x10(%1);    " /* push notif_pending loc */
-                     "movl %5,-0x14(%1);    " /* push notif_enabled loc */
-                     "movl %0,%%esp;        " /* pop the real tf */
-                     "popal;                " /* restore normal registers */
-                     "addl $0x20,%%esp;     " /* move to the eflags in the tf */
-                     "popfl;                " /* restore eflags */
-                     "popl %%esp;           " /* change to the new %esp */
-                     "subl $0x4,%%esp;      " /* move esp to the slot for eax */
-                     "pushl %%eax;          " /* save eax, will clobber soon */
-                     "subl $0xc,%%esp;      " /* move to notif_en_loc slot */
-                     "popl %%eax;           " /* load notif_enabaled addr */
-                     "movb $0x01,(%%eax);   " /* enable notifications */
-                     "popl %%eax;           " /* get notif_pending status */
-                     "pushfl;               " /* save eflags */
-                     "testb $0x01,(%%eax);  " /* test if a notif is pending */
-                     "jz 1f;                " /* if not pending, skip syscall */
-                     "popfl;                " /* restore eflags */
-                     "movb $0x00,(%%eax);   " /* clear pending */
-                     "pushl %%edx;          " /* save edx, syscall arg1 */
-                     "pushl %%ecx;          " /* save ecx, syscall arg2 */
-                     "pushl %%ebx;          " /* save ebx, syscall arg3 */
-                     "pushl %%esi;          " /* will be clobbered for errno */
-                     "popl %%edx;           " /* vcoreid, arg1 */
-                     "movl $0x0,%%ecx;      " /* send the null notif, arg2 */
-                     "movl $0x0,%%ecx;      " /* no u_ne message, arg3 */
-                     "movl %6,%%eax;        " /* syscall num */
-                     "int %7;               " /* fire the syscall */
-                     "popl %%esi;           " /* restore regs after syscall */
-                     "popl %%ebx;           "
-                     "popl %%ecx;           "
-                     "popl %%edx;           "
-                     "jmp 2f;               " /* skip 1:, already popped */
-                     "1: popfl;             " /* restore eflags */
-                     "popl %%eax;           " /* discard vcoreid */
-                     "2: popl %%eax;        " /* restore tf's %eax */
-                     "ret;                  " /* return to the new PC */
-                     :
-                     : "g"(tf), "r"(tf->tf_esp), "r"(tf->tf_eip), "r"(vcoreid),
-                       "r"(&vcpd->notif_pending), "r"(&vcpd->notif_enabled),
-                       "i"(SYS_self_notify), "i"(T_SYSCALL)
-                     : "memory");
-}
-
-/* Reading from the LDT.  Could also use %gs, but that would require including
- * half of libc's TLS header.  Sparc will probably ignore the vcoreid, so don't
- * rely on it too much.  The intent of it is vcoreid is the caller's vcoreid,
- * and that vcoreid might be in the TLS of the caller (it will be for transition
- * stacks) and we could avoid a trap on x86 to sys_getvcoreid(). */
-static inline void *get_tls_desc(uint32_t vcoreid)
-{
-       return (void*)(__procdata.ldt[vcoreid].sd_base_31_24 << 24 |
-                      __procdata.ldt[vcoreid].sd_base_23_16 << 16 |
-                      __procdata.ldt[vcoreid].sd_base_15_0);
-}
-
-/* passing in the vcoreid, since it'll be in TLS of the caller */
-static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
-{
-  /* Keep this technique in sync with sysdeps/ros/i386/tls.h */
-  segdesc_t tmp = SEG(STA_W, (uint32_t)tls_desc, 0xffffffff, 3);
-  __procdata.ldt[vcoreid] = tmp;
-
-  /* GS is still the same (should be!), but it needs to be reloaded to force a
-   * re-read of the LDT. */
-  uint32_t gs = (vcoreid << 3) | 0x07;
-  asm volatile("movl %0,%%gs" : : "r" (gs));
-}
-
-#endif /* PARLIB_ARCH_HART_H */
diff --git a/user/include/i686/vcore.h b/user/include/i686/vcore.h
new file mode 100644 (file)
index 0000000..5aadd88
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef PARLIB_ARCH_VCORE_H
+#define PARLIB_ARCH_VCORE_H
+
+#include <ros/common.h>
+#include <ros/arch/trapframe.h>
+#include <ros/procdata.h>
+#include <ros/syscall.h>
+#include <ros/arch/mmu.h>
+
+/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
+ * A Userspace scheduler can call this when transitioning off the transition
+ * stack.
+ *
+ * Make sure you clear the notif_pending flag, and then check the queue before
+ * calling this.  If notif_pending is not clear, this will self_notify this
+ * core, since it should be because we missed a notification message while
+ * notifs were disabled. 
+ *
+ * Basically, it sets up the future stack pointer to have extra stuff after it,
+ * and then it pops the registers, then pops the new context's stack
+ * pointer.  Then it uses the extra stuff (the new PC is on the stack, the
+ * location of notif_enabled, and a clobbered work register) to enable notifs,
+ * make sure notif IPIs weren't pending, restore the work reg, and then "ret".
+ *
+ * This is what the target notif_tf's stack will look like (growing down):
+ *
+ * Target ESP -> |   u_thread's old stuff   |
+ *               |   new eip                |
+ *               |   eax save space         |
+ *               |   vcoreid                |
+ *               |   notif_pending_loc      |
+ *               |   notif_enabled_loc      |
+ *
+ * The important thing is that it can handle a notification after it enables
+ * notifications, and when it gets resumed it can ultimately run the new
+ * context.  Enough state is saved in the running context and stack to continue
+ * running. */
+static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       if (!tf->tf_cs) { /* sysenter TF.  esp and eip are in other regs. */
+               tf->tf_esp = tf->tf_regs.reg_ebp;
+               tf->tf_eip = tf->tf_regs.reg_edx;
+       }
+       asm volatile ("movl %2,-0x04(%1);    " /* push the PC */
+                     "movl %3,-0x0c(%1);    " /* room for eax, push vcoreid */
+                     "movl %4,-0x10(%1);    " /* push notif_pending loc */
+                     "movl %5,-0x14(%1);    " /* push notif_enabled loc */
+                     "movl %0,%%esp;        " /* pop the real tf */
+                     "popal;                " /* restore normal registers */
+                     "addl $0x20,%%esp;     " /* move to the eflags in the tf */
+                     "popfl;                " /* restore eflags */
+                     "popl %%esp;           " /* change to the new %esp */
+                     "subl $0x4,%%esp;      " /* move esp to the slot for eax */
+                     "pushl %%eax;          " /* save eax, will clobber soon */
+                     "subl $0xc,%%esp;      " /* move to notif_en_loc slot */
+                     "popl %%eax;           " /* load notif_enabaled addr */
+                     "movb $0x01,(%%eax);   " /* enable notifications */
+                     "popl %%eax;           " /* get notif_pending status */
+                     "pushfl;               " /* save eflags */
+                     "testb $0x01,(%%eax);  " /* test if a notif is pending */
+                     "jz 1f;                " /* if not pending, skip syscall */
+                     "popfl;                " /* restore eflags */
+                     "movb $0x00,(%%eax);   " /* clear pending */
+                     "pushl %%edx;          " /* save edx, syscall arg1 */
+                     "pushl %%ecx;          " /* save ecx, syscall arg2 */
+                     "pushl %%ebx;          " /* save ebx, syscall arg3 */
+                     "pushl %%esi;          " /* will be clobbered for errno */
+                     "popl %%edx;           " /* vcoreid, arg1 */
+                     "movl $0x0,%%ecx;      " /* send the null notif, arg2 */
+                     "movl $0x0,%%ecx;      " /* no u_ne message, arg3 */
+                     "movl %6,%%eax;        " /* syscall num */
+                     "int %7;               " /* fire the syscall */
+                     "popl %%esi;           " /* restore regs after syscall */
+                     "popl %%ebx;           "
+                     "popl %%ecx;           "
+                     "popl %%edx;           "
+                     "jmp 2f;               " /* skip 1:, already popped */
+                     "1: popfl;             " /* restore eflags */
+                     "popl %%eax;           " /* discard vcoreid */
+                     "2: popl %%eax;        " /* restore tf's %eax */
+                     "ret;                  " /* return to the new PC */
+                     :
+                     : "g"(tf), "r"(tf->tf_esp), "r"(tf->tf_eip), "r"(vcoreid),
+                       "r"(&vcpd->notif_pending), "r"(&vcpd->notif_enabled),
+                       "i"(SYS_self_notify), "i"(T_SYSCALL)
+                     : "memory");
+}
+
+/* Reading from the LDT.  Could also use %gs, but that would require including
+ * half of libc's TLS header.  Sparc will probably ignore the vcoreid, so don't
+ * rely on it too much.  The intent of it is vcoreid is the caller's vcoreid,
+ * and that vcoreid might be in the TLS of the caller (it will be for transition
+ * stacks) and we could avoid a trap on x86 to sys_getvcoreid(). */
+static inline void *get_tls_desc(uint32_t vcoreid)
+{
+       return (void*)(__procdata.ldt[vcoreid].sd_base_31_24 << 24 |
+                      __procdata.ldt[vcoreid].sd_base_23_16 << 16 |
+                      __procdata.ldt[vcoreid].sd_base_15_0);
+}
+
+/* passing in the vcoreid, since it'll be in TLS of the caller */
+static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
+{
+  /* Keep this technique in sync with sysdeps/ros/i386/tls.h */
+  segdesc_t tmp = SEG(STA_W, (uint32_t)tls_desc, 0xffffffff, 3);
+  __procdata.ldt[vcoreid] = tmp;
+
+  /* GS is still the same (should be!), but it needs to be reloaded to force a
+   * re-read of the LDT. */
+  uint32_t gs = (vcoreid << 3) | 0x07;
+  asm volatile("movl %0,%%gs" : : "r" (gs));
+}
+
+// this is how we get our thread id on entry.
+#define __vcore_id_on_entry \
+({ \
+       register int temp asm ("eax"); \
+       temp; \
+})
+
+// The actual vcore_self() function is a global symbol that invokes this routine.
+static inline int
+__vcore_id()
+{
+       // TODO: use some kind of thread-local storage to speed this up!
+       return (int)ros_syscall(SYS_getvcoreid,0,0,0,0,0);
+}
+
+#endif /* PARLIB_ARCH_VCORE_H */
diff --git a/user/include/mcs.h b/user/include/mcs.h
new file mode 100644 (file)
index 0000000..0f9c378
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _MCS_H
+#define _MCS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <vcore.h>
+#include <arch/arch.h>
+
+#define MCS_LOCK_INIT {0}
+
+typedef struct mcs_lock_qnode
+{
+       volatile struct mcs_lock_qnode* volatile next;
+       volatile int locked;
+       char pad[ARCH_CL_SIZE-sizeof(void*)-sizeof(int)];
+} mcs_lock_qnode_t;
+
+typedef struct
+{
+       mcs_lock_qnode_t* lock;
+       char pad[ARCH_CL_SIZE-sizeof(mcs_lock_qnode_t*)];
+       mcs_lock_qnode_t qnode[MAX_VCORES] __attribute__((aligned(8)));
+} mcs_lock_t;
+
+typedef struct
+{
+       volatile int myflags[2][LOG2_MAX_VCORES];
+       volatile int* partnerflags[2][LOG2_MAX_VCORES];
+       int parity;
+       int sense;
+       char pad[ARCH_CL_SIZE];
+} mcs_dissem_flags_t;
+
+typedef struct
+{
+       size_t nprocs;
+       mcs_dissem_flags_t* allnodes;
+       size_t logp;
+} mcs_barrier_t;
+
+int mcs_barrier_init(mcs_barrier_t* b, size_t nprocs);
+void mcs_barrier_wait(mcs_barrier_t* b, size_t vcoreid);
+
+void mcs_lock_init(mcs_lock_t* lock);
+void mcs_lock_unlock(mcs_lock_t* lock);
+void mcs_lock_lock(mcs_lock_t* l);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index f1f50b4..00b45cb 100644 (file)
@@ -14,6 +14,7 @@
 #include <ros/syscall.h>
 #include <ros/procinfo.h>
 #include <ros/procdata.h>
+#include <ros/resource.h>
 #include <stdint.h>
 
 enum {
index 157d5f7..f9136e2 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef _PTHREAD_H
 #define _PTHREAD_H
 
-#include <hart.h>
+#include <vcore.h>
+#include <mcs.h>
 
 #ifdef __cplusplus
   extern "C" {
@@ -38,11 +39,11 @@ typedef struct
 
 typedef struct
 {
-  int local_sense[32*HART_MAX_MAX_HARTS];
+  int local_sense[32*MAX_VCORES];
   volatile int sense;
   int count;
   int nprocs;
-  hart_lock_t lock;
+  mcs_lock_t lock;
 } pthread_barrier_t;
 
 typedef struct
@@ -53,7 +54,7 @@ typedef struct
 typedef struct
 {
   const pthread_condattr_t* attr;
-  int waiters[HART_MAX_MAX_HARTS];
+  int waiters[MAX_VCORES];
 } pthread_cond_t;
 
 typedef struct pthread_wqt work_queue_t;
diff --git a/user/include/rstdio.h b/user/include/rstdio.h
new file mode 100644 (file)
index 0000000..404727a
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef PARLIB_INC_DEBUG_H
+#define PARLIB_INC_DEBUG_H
+
+#include <ros/common.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+void debugfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...);
+void vdebugfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list);
+
+int    debug(const char *fmt, ...);
+int    vdebug(const char *fmt, va_list);
+
+#ifndef __CONFIG_APPSERVER__
+#undef printf
+#define printf(...) debug(__VA_ARGS__)
+#endif /* __CONFIG_APPSERVER__ */
+
+#endif /* !PARLIB_INC_DEBUG_H */
index d97717e..dd5a98d 100644 (file)
@@ -3,6 +3,20 @@
 
 #include <ros/common.h>
 
+#define __RAMP__
+#define ARCH_CL_SIZE 128
+
+double do_fdiv(double,double);
+double do_fsqrt(double);
+double do_recip(double);
+double do_rsqrt(double);
+
+static __inline void
+set_stack_pointer(void* sp)
+{
+       __asm__ __volatile__ ("mov %0,%%sp" : : "r"(sp));
+}
+
 static __inline void
 breakpoint(void)
 {
index 4e01ec6..513ec2c 100644 (file)
@@ -16,14 +16,13 @@ typedef struct
 #define SPINLOCK_INITIALIZER {0}
 
 // atomic_t is void*, so we can't accidentally dereference it
-typedef void* atomic_t;
-
-static inline void atomic_init(atomic_t* number, int32_t val);
-static inline int32_t atomic_read(atomic_t* number);
-static inline void atomic_set(atomic_t* number, int32_t val);
-static inline void atomic_add(atomic_t* number, int32_t inc);
-static inline void atomic_inc(atomic_t* number);
-static inline void atomic_dec(atomic_t* number);
+//typedef void* atomic_t;
+//
+//static inline void atomic_init(atomic_t* number, int32_t val);
+//static inline int32_t atomic_read(atomic_t* number);
+//static inline void atomic_set(atomic_t* number, int32_t val);
+//static inline void atomic_inc(atomic_t* number);
+//static inline void atomic_dec(atomic_t* number);
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
                                     uint32_t new_val);
@@ -34,48 +33,35 @@ static inline void spin_unlock(spinlock_t*SAFE lock);
 
 /* Inlined functions declared above */
 
-static inline void atomic_init(atomic_t* number, int32_t val)
-{
-       val <<= 8;
-       __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
-}
-
-static inline int32_t atomic_read(atomic_t* number)
-{
-       int32_t val;
-       __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
-       return val >> 8;
-}
-
-static inline void atomic_add(atomic_t* number, int32_t inc)
-{
-       // this is pretty clever.  the lower 8 bits (i.e byte 3)
-       // of the atomic_t serve as a spinlock.  let's acquire it.
-       { TRUSTEDBLOCK spin_lock((spinlock_t*)number); }
-
-       // compute new counter value.
-       inc += atomic_read(number);
-
-       // set the new counter value.  the lock is cleared (for free)
-       atomic_init(number,inc);
-}
-
-static inline void atomic_set(atomic_t* number, int32_t val)
-{
-       // this works basically the same as atomic_add... but without the add
-       spin_lock((spinlock_t*)number);
-       atomic_init(number,val);
-}
-
-static inline void atomic_inc(atomic_t* number)
-{
-       atomic_add(number,1);
-}
-
-static inline void atomic_dec(atomic_t* number)
-{
-       atomic_add(number,-1);
-}
+//static inline void atomic_init(atomic_t* number, int32_t val)
+//{
+//     val <<= 8;
+//     __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
+//}
+//
+//static inline int32_t atomic_read(atomic_t* number)
+//{
+//     int32_t val;
+//     __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
+//     return val >> 8;
+//}
+//
+//static inline void atomic_set(atomic_t* number, int32_t val)
+//{
+//     // this works basically the same as atomic_add... but without the add
+//     spin_lock((spinlock_t*)number);
+//     atomic_init(number,val);
+//}
+//
+//static inline void atomic_inc(atomic_t* number)
+//{
+//     atomic_add(number,1);
+//}
+//
+//static inline void atomic_dec(atomic_t* number)
+//{
+//     atomic_add(number,-1);
+//}
 
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
 {
@@ -128,6 +114,7 @@ static inline void spin_unlock(spinlock_t*SAFE lock)
        __asm__ __volatile__ ("stub %%g0,[%0+3]" : : "r"(&lock->rlock) : "memory");
 }
 
+
 static inline void spinlock_init(spinlock_t* lock)
 {
        lock->rlock = 0;
diff --git a/user/include/sparc/hart.h b/user/include/sparc/hart.h
deleted file mode 100644 (file)
index d806ca4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef PARLIB_ARCH_HART_H
-#define PARLIB_ARCH_HART_H
-
-#include <ros/common.h>
-#include <ros/arch/trapframe.h>
-
-/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
- * A Userspace scheduler can call this when transitioning off the transition
- * stack.
- *
- * Make sure you clear the notif_pending flag, and then check the queue before
- * calling this.  If notif_pending is not clear, this will self_notify this
- * core, since it should be because we missed a notification message while
- * notifs were disabled. 
- *
- * The important thing is that it can a notification after it enables
- * notifications, and when it gets resumed it can ultimately run the new
- * context.  Enough state is saved in the running context and stack to continue
- * running. */
-static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
-{
-       // TODO: whatever sparc needs.
-}
-
-/* Feel free to ignore vcoreid.  It helps x86 to avoid a call to
- * sys_getvcoreid() if we pass it in. */
-static inline void *get_tls_desc(uint32_t vcoreid)
-{
-       void *tmp;
-       asm volatile ("mov %%g7,%0" : "=r"(tmp));
-       return tmp;
-}
-
-static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
-{
-       asm volatile ("mov %0,%%g7" : : "r"(tls_desc) : "memory");
-}
-#endif /* PARLIB_ARCH_HART_H */
diff --git a/user/include/sparc/vcore.h b/user/include/sparc/vcore.h
new file mode 100644 (file)
index 0000000..465a6a8
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef PARLIB_ARCH_VCORE_H
+#define PARLIB_ARCH_VCORE_H
+
+#include <ros/common.h>
+#include <ros/arch/trapframe.h>
+
+/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
+ * A Userspace scheduler can call this when transitioning off the transition
+ * stack.
+ *
+ * Make sure you clear the notif_pending flag, and then check the queue before
+ * calling this.  If notif_pending is not clear, this will self_notify this
+ * core, since it should be because we missed a notification message while
+ * notifs were disabled. 
+ *
+ * The important thing is that it can a notification after it enables
+ * notifications, and when it gets resumed it can ultimately run the new
+ * context.  Enough state is saved in the running context and stack to continue
+ * running. */
+static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
+{
+       // TODO: whatever sparc needs.
+}
+
+/* Feel free to ignore vcoreid.  It helps x86 to avoid a call to
+ * sys_getvcoreid() if we pass it in. */
+static inline void *get_tls_desc(uint32_t vcoreid)
+{
+       void *tmp;
+       asm volatile ("mov %%g7,%0" : "=r"(tmp));
+       return tmp;
+}
+
+static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
+{
+       asm volatile ("mov %0,%%g7" : : "r"(tls_desc) : "memory");
+}
+
+#define __vcore_id_on_entry (__vcore_id())
+
+static inline int
+__vcore_id()
+{
+       int id;
+       asm ("mov %%asr13,%0" : "=r"(id));
+       return id;
+}
+
+#endif /* PARLIB_ARCH_VCORE_H */
diff --git a/user/include/stdio.h b/user/include/stdio.h
deleted file mode 100644 (file)
index 08fc2f1..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __PARLIB_STDIO_H__
-#define __PARLIB_STDIO_H__
-
-#include_next <stdio.h>
-
-#ifndef __CONFIG_APPSERVER__
-#include <debug.h>
-#define printf(...) debug(__VA_ARGS__)
-#endif
-
-#endif
diff --git a/user/include/vcore.h b/user/include/vcore.h
new file mode 100644 (file)
index 0000000..1b5066f
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _VCORE_H
+#define _VCORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <arch/vcore.h>
+#include <string.h>
+
+#define LOG2_MAX_VCORES 6
+#define MAX_VCORES (1 << LOG2_MAX_VCORES)
+
+/* Defined by glibc; Must be implemented by a user level threading library */
+extern void vcore_entry();
+
+/* Vcore API functions */
+int vcore_init(void);
+int vcore_id(void);
+int vcore_request(size_t k);
+void vcore_yield(void);
+size_t max_vcores(void);
+size_t num_vcores(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index bc22ea3..145f33e 100644 (file)
@@ -11,7 +11,8 @@ ROS_USER_LIBS += $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a
 
 USER_PARLIB_SRCFILES := \
                  $(USER_PARLIB_DIR)/pthread.c \
-                 $(USER_PARLIB_DIR)/hart.c \
+                 $(USER_PARLIB_DIR)/vcore.c \
+                 $(USER_PARLIB_DIR)/mcs.c \
                  $(USER_PARLIB_DIR)/panic.c \
                  $(USER_PARLIB_DIR)/syscall.c \
                  $(USER_PARLIB_DIR)/debugfmt.c \
index e4c2977..57cb299 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <ros/common.h>
 #include <parlib.h>
-#include <debug.h>
+#include <rstdio.h>
 
 // Collect up to BUF_SIZE characters into a buffer
 // and perform ONE system call to print all of them,
index ce4e478..6f190fc 100644 (file)
@@ -1,6 +1,7 @@
 #include <ros/common.h>
 #include <ros/errno.h>
-#include <debug.h>
+#include <string.h>
+#include <rstdio.h>
 
 /*
  * Print a number (base <= 16) in reverse order,
diff --git a/user/parlib/hart.c b/user/parlib/hart.c
deleted file mode 100644 (file)
index ec9e074..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-#include <stdbool.h>
-#include <errno.h>
-#include <hart.h>
-#include <parlib.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <debug.h>
-
-// Only need in this file because _dl_allocate and friends are
-//  internal functions in glibc
-# ifdef __i386__
-#  define internal_function   __attribute ((regparm (3), stdcall))
-# else
-#  define internal_function
-# endif
-
-static size_t _current_harts = 1;
-static hart_lock_t _hart_lock = HART_LOCK_INIT;
-
-extern void** hart_thread_control_blocks;
-
-static void hart_free_tls(int id)
-{
-       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
-       if(hart_thread_control_blocks[id])
-       {
-               _dl_deallocate_tls(hart_thread_control_blocks[id],true);
-               hart_thread_control_blocks[id] = 0;
-       }
-}
-
-static int hart_allocate_tls(int id)
-{
-       #include <stdio.h>
-       extern void *_dl_allocate_tls (void *mem) internal_function;
-       // instead of freeing any old tls that may be present, and then
-       // reallocating it, we could instead just reinitialize it.
-       hart_free_tls(id);
-
-       void* tls = _dl_allocate_tls(NULL);
-       if((hart_thread_control_blocks[id] = tls) == NULL) {
-               errno = ENOMEM;
-               return -1;
-       }
-       return 0;
-}
-
-#define HART_STACK_PAGES 8
-#define HART_STACK_SIZE (HART_STACK_PAGES*PGSIZE)
-
-static void hart_free_stack(int id)
-{
-       // don't actually free stacks
-}
-
-static int hart_allocate_stack(int id)
-{
-       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[id];
-       if (vcpd->transition_stack)
-               return 0; // reuse old stack
-
-       void* stackbot = mmap(0, HART_STACK_SIZE,
-                             PROT_READ|PROT_WRITE|PROT_EXEC,
-                             MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
-
-       if(stackbot == MAP_FAILED)
-               return -1; // errno set by mmap
-
-       vcpd->transition_stack = (uintptr_t)stackbot + HART_STACK_SIZE;
-
-       return 0;
-}
-
-int hart_init()
-{
-       static int initialized = 0;
-       if(initialized)
-               return 0;
-
-       hart_thread_control_blocks = (void**)calloc(hart_max_harts(),sizeof(void*));
-
-       if(!hart_thread_control_blocks)
-               goto hart_tcb_fail;
-
-       if (hart_allocate_stack(0))
-               goto hart_stack_fail;
-       
-       if (hart_allocate_tls(0))
-               goto hart_tls_fail;
-
-       initialized = 1;
-       return 0;
-
-hart_tls_fail:
-       hart_free_stack(0);
-hart_stack_fail:
-       free(hart_thread_control_blocks);
-hart_tcb_fail:
-       errno = ENOMEM;
-       return -1;
-}
-
-int hart_request(size_t k)
-{
-       int ret = -1;
-       size_t i,j;
-
-       if(hart_init() < 0)
-               return -1;
-
-       hart_lock_lock(&_hart_lock);
-
-       if(k < 0 || _current_harts+k > hart_max_harts())
-       {
-               errno = EAGAIN;
-               goto out;
-       }
-
-       for(i = _current_harts, j = 0; i < _current_harts+k; i++, j++)
-       {
-               if(hart_allocate_stack(i) || hart_allocate_tls(i))
-                       goto fail;
-       }
-
-       if((ret = sys_resource_req(0,_current_harts+k,0,0)) == 0)
-       {
-               _current_harts += k;
-               goto out;
-       }
-
-fail:
-       for(i = _current_harts; i < _current_harts+k; i++)
-       {
-               hart_free_tls(i);
-               hart_free_stack(i);
-       }
-
-out:
-       hart_lock_unlock(&_hart_lock);
-       return ret;
-}
-
-void hart_yield()
-{
-       int id = hart_self();
-
-       hart_lock_lock(&_hart_lock);
-       _current_harts--;
-       if(_current_harts == 0)
-               exit(0);
-       hart_lock_unlock(&_hart_lock);
-
-       sys_yield();
-}
-
-size_t hart_max_harts()
-{
-       return __procinfo.max_harts < HART_MAX_MAX_HARTS ? __procinfo.max_harts : HART_MAX_MAX_HARTS;
-}
-
-size_t hart_current_harts()
-{
-       return _current_harts;
-}
-
-// MCS locks!!
-void hart_lock_init(hart_lock_t* lock)
-{
-       memset(lock,0,sizeof(hart_lock_t));
-}
-
-static inline hart_lock_qnode_t* hart_qnode_swap(hart_lock_qnode_t** addr, hart_lock_qnode_t* val)
-{
-       return (hart_lock_qnode_t*)hart_swap((int*)addr,(int)val);
-}
-
-void hart_lock_lock(hart_lock_t* lock)
-{
-       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
-       qnode->next = 0;
-       hart_lock_qnode_t* predecessor = hart_qnode_swap(&lock->lock,qnode);
-       if(predecessor)
-       {
-               qnode->locked = 1;
-               predecessor->next = qnode;
-               while(qnode->locked);
-       }
-}
-
-void hart_lock_unlock(hart_lock_t* lock)
-{
-       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
-       if(qnode->next == 0)
-       {
-               hart_lock_qnode_t* old_tail = hart_qnode_swap(&lock->lock,0);
-               if(old_tail == qnode)
-                       return;
-
-               hart_lock_qnode_t* usurper = hart_qnode_swap(&lock->lock,old_tail);
-               while(qnode->next == 0);
-               if(usurper)
-                       usurper->next = qnode->next;
-               else
-                       qnode->next->locked = 0;
-       }
-       else
-               qnode->next->locked = 0;
-}
-
-// MCS dissemination barrier!
-int hart_barrier_init(hart_barrier_t* b, size_t np)
-{
-       if(np > hart_max_harts())
-               return -1;
-       b->allnodes = (hart_dissem_flags_t*)malloc(np*sizeof(hart_dissem_flags_t));
-       memset(b->allnodes,0,np*sizeof(hart_dissem_flags_t));
-       b->nprocs = np;
-
-       b->logp = (np & (np-1)) != 0;
-       while(np >>= 1)
-               b->logp++;
-
-       size_t i,k;
-       for(i = 0; i < b->nprocs; i++)
-       {
-               b->allnodes[i].parity = 0;
-               b->allnodes[i].sense = 1;
-
-               for(k = 0; k < b->logp; k++)
-               {
-                       size_t j = (i+(1<<k)) % b->nprocs;
-                       b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
-                       b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
-               } 
-       }
-
-       return 0;
-}
-
-void hart_barrier_wait(hart_barrier_t* b, size_t pid)
-{
-       hart_dissem_flags_t* localflags = &b->allnodes[pid];
-       size_t i;
-       for(i = 0; i < b->logp; i++)
-       {
-               *localflags->partnerflags[localflags->parity][i] = localflags->sense;
-               while(localflags->myflags[localflags->parity][i] != localflags->sense);
-       }
-       if(localflags->parity)
-               localflags->sense = 1-localflags->sense;
-       localflags->parity = 1-localflags->parity;
-}
-
-int
-hart_self()
-{
-       // defined in ros/arch/hart.h
-       return __hart_self();
-}
-
-int
-hart_swap(int* addr, int val)
-{
-       return __hart_swap(addr,val);
-}
-
-void
-hart_relax()
-{
-       __hart_relax();
-}
-
diff --git a/user/parlib/mcs.c b/user/parlib/mcs.c
new file mode 100644 (file)
index 0000000..e031491
--- /dev/null
@@ -0,0 +1,94 @@
+#include <vcore.h>
+#include <mcs.h>
+#include <arch/atomic.h>
+#include <string.h>
+#include <stdlib.h>
+
+// MCS locks
+void mcs_lock_init(mcs_lock_t* lock)
+{
+       memset(lock,0,sizeof(mcs_lock_t));
+}
+
+static inline mcs_lock_qnode_t* mcs_qnode_swap(mcs_lock_qnode_t** addr, mcs_lock_qnode_t* val)
+{
+       return (mcs_lock_qnode_t*)atomic_swap((int*)addr,(int)val);
+}
+
+void mcs_lock_lock(mcs_lock_t* lock)
+{
+       mcs_lock_qnode_t* qnode = &lock->qnode[vcore_id()];
+       qnode->next = 0;
+       mcs_lock_qnode_t* predecessor = mcs_qnode_swap(&lock->lock,qnode);
+       if(predecessor)
+       {
+               qnode->locked = 1;
+               predecessor->next = qnode;
+               while(qnode->locked);
+       }
+}
+
+void mcs_lock_unlock(mcs_lock_t* lock)
+{
+       mcs_lock_qnode_t* qnode = &lock->qnode[vcore_id()];
+       if(qnode->next == 0)
+       {
+               mcs_lock_qnode_t* old_tail = mcs_qnode_swap(&lock->lock,0);
+               if(old_tail == qnode)
+                       return;
+
+               mcs_lock_qnode_t* usurper = mcs_qnode_swap(&lock->lock,old_tail);
+               while(qnode->next == 0);
+               if(usurper)
+                       usurper->next = qnode->next;
+               else
+                       qnode->next->locked = 0;
+       }
+       else
+               qnode->next->locked = 0;
+}
+
+// MCS dissemination barrier!
+int mcs_barrier_init(mcs_barrier_t* b, size_t np)
+{
+       if(np > max_vcores())
+               return -1;
+       b->allnodes = (mcs_dissem_flags_t*)malloc(np*sizeof(mcs_dissem_flags_t));
+       memset(b->allnodes,0,np*sizeof(mcs_dissem_flags_t));
+       b->nprocs = np;
+
+       b->logp = (np & (np-1)) != 0;
+       while(np >>= 1)
+               b->logp++;
+
+       size_t i,k;
+       for(i = 0; i < b->nprocs; i++)
+       {
+               b->allnodes[i].parity = 0;
+               b->allnodes[i].sense = 1;
+
+               for(k = 0; k < b->logp; k++)
+               {
+                       size_t j = (i+(1<<k)) % b->nprocs;
+                       b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
+                       b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
+               } 
+       }
+
+       return 0;
+}
+
+void mcs_barrier_wait(mcs_barrier_t* b, size_t pid)
+{
+       mcs_dissem_flags_t* localflags = &b->allnodes[pid];
+       size_t i;
+       for(i = 0; i < b->logp; i++)
+       {
+               *localflags->partnerflags[localflags->parity][i] = localflags->sense;
+               while(localflags->myflags[localflags->parity][i] != localflags->sense);
+       }
+       if(localflags->parity)
+               localflags->sense = 1-localflags->sense;
+       localflags->parity = 1-localflags->parity;
+}
+
index 992d557..621e79f 100644 (file)
@@ -1,18 +1,19 @@
 #include <pthread.h>
-#include <hart.h>
+#include <vcore.h>
+#include <mcs.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include <stdio.h>
+#include <rstdio.h>
 #include <errno.h>
+#include <arch/atomic.h>
 
-#include <debug.h>
 int threads_active = 1;
-hart_lock_t work_queue_lock = HART_LOCK_INIT;
+mcs_lock_t work_queue_lock = MCS_LOCK_INIT;
 pthread_t work_queue_head = 0;
 pthread_t work_queue_tail = 0;
 pthread_once_t init_once = PTHREAD_ONCE_INIT;
-pthread_t active_threads[HART_MAX_MAX_HARTS] = {0};
+pthread_t active_threads[MAX_VCORES] = {0};
 
 void queue_insert(pthread_t* head, pthread_t* tail, pthread_t node)
 {
@@ -34,22 +35,22 @@ pthread_t queue_remove(pthread_t* head, pthread_t* tail)
   return node;
 }
 
-void hart_entry()
+void vcore_entry()
 {
   pthread_t node = NULL;
   while(1)
   {
-    hart_lock_lock(&work_queue_lock);
+    mcs_lock_lock(&work_queue_lock);
     if(work_queue_head)
       node = queue_remove(&work_queue_head,&work_queue_tail);
-    hart_lock_unlock(&work_queue_lock);
+    mcs_lock_unlock(&work_queue_lock);
 
     if(node)
       break;
-    hart_relax();
+    cpu_relax();
   }
 
-  active_threads[hart_self()] = node;
+  active_threads[vcore_id()] = node;
 
   pthread_exit(node->start_routine(node->arg));
 }
@@ -80,14 +81,14 @@ int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
   (*thread)->next = 0;
   (*thread)->finished = 0;
   (*thread)->detached = 0;
-  hart_lock_lock(&work_queue_lock);
+  mcs_lock_lock(&work_queue_lock);
   {
     threads_active++;
     queue_insert(&work_queue_head,&work_queue_tail,*thread);
-    // don't return until we get a hart
-    while(threads_active > hart_current_harts() && hart_request(1));
+    // don't return until we get a vcore
+    while(threads_active > num_vcores() && vcore_request(1));
   }
-  hart_lock_unlock(&work_queue_lock);
+  mcs_lock_unlock(&work_queue_lock);
 
   return 0;
 }
@@ -148,7 +149,7 @@ int pthread_mutex_lock(pthread_mutex_t* m)
 
 int pthread_mutex_trylock(pthread_mutex_t* m)
 {
-  return hart_swap(&m->lock,1) == 0 ? 0 : EBUSY;
+  return atomic_swap(&m->lock,1) == 0 ? 0 : EBUSY;
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* m)
@@ -183,7 +184,7 @@ int pthread_cond_broadcast(pthread_cond_t *c)
 int pthread_cond_signal(pthread_cond_t *c)
 {
   int i;
-  for(i = 0; i < hart_max_harts(); i++)
+  for(i = 0; i < max_vcores(); i++)
   {
     if(c->waiters[i])
     {
@@ -196,10 +197,10 @@ int pthread_cond_signal(pthread_cond_t *c)
 
 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
 {
-  c->waiters[hart_self()] = 1;
+  c->waiters[vcore_id()] = 1;
   pthread_mutex_unlock(m);
 
-  volatile int* poll = &c->waiters[hart_self()];
+  volatile int* poll = &c->waiters[vcore_id()];
   while(*poll);
 
   pthread_mutex_lock(m);
@@ -232,7 +233,7 @@ int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
 
 pthread_t pthread_self()
 {
-  return active_threads[hart_self()];
+  return active_threads[vcore_id()];
 }
 
 int pthread_equal(pthread_t t1, pthread_t t2)
@@ -246,11 +247,11 @@ void pthread_exit(void* ret)
 
   pthread_t t = pthread_self();
 
-  hart_lock_lock(&work_queue_lock);
+  mcs_lock_lock(&work_queue_lock);
   threads_active--;
   if(threads_active == 0)
     exit(0);
-  hart_lock_unlock(&work_queue_lock);
+  mcs_lock_unlock(&work_queue_lock);
 
   if(t)
   {
@@ -260,12 +261,12 @@ void pthread_exit(void* ret)
       free(t);
   }
 
-  hart_entry();
+  vcore_entry();
 }
 
 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
 {
-  if(hart_swap(once_control,1) == 0)
+  if(atomic_swap(once_control,1) == 0)
     init_routine();
   return 0;
 }
@@ -276,18 +277,18 @@ int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, i
 
   b->sense = 0;
   b->nprocs = b->count = count;
-  hart_lock_init(&b->lock);
+  mcs_lock_init(&b->lock);
   return 0;
 }
 
 int pthread_barrier_wait(pthread_barrier_t* b)
 {
-  int id = hart_self();
+  int id = vcore_id();
   int ls = b->local_sense[32*id] = 1 - b->local_sense[32*id];
 
-  hart_lock_lock(&b->lock);
+  mcs_lock_lock(&b->lock);
   int count = --b->count;
-  hart_lock_unlock(&b->lock);
+  mcs_lock_unlock(&b->lock);
 
   if(count == 0)
   {
diff --git a/user/parlib/vcore.c b/user/parlib/vcore.c
new file mode 100644 (file)
index 0000000..d4db153
--- /dev/null
@@ -0,0 +1,147 @@
+#include <stdbool.h>
+#include <errno.h>
+#include <vcore.h>
+#include <mcs.h>
+#include <sys/param.h>
+#include <parlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <rstdio.h>
+
+// Only need in this file because _dl_allocate and friends are
+//  internal functions in glibc
+# ifdef __i386__
+#  define internal_function   __attribute ((regparm (3), stdcall))
+# else
+#  define internal_function
+# endif
+
+static size_t _max_vcores_ever_wanted = 0;
+static mcs_lock_t _vcore_lock = MCS_LOCK_INIT;
+
+extern void** vcore_thread_control_blocks;
+
+static void free_transition_tls(int id)
+{
+       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
+       if(vcore_thread_control_blocks[id])
+       {
+               _dl_deallocate_tls(vcore_thread_control_blocks[id],true);
+               vcore_thread_control_blocks[id] = NULL;
+       }
+}
+
+static int allocate_transition_tls(int id)
+{
+       extern void *_dl_allocate_tls (void *mem) internal_function;
+       // We want to free and then reallocate the tls rather than simply 
+       // reinitializing it because its size may have changed
+       free_transition_tls(id);
+
+       void* tls = _dl_allocate_tls(NULL);
+       if((vcore_thread_control_blocks[id] = tls) == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+       return 0;
+}
+
+#define TRANSITION_STACK_PAGES 2
+#define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
+
+static void free_transition_stack(int id)
+{
+       // don't actually free stacks
+}
+
+static int allocate_transition_stack(int id)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[id];
+       if (vcpd->transition_stack)
+               return 0; // reuse old stack
+
+       void* stackbot = mmap(0, TRANSITION_STACK_SIZE,
+                             PROT_READ|PROT_WRITE|PROT_EXEC,
+                             MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
+
+       if(stackbot == MAP_FAILED)
+               return -1; // errno set by mmap
+
+       vcpd->transition_stack = (uintptr_t)stackbot + TRANSITION_STACK_SIZE;
+
+       return 0;
+}
+
+int vcore_init()
+{
+       static int initialized = 0;
+       if(initialized)
+               return 0;
+
+       vcore_thread_control_blocks = (void**)calloc(max_vcores(),sizeof(void*));
+
+       if(!vcore_thread_control_blocks)
+               goto vcore_init_fail;
+
+       initialized = 1;
+       return 0;
+
+vcore_init_fail:
+       errno = ENOMEM;
+       return -1;
+}
+
+int vcore_request(size_t k)
+{
+       int ret = -1;
+       size_t i,j;
+
+       if(vcore_init() < 0)
+               return -1;
+
+       // TODO: could do this function without a lock once we 
+       // have atomic fetch and add in user space
+       mcs_lock_lock(&_vcore_lock);
+
+       size_t vcores_wanted = num_vcores() + k;
+       if(k < 0 || vcores_wanted > max_vcores())
+       {
+               errno = EAGAIN;
+               goto fail;
+       }
+
+       for(i = _max_vcores_ever_wanted; i < vcores_wanted; i++)
+       {
+               if(allocate_transition_stack(i) || allocate_transition_tls(i))
+                       goto fail; // errno set by the call that failed
+               _max_vcores_ever_wanted++;
+       }
+       ret = sys_resource_req(RES_CORES, vcores_wanted, 1, 0);
+
+fail:
+       mcs_lock_unlock(&_vcore_lock);
+       return ret;
+}
+
+void vcore_yield()
+{
+       sys_yield(0);
+}
+
+size_t max_vcores()
+{
+       return MIN(__procinfo.max_vcores, MAX_VCORES);
+}
+
+size_t num_vcores()
+{
+       return __procinfo.num_vcores;
+}
+
+int vcore_id()
+{
+       // defined in ros/arch/vcore.h
+       return __vcore_id();
+}
+
index 54bb4bd..dfed8ba 100644 (file)
@@ -11,7 +11,7 @@ ROS_USER_LIBS += $(OBJDIR)/$(USER_PTHREAD_DIR)/libpthread.a
 
 USER_PTHREAD_SRCFILES := \
                  $(USER_PARLIB_DIR)/pthread.c \
-                 $(USER_PARLIB_DIR)/hart.c \
+                 $(USER_PARLIB_DIR)/vcore.c \
                  $(USER_PARLIB_DIR)/syscall.c 
 
 # Only build files if they exist.