Clean up user library include paths (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 16 Feb 2016 19:33:42 +0000 (14:33 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 17 Feb 2016 22:26:28 +0000 (17:26 -0500)
Allowing libraries to search their own include/ for <foo.h> is a huge mess
that results in issues when glibc has foo.h.  The fix is to not allow that,
and to insist libraries refer to their own files by their full name
(libname/foo.h).

All user libraries (other than pthread) now have their include directories
arranged as:

user/LIBNAME/include/LIBNAME/FOO.h

With their include path being set to user/LIBNAME/include/, and all
 #includes explicitly list the libname.

Due to moving parlib's arch symlink, you'll need to do something like:

$ rm user/parlib/include/arch
$ make mrproper
$ mv .config.old .config
$ make ARCH=x86 oldconfig
$ make userclean

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
214 files changed:
.gitignore
Makefile
tools/compilers/gcc-glibc/Makefile
user/Makefrag-user-lib
user/benchutil/include/alarm.h [deleted file]
user/benchutil/include/benchutil [deleted symlink]
user/benchutil/include/benchutil/alarm.h [new file with mode: 0644]
user/benchutil/include/benchutil/measure.h [new file with mode: 0644]
user/benchutil/include/benchutil/pvcalarm.h [new file with mode: 0644]
user/benchutil/include/measure.h [deleted file]
user/benchutil/include/pvcalarm.h [deleted file]
user/iplib/include/icmp.h [deleted file]
user/iplib/include/iplib [deleted symlink]
user/iplib/include/iplib.h [deleted file]
user/iplib/include/iplib/icmp.h [new file with mode: 0644]
user/iplib/include/iplib/iplib.h [new file with mode: 0644]
user/ndblib/include/fcallfmt.h [deleted file]
user/ndblib/include/ndb.h [deleted file]
user/ndblib/include/ndbhf.h [deleted file]
user/ndblib/include/ndblib [deleted symlink]
user/ndblib/include/ndblib/fcallfmt.h [new file with mode: 0644]
user/ndblib/include/ndblib/ndb.h [new file with mode: 0644]
user/ndblib/include/ndblib/ndbhf.h [new file with mode: 0644]
user/ndblib/ndbopen.c
user/parlib/include/arc.h [deleted file]
user/parlib/include/assert.h [deleted file]
user/parlib/include/bitmask.h [deleted file]
user/parlib/include/ceq.h [deleted file]
user/parlib/include/common.h [deleted file]
user/parlib/include/dtls.h [deleted file]
user/parlib/include/evbitmap.h [deleted file]
user/parlib/include/event.h [deleted file]
user/parlib/include/mcs.h [deleted file]
user/parlib/include/net.h [deleted file]
user/parlib/include/parlib [deleted symlink]
user/parlib/include/parlib.h [deleted file]
user/parlib/include/parlib/arc.h [new file with mode: 0644]
user/parlib/include/parlib/assert.h [new file with mode: 0644]
user/parlib/include/parlib/bitmask.h [new file with mode: 0644]
user/parlib/include/parlib/ceq.h [new file with mode: 0644]
user/parlib/include/parlib/common.h [new file with mode: 0644]
user/parlib/include/parlib/dtls.h [new file with mode: 0644]
user/parlib/include/parlib/evbitmap.h [new file with mode: 0644]
user/parlib/include/parlib/event.h [new file with mode: 0644]
user/parlib/include/parlib/mcs.h [new file with mode: 0644]
user/parlib/include/parlib/net.h [new file with mode: 0644]
user/parlib/include/parlib/parlib.h [new file with mode: 0644]
user/parlib/include/parlib/poke.h [new file with mode: 0644]
user/parlib/include/parlib/pool.h [new file with mode: 0644]
user/parlib/include/parlib/printf-ext.h [new file with mode: 0644]
user/parlib/include/parlib/riscv/arch.h [new file with mode: 0644]
user/parlib/include/parlib/riscv/atomic.h [new file with mode: 0644]
user/parlib/include/parlib/riscv/bitmask.h [new file with mode: 0644]
user/parlib/include/parlib/riscv/trap.h [new file with mode: 0644]
user/parlib/include/parlib/riscv/vcore.h [new file with mode: 0644]
user/parlib/include/parlib/ros_debug.h [new file with mode: 0644]
user/parlib/include/parlib/serialize.h [new file with mode: 0644]
user/parlib/include/parlib/signal.h [new file with mode: 0644]
user/parlib/include/parlib/slab.h [new file with mode: 0644]
user/parlib/include/parlib/spinlock.h [new file with mode: 0644]
user/parlib/include/parlib/stdio.h [new file with mode: 0644]
user/parlib/include/parlib/timing.h [new file with mode: 0644]
user/parlib/include/parlib/tsc-compat.h [new file with mode: 0644]
user/parlib/include/parlib/ucq.h [new file with mode: 0644]
user/parlib/include/parlib/uthread.h [new file with mode: 0644]
user/parlib/include/parlib/vcore.h [new file with mode: 0644]
user/parlib/include/parlib/waitfreelist.h [new file with mode: 0644]
user/parlib/include/parlib/x86/arch.h [new file with mode: 0644]
user/parlib/include/parlib/x86/atomic.h [new file with mode: 0644]
user/parlib/include/parlib/x86/bitmask.h [new file with mode: 0644]
user/parlib/include/parlib/x86/trap.h [new file with mode: 0644]
user/parlib/include/parlib/x86/vcore.h [new file with mode: 0644]
user/parlib/include/parlib/x86/vcore32.h [new file with mode: 0644]
user/parlib/include/parlib/x86/vcore64.h [new file with mode: 0644]
user/parlib/include/poke.h [deleted file]
user/parlib/include/pool.h [deleted file]
user/parlib/include/printf-ext.h [deleted file]
user/parlib/include/riscv/arch.h [deleted file]
user/parlib/include/riscv/atomic.h [deleted file]
user/parlib/include/riscv/bitmask.h [deleted file]
user/parlib/include/riscv/trap.h [deleted file]
user/parlib/include/riscv/vcore.h [deleted file]
user/parlib/include/ros_debug.h [deleted file]
user/parlib/include/serialize.h [deleted file]
user/parlib/include/signal.h [deleted file]
user/parlib/include/slab.h [deleted file]
user/parlib/include/spinlock.h [deleted file]
user/parlib/include/stdio.h [deleted file]
user/parlib/include/timing.h [deleted file]
user/parlib/include/tsc-compat.h [deleted file]
user/parlib/include/ucq.h [deleted file]
user/parlib/include/uthread.h [deleted file]
user/parlib/include/vcore.h [deleted file]
user/parlib/include/waitfreelist.h [deleted file]
user/parlib/include/x86/arch.h [deleted file]
user/parlib/include/x86/atomic.h [deleted file]
user/parlib/include/x86/bitmask.h [deleted file]
user/parlib/include/x86/trap.h [deleted file]
user/parlib/include/x86/vcore.h [deleted file]
user/parlib/include/x86/vcore32.h [deleted file]
user/parlib/include/x86/vcore64.h [deleted file]
user/vmm/include/acpi/acakaros.h [deleted file]
user/vmm/include/acpi/acakarosex.h [deleted file]
user/vmm/include/acpi/acbuffer.h [deleted file]
user/vmm/include/acpi/acconfig.h [deleted file]
user/vmm/include/acpi/acenv.h [deleted file]
user/vmm/include/acpi/acenvex.h [deleted file]
user/vmm/include/acpi/acexcep.h [deleted file]
user/vmm/include/acpi/acgcc.h [deleted file]
user/vmm/include/acpi/acnames.h [deleted file]
user/vmm/include/acpi/acoutput.h [deleted file]
user/vmm/include/acpi/acpi.h [deleted file]
user/vmm/include/acpi/acpi_bus.h [deleted file]
user/vmm/include/acpi/acpi_drivers.h [deleted file]
user/vmm/include/acpi/acpi_io.h [deleted file]
user/vmm/include/acpi/acpi_lpat.h [deleted file]
user/vmm/include/acpi/acpi_numa.h [deleted file]
user/vmm/include/acpi/acpiosxf.h [deleted file]
user/vmm/include/acpi/acpixf.h [deleted file]
user/vmm/include/acpi/acrestyp.h [deleted file]
user/vmm/include/acpi/actbl.h [deleted file]
user/vmm/include/acpi/actbl1.h [deleted file]
user/vmm/include/acpi/actbl2.h [deleted file]
user/vmm/include/acpi/actbl3.h [deleted file]
user/vmm/include/acpi/actypes.h [deleted file]
user/vmm/include/acpi/acuuid.h [deleted file]
user/vmm/include/acpi/apei.h [deleted file]
user/vmm/include/acpi/button.h [deleted file]
user/vmm/include/acpi/ghes.h [deleted file]
user/vmm/include/acpi/hed.h [deleted file]
user/vmm/include/acpi/pdc_intel.h [deleted file]
user/vmm/include/acpi/platform/acakaros.h [deleted file]
user/vmm/include/acpi/platform/acakarosex.h [deleted file]
user/vmm/include/acpi/platform/acenv.h [deleted file]
user/vmm/include/acpi/platform/acenvex.h [deleted file]
user/vmm/include/acpi/platform/acgcc.h [deleted file]
user/vmm/include/acpi/processor.h [deleted file]
user/vmm/include/acpi/reboot.h [deleted file]
user/vmm/include/acpi/video.h [deleted file]
user/vmm/include/coreboot_tables.h [deleted file]
user/vmm/include/linux_bootparam.h [deleted file]
user/vmm/include/virtio.h [deleted file]
user/vmm/include/virtio_9p.h [deleted file]
user/vmm/include/virtio_balloon.h [deleted file]
user/vmm/include/virtio_blk.h [deleted file]
user/vmm/include/virtio_config.h [deleted file]
user/vmm/include/virtio_console.h [deleted file]
user/vmm/include/virtio_ids.h [deleted file]
user/vmm/include/virtio_input.h [deleted file]
user/vmm/include/virtio_mmio.h [deleted file]
user/vmm/include/virtio_net.h [deleted file]
user/vmm/include/virtio_pci.h [deleted file]
user/vmm/include/virtio_ring.h [deleted file]
user/vmm/include/virtio_rng.h [deleted file]
user/vmm/include/virtio_scsi.h [deleted file]
user/vmm/include/virtio_types.h [deleted file]
user/vmm/include/vmm [deleted symlink]
user/vmm/include/vmm.h [deleted file]
user/vmm/include/vmm/acpi/acakaros.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acakarosex.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acbuffer.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acconfig.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acenv.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acenvex.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acexcep.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acgcc.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acnames.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acoutput.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi_bus.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi_drivers.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi_io.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi_lpat.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpi_numa.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpiosxf.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acpixf.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acrestyp.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/actbl.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/actbl1.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/actbl2.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/actbl3.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/actypes.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/acuuid.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/apei.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/button.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/ghes.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/hed.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/pdc_intel.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/platform/acakaros.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/platform/acakarosex.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/platform/acenv.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/platform/acenvex.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/platform/acgcc.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/processor.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/reboot.h [new file with mode: 0644]
user/vmm/include/vmm/acpi/video.h [new file with mode: 0644]
user/vmm/include/vmm/coreboot_tables.h [new file with mode: 0644]
user/vmm/include/vmm/linux_bootparam.h [new file with mode: 0644]
user/vmm/include/vmm/virtio.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_9p.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_balloon.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_blk.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_config.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_console.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_ids.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_input.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_mmio.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_net.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_pci.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_ring.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_rng.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_scsi.h [new file with mode: 0644]
user/vmm/include/vmm/virtio_types.h [new file with mode: 0644]
user/vmm/include/vmm/vmm.h [new file with mode: 0644]

index 2c8ba61..5cc90e4 100644 (file)
@@ -21,7 +21,7 @@ kern/include/arch
 kern/src/arch
 kern/src/build_info.*
 kern/src/error.c
-user/parlib/include/arch
+user/parlib/include/parlib/arch
 Documentation/doxygen/rosdoc
 sim/
 sim
index ad1a74c..1fb54ba 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -122,7 +122,7 @@ endif
 
 PHONY += symlinks clean_symlinks
 clean_symlinks: objclean
-       @rm -f kern/include/arch kern/boot user/parlib/include/arch
+       @rm -f kern/include/arch kern/boot user/parlib/include/parlib/arch
 
 arch-link := $(notdir $(shell readlink kern/include/arch))
 valid-arches := $(notdir $(wildcard kern/arch/*))
@@ -140,7 +140,7 @@ symlinks: clean_symlinks
        @echo Making symlinks...
        $(Q)ln -fs ../arch/$(ARCH) kern/include/arch
        $(Q)ln -fs arch/$(ARCH)/boot kern/boot
-       $(Q)ln -fs $(ARCH) user/parlib/include/arch
+       $(Q)ln -fs $(ARCH) user/parlib/include/parlib/arch
        $(Q)$(MAKE) -f $(srctree)/Makefile clean
 
     else
index 55adf9e..41f4f8b 100644 (file)
@@ -472,9 +472,8 @@ $(BINARY_PREFIX)gcc-stage2-builddir: gcc-$(GCC_VERSION)
        mkdir -p $(SYSROOT)/usr/include/ros/arch
        cp -r $(AKAROSDIR)/kern/arch/$(AKAROS_ARCH_DIR)/ros/* \
            $(SYSROOT)/usr/include/ros/arch/
-       mkdir -p $(SYSROOT)/usr/include/parlib
        cp -r $(AKAROSDIR)/user/parlib/include/* \
-           $(SYSROOT)/usr/include/parlib/
+           $(SYSROOT)/usr/include/
        cp -r $(AKAROSDIR)/user/pthread/*.h \
            $(SYSROOT)/usr/include/
 
index 2ac9d05..2e27ad9 100644 (file)
@@ -43,15 +43,10 @@ $(FINALLIB): $(OBJS)
        @mkdir -p $(@D)
        $(Q)$(AR) rc $@ $(OBJS)
 
-# Allow three different patterns for installing include files
+# Allow two different patterns for installing include files
 $(FINALLIB-INSTALL): $(FINALLIB)
        @cp $(FINALLIB) $@
-       @if [ -L "$(INCDIR)/$(LIBNAME)" ]; then \
-               rm -rf $(XCC_TARGET_INCLUDE)/$(LIBNAME) ; \
-               mkdir $(XCC_TARGET_INCLUDE)/$(LIBNAME) ; \
-               cp -r $(INCDIR)/* $(XCC_TARGET_INCLUDE)/$(LIBNAME)/ ; \
-               rm $(XCC_TARGET_INCLUDE)/$(LIBNAME)/$(LIBNAME) ; \
-       elif [ -d "$(INCDIR)/$(LIBNAME)" ]; then \
+       @if [ -d "$(INCDIR)/$(LIBNAME)" ]; then \
                rm -rf $(XCC_TARGET_INCLUDE)/$(LIBNAME) ; \
                cp -r $(INCDIR)/$(LIBNAME) $(XCC_TARGET_INCLUDE)/ ; \
        else \
diff --git a/user/benchutil/include/alarm.h b/user/benchutil/include/alarm.h
deleted file mode 100644 (file)
index 79fd3f8..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Userspace alarms.  There are lower level helpers to build your own alarms
- * from the #A device and an alarm service, based off a slimmed down version of
- * the kernel alarms.  Under the hood, the user alarm uses the #A service for
- * the root of the alarm chain.
- *
- * This is (was) hanging out in benchutil so as to not create a dependency from
- * parlib on benchutil (usec2tsc and friends).
- *
- * There's only one timer chain, unlike in the kernel, for the entire process.
- * If you want one-off timers unrelated to the chain (and sent to other vcores),
- * use #A directly.
- *
- * Your handlers will run from vcore context.
- *
- * 1) To set a handler to run on an alarm:
- *     struct alarm_waiter *waiter = malloc(sizeof(struct alarm_waiter));
- *     init_awaiter(waiter, HANDLER);
- *     waiter->data = something;
- *     set_awaiter_rel(waiter, USEC);
- *     set_alarm(waiter);
- * If you want the HANDLER to run again, do this at the end of it:
- *     set_awaiter_rel(waiter, USEC);
- *     __set_alarm(waiter);
- * Do not call set_alarm() from within an alarm handler; you'll deadlock.
- * Don't forget to manage your memory at some (safe) point:
- *     free(waiter); */
-
-#pragma once
-
-#include <parlib/common.h>
-#include <sys/queue.h>
-#include <parlib/spinlock.h>
-#include <parlib/event.h>
-
-__BEGIN_DECLS
-
-/* Low-level alarm interface */
-
-int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r);
-int devalarm_set_evq(int ctlfd, struct event_queue *ev_q);
-int devalarm_set_time(int timerfd, uint64_t tsc_time);
-int devalarm_disable(int ctlfd);
-
-/* Alarm service */
-
-/* Specifc waiter, per alarm */
-struct alarm_waiter {
-       uint64_t                                        wake_up_time;   /* tsc time */
-       void (*func) (struct alarm_waiter *waiter);
-       void                                            *data;
-       TAILQ_ENTRY(alarm_waiter)       next;
-       bool                                            on_tchain;
-};
-TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
-
-typedef void (*alarm_handler)(struct alarm_waiter *waiter);
-
-/* Sorted collection of alarms. */
-struct timer_chain {
-       struct spin_pdr_lock            lock;
-       struct awaiters_tailq           waiters;
-       uint64_t                                        earliest_time;
-       uint64_t                                        latest_time;
-       int                                                     ctlfd;
-       int                                                     timerfd;
-       int                                                     alarmid;
-       struct event_queue                      *ev_q;
-};
-
-/* For fresh alarm waiters.  func == 0 for kthreads */
-void init_awaiter(struct alarm_waiter *waiter,
-                  void (*func) (struct alarm_waiter *));
-/* Sets the time an awaiter goes off */
-void set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time);
-void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_time);
-void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
-void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
-/* Arms/disarms the alarm */
-void __set_alarm(struct alarm_waiter *waiter);
-void set_alarm(struct alarm_waiter *waiter);
-bool unset_alarm(struct alarm_waiter *waiter);
-void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time);
-
-/* "parlib" alarm handlers */
-void alarm_abort_sysc(struct alarm_waiter *awaiter);
-
-/* Debugging */
-#define ALARM_POISON_TIME 12345
-void print_chain(struct timer_chain *tchain);
-
-__END_DECLS
diff --git a/user/benchutil/include/benchutil b/user/benchutil/include/benchutil
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
diff --git a/user/benchutil/include/benchutil/alarm.h b/user/benchutil/include/benchutil/alarm.h
new file mode 100644 (file)
index 0000000..79fd3f8
--- /dev/null
@@ -0,0 +1,95 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace alarms.  There are lower level helpers to build your own alarms
+ * from the #A device and an alarm service, based off a slimmed down version of
+ * the kernel alarms.  Under the hood, the user alarm uses the #A service for
+ * the root of the alarm chain.
+ *
+ * This is (was) hanging out in benchutil so as to not create a dependency from
+ * parlib on benchutil (usec2tsc and friends).
+ *
+ * There's only one timer chain, unlike in the kernel, for the entire process.
+ * If you want one-off timers unrelated to the chain (and sent to other vcores),
+ * use #A directly.
+ *
+ * Your handlers will run from vcore context.
+ *
+ * 1) To set a handler to run on an alarm:
+ *     struct alarm_waiter *waiter = malloc(sizeof(struct alarm_waiter));
+ *     init_awaiter(waiter, HANDLER);
+ *     waiter->data = something;
+ *     set_awaiter_rel(waiter, USEC);
+ *     set_alarm(waiter);
+ * If you want the HANDLER to run again, do this at the end of it:
+ *     set_awaiter_rel(waiter, USEC);
+ *     __set_alarm(waiter);
+ * Do not call set_alarm() from within an alarm handler; you'll deadlock.
+ * Don't forget to manage your memory at some (safe) point:
+ *     free(waiter); */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <sys/queue.h>
+#include <parlib/spinlock.h>
+#include <parlib/event.h>
+
+__BEGIN_DECLS
+
+/* Low-level alarm interface */
+
+int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r);
+int devalarm_set_evq(int ctlfd, struct event_queue *ev_q);
+int devalarm_set_time(int timerfd, uint64_t tsc_time);
+int devalarm_disable(int ctlfd);
+
+/* Alarm service */
+
+/* Specifc waiter, per alarm */
+struct alarm_waiter {
+       uint64_t                                        wake_up_time;   /* tsc time */
+       void (*func) (struct alarm_waiter *waiter);
+       void                                            *data;
+       TAILQ_ENTRY(alarm_waiter)       next;
+       bool                                            on_tchain;
+};
+TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
+
+typedef void (*alarm_handler)(struct alarm_waiter *waiter);
+
+/* Sorted collection of alarms. */
+struct timer_chain {
+       struct spin_pdr_lock            lock;
+       struct awaiters_tailq           waiters;
+       uint64_t                                        earliest_time;
+       uint64_t                                        latest_time;
+       int                                                     ctlfd;
+       int                                                     timerfd;
+       int                                                     alarmid;
+       struct event_queue                      *ev_q;
+};
+
+/* For fresh alarm waiters.  func == 0 for kthreads */
+void init_awaiter(struct alarm_waiter *waiter,
+                  void (*func) (struct alarm_waiter *));
+/* Sets the time an awaiter goes off */
+void set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time);
+void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_time);
+void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
+void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
+/* Arms/disarms the alarm */
+void __set_alarm(struct alarm_waiter *waiter);
+void set_alarm(struct alarm_waiter *waiter);
+bool unset_alarm(struct alarm_waiter *waiter);
+void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time);
+
+/* "parlib" alarm handlers */
+void alarm_abort_sysc(struct alarm_waiter *awaiter);
+
+/* Debugging */
+#define ALARM_POISON_TIME 12345
+void print_chain(struct timer_chain *tchain);
+
+__END_DECLS
diff --git a/user/benchutil/include/benchutil/measure.h b/user/benchutil/include/benchutil/measure.h
new file mode 100644 (file)
index 0000000..9132a8f
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace functions for various measurements.
+ *
+ * For now, this is built into parlib.  We can pull it out in the future.  Many
+ * of the larger functions are in flux (interfaces, options, etc). */
+
+/* Basic stats computation and printing.
+ *
+ * All of these expect a 2D collection of samples, where the first array is an
+ * array of arrays of samples.  The first array's members are something like
+ * per-thread samples, where each thread fills in its
+ * data[thread_id][sample_number].  The samples should be ordered in
+ * chronological order.  Ultimately, the sample needs to produce a uint64_t
+ * (e.g. TSC tick). */
+
+#pragma once
+
+__BEGIN_DECLS
+
+struct sample_stats {
+       int (*get_sample)(void **data, int i, int j, uint64_t *sample);
+       uint64_t                                        avg_time;
+       uint64_t                                        var_time;
+       uint64_t                                        max_time;
+       uint64_t                                        min_time;
+       unsigned int                            lat_50;
+       unsigned int                            lat_75;
+       unsigned int                            lat_90;
+       unsigned int                            lat_99;
+       uint64_t                                        total_samples;
+};
+
+/* Computes basic stats and prints histograms, stats returned via *stats */
+void compute_stats(void **data, int nr_i, int nr_j, struct sample_stats *stats);
+
+/* Prints the throughput of events in **data */
+void print_throughput(void **data, unsigned int nr_steps, uint64_t interval,
+                      unsigned int nr_print_steps, uint64_t start_time,
+                      int nr_i, int nr_j,
+                      int (*get_sample)(void **data, int i, int j,
+                                        uint64_t *sample));
+
+__END_DECLS
diff --git a/user/benchutil/include/benchutil/pvcalarm.h b/user/benchutil/include/benchutil/pvcalarm.h
new file mode 100644 (file)
index 0000000..410e8e5
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * See LICENSE for details. */
+
+#pragma once
+
+#include <stdint.h>
+__BEGIN_DECLS
+
+/* Types of per-vcore alarms that can be set */
+enum {
+       /* This is a real-time alarm that does not take into account time that a
+        * vcore spends offline not doing work. It is like the posix ITIMER_REAL
+        * but for vcores. */
+       PVCALARM_REAL,
+       /* This is a profiling alarm that only accounts for time that a vcore
+        * spends online doing useful work. It is like the posix ITIMER_PROF but
+        * for vcores. */
+       PVCALARM_PROF
+};
+
+/* Enable the per-vcore calarm service according to one of the policies listed
+ * above.  Every interval usecs the provided callback will be called on each
+ * active vcore according to that policy. */
+int enable_pvcalarms(int policy, uint64_t interval, void (*callback) (void));
+
+/* Disable the currently active per-vcore alarm service */
+int disable_pvcalarms();
+
+__END_DECLS
diff --git a/user/benchutil/include/measure.h b/user/benchutil/include/measure.h
deleted file mode 100644 (file)
index 9132a8f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Userspace functions for various measurements.
- *
- * For now, this is built into parlib.  We can pull it out in the future.  Many
- * of the larger functions are in flux (interfaces, options, etc). */
-
-/* Basic stats computation and printing.
- *
- * All of these expect a 2D collection of samples, where the first array is an
- * array of arrays of samples.  The first array's members are something like
- * per-thread samples, where each thread fills in its
- * data[thread_id][sample_number].  The samples should be ordered in
- * chronological order.  Ultimately, the sample needs to produce a uint64_t
- * (e.g. TSC tick). */
-
-#pragma once
-
-__BEGIN_DECLS
-
-struct sample_stats {
-       int (*get_sample)(void **data, int i, int j, uint64_t *sample);
-       uint64_t                                        avg_time;
-       uint64_t                                        var_time;
-       uint64_t                                        max_time;
-       uint64_t                                        min_time;
-       unsigned int                            lat_50;
-       unsigned int                            lat_75;
-       unsigned int                            lat_90;
-       unsigned int                            lat_99;
-       uint64_t                                        total_samples;
-};
-
-/* Computes basic stats and prints histograms, stats returned via *stats */
-void compute_stats(void **data, int nr_i, int nr_j, struct sample_stats *stats);
-
-/* Prints the throughput of events in **data */
-void print_throughput(void **data, unsigned int nr_steps, uint64_t interval,
-                      unsigned int nr_print_steps, uint64_t start_time,
-                      int nr_i, int nr_j,
-                      int (*get_sample)(void **data, int i, int j,
-                                        uint64_t *sample));
-
-__END_DECLS
diff --git a/user/benchutil/include/pvcalarm.h b/user/benchutil/include/pvcalarm.h
deleted file mode 100644 (file)
index 410e8e5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2014 The Regents of the University of California
- * Kevin Klues <klueska@cs.berkeley.edu>
- * See LICENSE for details. */
-
-#pragma once
-
-#include <stdint.h>
-__BEGIN_DECLS
-
-/* Types of per-vcore alarms that can be set */
-enum {
-       /* This is a real-time alarm that does not take into account time that a
-        * vcore spends offline not doing work. It is like the posix ITIMER_REAL
-        * but for vcores. */
-       PVCALARM_REAL,
-       /* This is a profiling alarm that only accounts for time that a vcore
-        * spends online doing useful work. It is like the posix ITIMER_PROF but
-        * for vcores. */
-       PVCALARM_PROF
-};
-
-/* Enable the per-vcore calarm service according to one of the policies listed
- * above.  Every interval usecs the provided callback will be called on each
- * active vcore according to that policy. */
-int enable_pvcalarms(int policy, uint64_t interval, void (*callback) (void));
-
-/* Disable the currently active per-vcore alarm service */
-int disable_pvcalarms();
-
-__END_DECLS
diff --git a/user/iplib/include/icmp.h b/user/iplib/include/icmp.h
deleted file mode 100644 (file)
index d50853b..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* 
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-/* ICMP for IP v4 and v6 */
-
-#pragma once
-
-__BEGIN_DECLS
-
-enum
-{
-       /* Packet Types, icmp v4 (rfc 792) */
-       EchoReply       = 0,
-       Unreachable     = 3,
-       SrcQuench       = 4,
-       Redirect        = 5,
-       EchoRequest     = 8,
-       TimeExceed      = 11,
-       InParmProblem   = 12,
-       Timestamp       = 13,
-       TimestampReply  = 14,
-       InfoRequest     = 15,
-       InfoReply       = 16,
-       AddrMaskRequest = 17,
-       AddrMaskReply   = 18,
-       Traceroute      = 30,
-       IPv6WhereAreYou = 33,
-       IPv6IAmHere     = 34,
-
-       /* packet types, icmp v6 (rfc 2463) */
-
-        /* error messages */
-       UnreachableV6   = 1,
-       PacketTooBigV6  = 2,
-       TimeExceedV6    = 3,
-       ParamProblemV6  = 4,
-
-        /* informational messages (rfc 2461 also) */
-       EchoRequestV6   = 128,
-       EchoReplyV6     = 129,
-       RouterSolicit   = 133,
-       RouterAdvert    = 134,
-       NbrSolicit      = 135,
-       NbrAdvert       = 136,
-       RedirectV6      = 137,
-
-       Maxtype6        = 137,
-
-       ICMP_HDRSIZE    = 8,
-};
-
-struct ip4hdr
-{
-       uint8_t vihl;           /* Version and header length */
-       uint8_t tos;            /* Type of service */
-       uint8_t length[2];      /* packet length */
-       uint8_t id[2];          /* Identification */
-       uint8_t frag[2];        /* Fragment information */
-       uint8_t ttl;            /* Time to live */
-       uint8_t proto;          /* Protocol */
-       uint8_t ipcksum[2];     /* Header checksum */
-       uint8_t src[4];         /* Ipv4 source */
-       uint8_t dst[4];         /* Ipv4 destination */
-
-       uint8_t data[];
-};
-
-// #define IP4HDRSZ offsetof(Ip4hdr, data[0])
-
-/* the icmp payload has the same format in v4 and v6 */
-
-struct icmphdr {
-       uint8_t type;
-       uint8_t code;
-       uint8_t cksum[2];
-       uint8_t icmpid[2];
-       uint8_t seq[2];
-       uint8_t data[];
-};
-
-// #define ICMPHDRSZ offsetof(Icmphdr, data[0])
-
-__END_DECLS
diff --git a/user/iplib/include/iplib b/user/iplib/include/iplib
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
diff --git a/user/iplib/include/iplib.h b/user/iplib/include/iplib.h
deleted file mode 100644 (file)
index e7ada85..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/* 
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-#pragma once
-
-#include <parlib/common.h>
-
-__BEGIN_DECLS
-
-enum 
-{
-       IPaddrlen=      16,
-       IPv4addrlen=    4,
-       IPv4off=        12,
-       IPllen=         4,
-       IPV4HDR_LEN=    20,
-
-       /* vihl & vcf[0] values */
-       IP_VER4=        0x40,
-       IP_VER6=        0x60,
-       NETPATHLEN=     40,
-};
-
-/*
- *  for reading /net/ipifc
- */
-
-/* local address */
-struct iplifc
-{
-       struct iplifc   *next;
-
-       /* per address on the ip interface */
-       uint8_t ip[IPaddrlen];
-       uint8_t mask[IPaddrlen];
-       uint8_t net[IPaddrlen];         /* ip & mask */
-       uint32_t        preflt;                 /* preferred lifetime */
-       uint32_t        validlt;                /* valid lifetime */
-};
-
-/* default values, one per stack */
-struct ipv6rp
-{
-       int     mflag;
-       int     oflag;
-       int     maxraint;
-       int     minraint;
-       int     linkmtu;
-       int     reachtime;
-       int     rxmitra;
-       int     ttl;
-       int     routerlt;       
-};
-
-/* actual interface */
-struct ipifc
-{
-       struct ipifc    *next;
-       struct iplifc   *lifc;
-
-       /* per ip interface */
-       int     index;                  /* number of interface in ipifc dir */
-       char    dev[64];
-       uint8_t sendra6;                /* on == send router adv */
-       uint8_t recvra6;                /* on == rcv router adv */
-       int     mtu;
-       uint32_t        pktin;
-       uint32_t        pktout;
-       uint32_t        errin;
-       uint32_t        errout;
-       struct ipv6rp   rp;
-};
-
-#define ISIPV6MCAST(addr)      ((addr)[0] == 0xff)
-#define ISIPV6LINKLOCAL(addr) ((addr)[0] == 0xfe && ((addr)[1] & 0xc0) == 0x80)
-
-/*
- * ipv6 constants
- * `ra' is `router advertisement', `rs' is `router solicitation'.
- * `na' is `neighbour advertisement'.
- */
-enum {
-       IPV6HDR_LEN     = 40,
-
-       /* neighbour discovery option types */
-       V6nd_srclladdr  = 1,
-       V6nd_targlladdr = 2,
-       V6nd_pfxinfo    = 3,
-       V6nd_redirhdr   = 4,
-       V6nd_mtu        = 5,
-       /* new since rfc2461; see iana.org/assignments/icmpv6-parameters */
-       V6nd_home       = 8,
-       V6nd_srcaddrs   = 9,            /* rfc3122 */
-       V6nd_ip         = 17,
-       /* /lib/rfc/drafts/draft-jeong-dnsop-ipv6-dns-discovery-12.txt */
-       V6nd_rdns       = 25,
-       /* plan 9 extensions */
-       V6nd_9fs        = 250,
-       V6nd_9auth      = 251,
-
-       /* Router constants (all times in ms.) */
-       Maxv6initraintvl= 16000,
-       Maxv6initras    = 3,
-       Maxv6finalras   = 3,
-       Minv6interradelay= 3000,
-       Maxv6radelay    = 500,
-
-       /* Host constants */
-       Maxv6rsdelay    = 1000,
-       V6rsintvl       = 4000,
-       Maxv6rss        = 3,
-
-       /* Node constants */
-       Maxv6mcastrss   = 3,
-       Maxv6unicastrss = 3,
-       Maxv6anycastdelay= 1000,
-       Maxv6na         = 3,
-       V6reachabletime = 30000,
-       V6retranstimer  = 1000,
-       V6initprobedelay= 5000,
-};
-
-# if 0
-/* in icmp.h? */
-struct ip4hdr
-{
-       uint8_t vihl;           /* Version and header length */
-       uint8_t tos;            /* Type of service */
-       uint8_t length[2];      /* packet length */
-       uint8_t id[2];          /* ip->identification */
-       uint8_t frag[2];        /* Fragment information */
-       uint8_t ttl;            /* Time to live */
-       uint8_t proto;          /* Protocol */
-       uint8_t cksum[2];       /* Header checksum */
-       uint8_t src[4];         /* IP source */
-       uint8_t dst[4];         /* IP destination */
-};
-#endif
-
-/* V6 header on the wire */
-
-struct ip6hdr {
-       uint8_t vcf[4];         /* version:4, traffic class:8, flow label:20 */
-       uint8_t ploadlen[2];    /* payload length: packet length - 40 */
-       uint8_t proto;          /* next header type */
-       uint8_t ttl;            /* hop limit */
-       uint8_t src[IPaddrlen]; /* source address */
-       uint8_t dst[IPaddrlen]; /* destination address */
-       uint8_t payload[];
-};
-
-/*
- *  user-level icmpv6 with control message "headers"
- */
-
-struct icmp6hdr {
-       uint8_t _0_[8];
-       uint8_t laddr[IPaddrlen];       /* local address */
-       uint8_t raddr[IPaddrlen];       /* remote address */
-};
-
-/*
- *  user level udp headers with control message "headers"
- */
-enum 
-{
-       Udphdrsize=     52,     /* size of a Udphdr */
-};
-
-struct udphdr
-{
-       uint8_t raddr[IPaddrlen];       /* V6 remote address */
-       uint8_t laddr[IPaddrlen];       /* V6 local address */
-       uint8_t ifcaddr[IPaddrlen];     /* V6 ifc addr msg was received on */
-       uint8_t rport[2];               /* remote port */
-       uint8_t lport[2];               /* local port */
-};
-
-uint8_t*       defmask(uint8_t*);
-void   maskip(uint8_t*, uint8_t*, uint8_t*);
-//int  eipfmt(Fmt*);
-int    isv4(uint8_t*);
-int64_t        parseip(uint8_t*, char*);
-int64_t        parseipmask(uint8_t*, char*);
-char*  v4parseip(uint8_t*, char*);
-char*  v4parsecidr(uint8_t*, uint8_t*, char*);
-int    parseether(uint8_t*, char*);
-int    myipaddr(uint8_t*, char*);
-int    myetheraddr(uint8_t*, char*);
-int    equivip4(uint8_t*, uint8_t*);
-int    equivip6(uint8_t*, uint8_t*);
-
-struct ipifc*  readipifc(char*, struct ipifc*, int);
-
-void   hnputv(void*, uint64_t);
-void   hnputl(void*, unsigned int);
-void   hnputs(void*, uint16_t);
-uint64_t       nhgetv(void*);
-unsigned int   nhgetl(void*);
-uint16_t       nhgets(void*);
-uint16_t       ptclbsum(uint8_t*, int);
-
-int    v6tov4(uint8_t*, uint8_t*);
-void   v4tov6(uint8_t*, uint8_t*);
-
-#define        ipcmp(x, y) memcmp(x, y, IPaddrlen)
-#define        ipmove(x, y) memmove(x, y, IPaddrlen)
-
-extern uint8_t IPv4bcast[IPaddrlen];
-extern uint8_t IPv4bcastobs[IPaddrlen];
-extern uint8_t IPv4allsys[IPaddrlen];
-extern uint8_t IPv4allrouter[IPaddrlen];
-extern uint8_t IPnoaddr[IPaddrlen];
-extern uint8_t v4prefix[IPaddrlen];
-extern uint8_t IPallbits[IPaddrlen];
-
-#define CLASS(p) ((*(uint8_t*)(p))>>6)
-
-int tokenize(char *s, char **args, int maxargs);
-int getfields(char *str, char **args, int max, int mflag, char *unused_set);
-char *netmkaddr(char *linear, char *defnet, char *defsrv);
-int dial9(char *dest, char *local, char *dir, int *cfdp, int flags);
-int announce9(char *addr, char *dir, int flags);
-int listen9(char *dir, char *newdir, int flags);
-int accept9(int ctl, char *dir);
-int reject9(int ctl, char *dir, char *cause);
-
-__END_DECLS
diff --git a/user/iplib/include/iplib/icmp.h b/user/iplib/include/iplib/icmp.h
new file mode 100644 (file)
index 0000000..d50853b
--- /dev/null
@@ -0,0 +1,88 @@
+/* 
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+/* ICMP for IP v4 and v6 */
+
+#pragma once
+
+__BEGIN_DECLS
+
+enum
+{
+       /* Packet Types, icmp v4 (rfc 792) */
+       EchoReply       = 0,
+       Unreachable     = 3,
+       SrcQuench       = 4,
+       Redirect        = 5,
+       EchoRequest     = 8,
+       TimeExceed      = 11,
+       InParmProblem   = 12,
+       Timestamp       = 13,
+       TimestampReply  = 14,
+       InfoRequest     = 15,
+       InfoReply       = 16,
+       AddrMaskRequest = 17,
+       AddrMaskReply   = 18,
+       Traceroute      = 30,
+       IPv6WhereAreYou = 33,
+       IPv6IAmHere     = 34,
+
+       /* packet types, icmp v6 (rfc 2463) */
+
+        /* error messages */
+       UnreachableV6   = 1,
+       PacketTooBigV6  = 2,
+       TimeExceedV6    = 3,
+       ParamProblemV6  = 4,
+
+        /* informational messages (rfc 2461 also) */
+       EchoRequestV6   = 128,
+       EchoReplyV6     = 129,
+       RouterSolicit   = 133,
+       RouterAdvert    = 134,
+       NbrSolicit      = 135,
+       NbrAdvert       = 136,
+       RedirectV6      = 137,
+
+       Maxtype6        = 137,
+
+       ICMP_HDRSIZE    = 8,
+};
+
+struct ip4hdr
+{
+       uint8_t vihl;           /* Version and header length */
+       uint8_t tos;            /* Type of service */
+       uint8_t length[2];      /* packet length */
+       uint8_t id[2];          /* Identification */
+       uint8_t frag[2];        /* Fragment information */
+       uint8_t ttl;            /* Time to live */
+       uint8_t proto;          /* Protocol */
+       uint8_t ipcksum[2];     /* Header checksum */
+       uint8_t src[4];         /* Ipv4 source */
+       uint8_t dst[4];         /* Ipv4 destination */
+
+       uint8_t data[];
+};
+
+// #define IP4HDRSZ offsetof(Ip4hdr, data[0])
+
+/* the icmp payload has the same format in v4 and v6 */
+
+struct icmphdr {
+       uint8_t type;
+       uint8_t code;
+       uint8_t cksum[2];
+       uint8_t icmpid[2];
+       uint8_t seq[2];
+       uint8_t data[];
+};
+
+// #define ICMPHDRSZ offsetof(Icmphdr, data[0])
+
+__END_DECLS
diff --git a/user/iplib/include/iplib/iplib.h b/user/iplib/include/iplib/iplib.h
new file mode 100644 (file)
index 0000000..e7ada85
--- /dev/null
@@ -0,0 +1,233 @@
+/* 
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+#pragma once
+
+#include <parlib/common.h>
+
+__BEGIN_DECLS
+
+enum 
+{
+       IPaddrlen=      16,
+       IPv4addrlen=    4,
+       IPv4off=        12,
+       IPllen=         4,
+       IPV4HDR_LEN=    20,
+
+       /* vihl & vcf[0] values */
+       IP_VER4=        0x40,
+       IP_VER6=        0x60,
+       NETPATHLEN=     40,
+};
+
+/*
+ *  for reading /net/ipifc
+ */
+
+/* local address */
+struct iplifc
+{
+       struct iplifc   *next;
+
+       /* per address on the ip interface */
+       uint8_t ip[IPaddrlen];
+       uint8_t mask[IPaddrlen];
+       uint8_t net[IPaddrlen];         /* ip & mask */
+       uint32_t        preflt;                 /* preferred lifetime */
+       uint32_t        validlt;                /* valid lifetime */
+};
+
+/* default values, one per stack */
+struct ipv6rp
+{
+       int     mflag;
+       int     oflag;
+       int     maxraint;
+       int     minraint;
+       int     linkmtu;
+       int     reachtime;
+       int     rxmitra;
+       int     ttl;
+       int     routerlt;       
+};
+
+/* actual interface */
+struct ipifc
+{
+       struct ipifc    *next;
+       struct iplifc   *lifc;
+
+       /* per ip interface */
+       int     index;                  /* number of interface in ipifc dir */
+       char    dev[64];
+       uint8_t sendra6;                /* on == send router adv */
+       uint8_t recvra6;                /* on == rcv router adv */
+       int     mtu;
+       uint32_t        pktin;
+       uint32_t        pktout;
+       uint32_t        errin;
+       uint32_t        errout;
+       struct ipv6rp   rp;
+};
+
+#define ISIPV6MCAST(addr)      ((addr)[0] == 0xff)
+#define ISIPV6LINKLOCAL(addr) ((addr)[0] == 0xfe && ((addr)[1] & 0xc0) == 0x80)
+
+/*
+ * ipv6 constants
+ * `ra' is `router advertisement', `rs' is `router solicitation'.
+ * `na' is `neighbour advertisement'.
+ */
+enum {
+       IPV6HDR_LEN     = 40,
+
+       /* neighbour discovery option types */
+       V6nd_srclladdr  = 1,
+       V6nd_targlladdr = 2,
+       V6nd_pfxinfo    = 3,
+       V6nd_redirhdr   = 4,
+       V6nd_mtu        = 5,
+       /* new since rfc2461; see iana.org/assignments/icmpv6-parameters */
+       V6nd_home       = 8,
+       V6nd_srcaddrs   = 9,            /* rfc3122 */
+       V6nd_ip         = 17,
+       /* /lib/rfc/drafts/draft-jeong-dnsop-ipv6-dns-discovery-12.txt */
+       V6nd_rdns       = 25,
+       /* plan 9 extensions */
+       V6nd_9fs        = 250,
+       V6nd_9auth      = 251,
+
+       /* Router constants (all times in ms.) */
+       Maxv6initraintvl= 16000,
+       Maxv6initras    = 3,
+       Maxv6finalras   = 3,
+       Minv6interradelay= 3000,
+       Maxv6radelay    = 500,
+
+       /* Host constants */
+       Maxv6rsdelay    = 1000,
+       V6rsintvl       = 4000,
+       Maxv6rss        = 3,
+
+       /* Node constants */
+       Maxv6mcastrss   = 3,
+       Maxv6unicastrss = 3,
+       Maxv6anycastdelay= 1000,
+       Maxv6na         = 3,
+       V6reachabletime = 30000,
+       V6retranstimer  = 1000,
+       V6initprobedelay= 5000,
+};
+
+# if 0
+/* in icmp.h? */
+struct ip4hdr
+{
+       uint8_t vihl;           /* Version and header length */
+       uint8_t tos;            /* Type of service */
+       uint8_t length[2];      /* packet length */
+       uint8_t id[2];          /* ip->identification */
+       uint8_t frag[2];        /* Fragment information */
+       uint8_t ttl;            /* Time to live */
+       uint8_t proto;          /* Protocol */
+       uint8_t cksum[2];       /* Header checksum */
+       uint8_t src[4];         /* IP source */
+       uint8_t dst[4];         /* IP destination */
+};
+#endif
+
+/* V6 header on the wire */
+
+struct ip6hdr {
+       uint8_t vcf[4];         /* version:4, traffic class:8, flow label:20 */
+       uint8_t ploadlen[2];    /* payload length: packet length - 40 */
+       uint8_t proto;          /* next header type */
+       uint8_t ttl;            /* hop limit */
+       uint8_t src[IPaddrlen]; /* source address */
+       uint8_t dst[IPaddrlen]; /* destination address */
+       uint8_t payload[];
+};
+
+/*
+ *  user-level icmpv6 with control message "headers"
+ */
+
+struct icmp6hdr {
+       uint8_t _0_[8];
+       uint8_t laddr[IPaddrlen];       /* local address */
+       uint8_t raddr[IPaddrlen];       /* remote address */
+};
+
+/*
+ *  user level udp headers with control message "headers"
+ */
+enum 
+{
+       Udphdrsize=     52,     /* size of a Udphdr */
+};
+
+struct udphdr
+{
+       uint8_t raddr[IPaddrlen];       /* V6 remote address */
+       uint8_t laddr[IPaddrlen];       /* V6 local address */
+       uint8_t ifcaddr[IPaddrlen];     /* V6 ifc addr msg was received on */
+       uint8_t rport[2];               /* remote port */
+       uint8_t lport[2];               /* local port */
+};
+
+uint8_t*       defmask(uint8_t*);
+void   maskip(uint8_t*, uint8_t*, uint8_t*);
+//int  eipfmt(Fmt*);
+int    isv4(uint8_t*);
+int64_t        parseip(uint8_t*, char*);
+int64_t        parseipmask(uint8_t*, char*);
+char*  v4parseip(uint8_t*, char*);
+char*  v4parsecidr(uint8_t*, uint8_t*, char*);
+int    parseether(uint8_t*, char*);
+int    myipaddr(uint8_t*, char*);
+int    myetheraddr(uint8_t*, char*);
+int    equivip4(uint8_t*, uint8_t*);
+int    equivip6(uint8_t*, uint8_t*);
+
+struct ipifc*  readipifc(char*, struct ipifc*, int);
+
+void   hnputv(void*, uint64_t);
+void   hnputl(void*, unsigned int);
+void   hnputs(void*, uint16_t);
+uint64_t       nhgetv(void*);
+unsigned int   nhgetl(void*);
+uint16_t       nhgets(void*);
+uint16_t       ptclbsum(uint8_t*, int);
+
+int    v6tov4(uint8_t*, uint8_t*);
+void   v4tov6(uint8_t*, uint8_t*);
+
+#define        ipcmp(x, y) memcmp(x, y, IPaddrlen)
+#define        ipmove(x, y) memmove(x, y, IPaddrlen)
+
+extern uint8_t IPv4bcast[IPaddrlen];
+extern uint8_t IPv4bcastobs[IPaddrlen];
+extern uint8_t IPv4allsys[IPaddrlen];
+extern uint8_t IPv4allrouter[IPaddrlen];
+extern uint8_t IPnoaddr[IPaddrlen];
+extern uint8_t v4prefix[IPaddrlen];
+extern uint8_t IPallbits[IPaddrlen];
+
+#define CLASS(p) ((*(uint8_t*)(p))>>6)
+
+int tokenize(char *s, char **args, int maxargs);
+int getfields(char *str, char **args, int max, int mflag, char *unused_set);
+char *netmkaddr(char *linear, char *defnet, char *defsrv);
+int dial9(char *dest, char *local, char *dir, int *cfdp, int flags);
+int announce9(char *addr, char *dir, int flags);
+int listen9(char *dir, char *newdir, int flags);
+int accept9(int ctl, char *dir);
+int reject9(int ctl, char *dir, char *cause);
+
+__END_DECLS
diff --git a/user/ndblib/include/fcallfmt.h b/user/ndblib/include/fcallfmt.h
deleted file mode 100644 (file)
index 8cd6f45..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-#include <parlib/printf-ext.h>
-#include <fcall.h>
-
-__BEGIN_DECLS
-
-int printf_fcall(FILE *stream, const struct printf_info *info,
-                 const void *const *args);
-int printf_fcall_info(const struct printf_info* info, size_t n, int *argtypes,
-                      int *size);
-int printf_dir(FILE *stream, const struct printf_info *info,
-               const void *const *args);
-int printf_dir_info(const struct printf_info* info, size_t n, int *argtypes,
-                    int *size);
-
-int read9pmsg(int, void *, unsigned int);
-
-__END_DECLS
diff --git a/user/ndblib/include/ndb.h b/user/ndblib/include/ndb.h
deleted file mode 100644 (file)
index ae44376..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* 
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-#pragma once
-
-#include <fcall.h>
-
-__BEGIN_DECLS
-
-enum
-{
-       Ndbalen=        32,     /* max attribute length */
-       Ndbvlen=        64,     /* max value length */
-};
-
-struct ndbcache;
-/*
- *  the database
- */
-struct ndb
-{
-       struct ndb              *next;
-
-       FILE    *b;             /* buffered input file */
-       uint8_t         buf[256];       /* and its buffer */
-
-       uint32_t                mtime;          /* mtime of db file */
-       struct qid              qid;            /* qid of db file */
-       char            file[128];/* path name of db file */
-       uint32_t                length;         /* length of db file */
-       int             isopen; /* true if the file is open */
-
-       int             nohash;         /* don't look for hash files */
-       struct ndbhf            *hf;            /* open hash files */
-
-       int             ncache;         /* size of tuple cache */
-       struct ndbcache *cache;         /* cached entries */
-};
-
-/*
- *  a parsed entry, doubly linked
- */
-struct ndbtuple
-{
-       char            attr[Ndbalen];          /* attribute name */
-       char            *val;                   /* value(s) */
-       struct ndbtuple *entry;                 /* next tuple in this entry */
-       struct ndbtuple *line;                  /* next tuple on this line */
-       uint32_t                ptr;                    /* (for the application - starts 0) */
-       char            valbuf[Ndbvlen];        /* initial allocation for value */
-};
-
-/*
- *  each hash file is of the form
- *
- *             +---------------------------------------+
- *             |       mtime of db file (4 bytes)      |
- *             +---------------------------------------+
- *             |  size of table (in entries - 4 bytes) |
- *             +---------------------------------------+
- *             |               hash table              |
- *             +---------------------------------------+
- *             |               hash chains             |
- *             +---------------------------------------+
- *
- *  hash collisions are resolved using chained entries added to the
- *  the end of the hash table.
- *
- *  Hash entries are of the form
- *
- *             +-------------------------------+
- *             |       offset  (3 bytes)       |
- *             +-------------------------------+
- *
- *  Chain entries are of the form
- *
- *             +-------------------------------+
- *             |       offset1 (3 bytes)       |
- *             +-------------------------------+
- *             |       offset2 (3 bytes)       |
- *             +-------------------------------+
- *
- *  The top bit of an offset set to 1 indicates a pointer to a hash chain entry.
- */
-#define NDBULLEN       4               /* unsigned long length in bytes */
-#define NDBPLEN                3               /* pointer length in bytes */
-#define NDBHLEN                (2*NDBULLEN)    /* hash file header length in bytes */
-
-/*
- *  finger pointing to current point in a search
- */
-struct ndbs
-{
-       struct ndb      *db;    /* data base file being searched */
-       struct ndbhf    *hf;    /* hash file being searched */
-       int     type;
-       uint32_t        ptr;    /* current pointer */
-       uint32_t        ptr1;   /* next pointer */
-       struct ndbtuple *t;     /* last attribute value pair found */
-};
-
-struct ndbcache
-{
-       struct ndbcache *next;
-       char            *attr;
-       char            *val;
-       struct ndbs             s;
-       struct ndbtuple *t;
-};
-
-/*
- *  bit defs for pointers in hash files
- */
-#define NDBSPEC        (1<<23)
-#define NDBCHAIN       NDBSPEC         /* points to a collision chain */
-#define NDBNAP         (NDBSPEC|1)     /* not a pointer */
-
-/*
- *  macros for packing and unpacking pointers
- */
-#define NDBPUTP(v,a) { (a)[0] = v; (a)[1] = (v)>>8; (a)[2] = (v)>>16; }
-#define NDBGETP(a) ((a)[0] | ((a)[1]<<8) | ((a)[2]<<16))
-
-/*
- *  macros for packing and unpacking unsigned longs
- */
-#define NDBPUTUL(v,a) { (a)[0] = v; (a)[1] = (v)>>8; (a)[2] = (v)>>16; (a)[3] = (v)>>24; }
-#define NDBGETUL(a) ((a)[0] | ((a)[1]<<8) | ((a)[2]<<16) | ((a)[3]<<24))
-
-#define NDB_IPlen 16
-
-struct ndbtuple*       csgetval(char*, char*, char*, char*, char*);
-char*          csgetvalue(char*, char*, char*, char*, struct ndbtuple**);
-struct ndbtuple*       csipinfo(char*, char*, char*, char**, int);
-struct ndbtuple*       dnsquery(char*, char*, char*);
-char*          ipattr(char*);
-struct ndb*            ndbcat(struct ndb*, struct ndb*);
-int            ndbchanged(struct ndb*);
-void           ndbclose(struct ndb*);
-struct ndbtuple*       ndbconcatenate(struct ndbtuple*, struct ndbtuple*);
-struct ndbtuple*       ndbdiscard(struct ndbtuple*, struct ndbtuple*);
-void           ndbfree(struct ndbtuple*);
-struct ndbtuple*       ndbgetipaddr(struct ndb*, char*);
-struct ndbtuple*       ndbgetval(struct ndb*,
-                                 struct ndbs*, char*, char*, char*, char*);
-char*          ndbgetvalue(struct ndb*, struct ndbs*, char*, char*, char*,
-                                struct ndbtuple**);
-struct ndbtuple*       ndbfindattr(struct ndbtuple*, struct ndbtuple*, char*);
-uint32_t               ndbhash(char*, int);
-struct ndbtuple*       ndbipinfo(struct ndb*, char*, char*, char**, int);
-struct ndbtuple*       ndblookval(struct ndbtuple*,
-                                  struct ndbtuple*, char*, char*);
-struct ndbtuple*       ndbnew(char*, char*);
-struct ndb*            ndbopen(char*);
-struct ndbtuple*       ndbparse(struct ndb*);
-int            ndbreopen(struct ndb*);
-struct ndbtuple*       ndbreorder(struct ndbtuple*, struct ndbtuple*);
-struct ndbtuple*       ndbsearch(struct ndb*, struct ndbs*, char*, char*);
-void           ndbsetval(struct ndbtuple*, char*, int);
-struct ndbtuple*       ndbsnext(struct ndbs*, char*, char*);
-struct ndbtuple*       ndbsubstitute(struct ndbtuple*, struct ndbtuple*,
-                                     struct ndbtuple*);
-char*_ndbparsetuple(char *cp, struct ndbtuple **tp);
-struct ndbtuple*_ndbparseline(char *cp);
-//void         ndbsetmalloctag(struct ndbtuple*, uintptr_t);
-static inline void             ndbsetmalloctag(struct ndbtuple*t, uintptr_t v){}
-
-static inline uintptr_t getcallerpc(void *v){return 0;}
-static inline void setmalloctag(void *v){}
-
-void _ndbcacheflush(struct ndb *db);
-/* No implementation for this, dumped into a garbage file */
-void setnetmtpt(char *net, int n, char *x);
-
-__END_DECLS
diff --git a/user/ndblib/include/ndbhf.h b/user/ndblib/include/ndbhf.h
deleted file mode 100644 (file)
index ee56cad..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-/* a hash file */
-
-#pragma once
-
-__BEGIN_DECLS
-
-struct ndbhf
-{
-       struct ndbhf    *next;
-
-       int     fd;
-       uint32_t        dbmtime;        /* mtime of data base */
-       int     hlen;           /* length (in entries) of hash table */
-       char    attr[Ndbalen];  /* attribute hashed */
-
-       uint8_t buf[256];       /* hash file buffer */
-       long    off;            /* offset of first byte of buffer */
-       int     len;            /* length of valid data in buffer */
-};
-
-char*          _ndbparsetuple(char*, struct ndbtuple**);
-struct ndbtuple*       _ndbparseline(char*);
-
-#define ISWHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\r')
-#define EATWHITE(x) while(ISWHITE(*(x)))(x)++
-
-extern struct ndbtuple *_ndbtfree;
-
-/* caches */
-void   _ndbcacheflush(struct ndb *db);
-int    _ndbcachesearch(struct ndb *db, struct ndbs *s, char *attr, char *val,
-                          struct ndbtuple **t);
-struct ndbtuple* _ndbcacheadd(struct ndb *db, struct ndbs *s, char *attr, char *val,
-                             struct ndbtuple *t);
-
-__END_DECLS
diff --git a/user/ndblib/include/ndblib b/user/ndblib/include/ndblib
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
diff --git a/user/ndblib/include/ndblib/fcallfmt.h b/user/ndblib/include/ndblib/fcallfmt.h
new file mode 100644 (file)
index 0000000..8cd6f45
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <parlib/printf-ext.h>
+#include <fcall.h>
+
+__BEGIN_DECLS
+
+int printf_fcall(FILE *stream, const struct printf_info *info,
+                 const void *const *args);
+int printf_fcall_info(const struct printf_info* info, size_t n, int *argtypes,
+                      int *size);
+int printf_dir(FILE *stream, const struct printf_info *info,
+               const void *const *args);
+int printf_dir_info(const struct printf_info* info, size_t n, int *argtypes,
+                    int *size);
+
+int read9pmsg(int, void *, unsigned int);
+
+__END_DECLS
diff --git a/user/ndblib/include/ndblib/ndb.h b/user/ndblib/include/ndblib/ndb.h
new file mode 100644 (file)
index 0000000..ae44376
--- /dev/null
@@ -0,0 +1,180 @@
+/* 
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+#pragma once
+
+#include <fcall.h>
+
+__BEGIN_DECLS
+
+enum
+{
+       Ndbalen=        32,     /* max attribute length */
+       Ndbvlen=        64,     /* max value length */
+};
+
+struct ndbcache;
+/*
+ *  the database
+ */
+struct ndb
+{
+       struct ndb              *next;
+
+       FILE    *b;             /* buffered input file */
+       uint8_t         buf[256];       /* and its buffer */
+
+       uint32_t                mtime;          /* mtime of db file */
+       struct qid              qid;            /* qid of db file */
+       char            file[128];/* path name of db file */
+       uint32_t                length;         /* length of db file */
+       int             isopen; /* true if the file is open */
+
+       int             nohash;         /* don't look for hash files */
+       struct ndbhf            *hf;            /* open hash files */
+
+       int             ncache;         /* size of tuple cache */
+       struct ndbcache *cache;         /* cached entries */
+};
+
+/*
+ *  a parsed entry, doubly linked
+ */
+struct ndbtuple
+{
+       char            attr[Ndbalen];          /* attribute name */
+       char            *val;                   /* value(s) */
+       struct ndbtuple *entry;                 /* next tuple in this entry */
+       struct ndbtuple *line;                  /* next tuple on this line */
+       uint32_t                ptr;                    /* (for the application - starts 0) */
+       char            valbuf[Ndbvlen];        /* initial allocation for value */
+};
+
+/*
+ *  each hash file is of the form
+ *
+ *             +---------------------------------------+
+ *             |       mtime of db file (4 bytes)      |
+ *             +---------------------------------------+
+ *             |  size of table (in entries - 4 bytes) |
+ *             +---------------------------------------+
+ *             |               hash table              |
+ *             +---------------------------------------+
+ *             |               hash chains             |
+ *             +---------------------------------------+
+ *
+ *  hash collisions are resolved using chained entries added to the
+ *  the end of the hash table.
+ *
+ *  Hash entries are of the form
+ *
+ *             +-------------------------------+
+ *             |       offset  (3 bytes)       |
+ *             +-------------------------------+
+ *
+ *  Chain entries are of the form
+ *
+ *             +-------------------------------+
+ *             |       offset1 (3 bytes)       |
+ *             +-------------------------------+
+ *             |       offset2 (3 bytes)       |
+ *             +-------------------------------+
+ *
+ *  The top bit of an offset set to 1 indicates a pointer to a hash chain entry.
+ */
+#define NDBULLEN       4               /* unsigned long length in bytes */
+#define NDBPLEN                3               /* pointer length in bytes */
+#define NDBHLEN                (2*NDBULLEN)    /* hash file header length in bytes */
+
+/*
+ *  finger pointing to current point in a search
+ */
+struct ndbs
+{
+       struct ndb      *db;    /* data base file being searched */
+       struct ndbhf    *hf;    /* hash file being searched */
+       int     type;
+       uint32_t        ptr;    /* current pointer */
+       uint32_t        ptr1;   /* next pointer */
+       struct ndbtuple *t;     /* last attribute value pair found */
+};
+
+struct ndbcache
+{
+       struct ndbcache *next;
+       char            *attr;
+       char            *val;
+       struct ndbs             s;
+       struct ndbtuple *t;
+};
+
+/*
+ *  bit defs for pointers in hash files
+ */
+#define NDBSPEC        (1<<23)
+#define NDBCHAIN       NDBSPEC         /* points to a collision chain */
+#define NDBNAP         (NDBSPEC|1)     /* not a pointer */
+
+/*
+ *  macros for packing and unpacking pointers
+ */
+#define NDBPUTP(v,a) { (a)[0] = v; (a)[1] = (v)>>8; (a)[2] = (v)>>16; }
+#define NDBGETP(a) ((a)[0] | ((a)[1]<<8) | ((a)[2]<<16))
+
+/*
+ *  macros for packing and unpacking unsigned longs
+ */
+#define NDBPUTUL(v,a) { (a)[0] = v; (a)[1] = (v)>>8; (a)[2] = (v)>>16; (a)[3] = (v)>>24; }
+#define NDBGETUL(a) ((a)[0] | ((a)[1]<<8) | ((a)[2]<<16) | ((a)[3]<<24))
+
+#define NDB_IPlen 16
+
+struct ndbtuple*       csgetval(char*, char*, char*, char*, char*);
+char*          csgetvalue(char*, char*, char*, char*, struct ndbtuple**);
+struct ndbtuple*       csipinfo(char*, char*, char*, char**, int);
+struct ndbtuple*       dnsquery(char*, char*, char*);
+char*          ipattr(char*);
+struct ndb*            ndbcat(struct ndb*, struct ndb*);
+int            ndbchanged(struct ndb*);
+void           ndbclose(struct ndb*);
+struct ndbtuple*       ndbconcatenate(struct ndbtuple*, struct ndbtuple*);
+struct ndbtuple*       ndbdiscard(struct ndbtuple*, struct ndbtuple*);
+void           ndbfree(struct ndbtuple*);
+struct ndbtuple*       ndbgetipaddr(struct ndb*, char*);
+struct ndbtuple*       ndbgetval(struct ndb*,
+                                 struct ndbs*, char*, char*, char*, char*);
+char*          ndbgetvalue(struct ndb*, struct ndbs*, char*, char*, char*,
+                                struct ndbtuple**);
+struct ndbtuple*       ndbfindattr(struct ndbtuple*, struct ndbtuple*, char*);
+uint32_t               ndbhash(char*, int);
+struct ndbtuple*       ndbipinfo(struct ndb*, char*, char*, char**, int);
+struct ndbtuple*       ndblookval(struct ndbtuple*,
+                                  struct ndbtuple*, char*, char*);
+struct ndbtuple*       ndbnew(char*, char*);
+struct ndb*            ndbopen(char*);
+struct ndbtuple*       ndbparse(struct ndb*);
+int            ndbreopen(struct ndb*);
+struct ndbtuple*       ndbreorder(struct ndbtuple*, struct ndbtuple*);
+struct ndbtuple*       ndbsearch(struct ndb*, struct ndbs*, char*, char*);
+void           ndbsetval(struct ndbtuple*, char*, int);
+struct ndbtuple*       ndbsnext(struct ndbs*, char*, char*);
+struct ndbtuple*       ndbsubstitute(struct ndbtuple*, struct ndbtuple*,
+                                     struct ndbtuple*);
+char*_ndbparsetuple(char *cp, struct ndbtuple **tp);
+struct ndbtuple*_ndbparseline(char *cp);
+//void         ndbsetmalloctag(struct ndbtuple*, uintptr_t);
+static inline void             ndbsetmalloctag(struct ndbtuple*t, uintptr_t v){}
+
+static inline uintptr_t getcallerpc(void *v){return 0;}
+static inline void setmalloctag(void *v){}
+
+void _ndbcacheflush(struct ndb *db);
+/* No implementation for this, dumped into a garbage file */
+void setnetmtpt(char *net, int n, char *x);
+
+__END_DECLS
diff --git a/user/ndblib/include/ndblib/ndbhf.h b/user/ndblib/include/ndblib/ndbhf.h
new file mode 100644 (file)
index 0000000..ee56cad
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+/* a hash file */
+
+#pragma once
+
+__BEGIN_DECLS
+
+struct ndbhf
+{
+       struct ndbhf    *next;
+
+       int     fd;
+       uint32_t        dbmtime;        /* mtime of data base */
+       int     hlen;           /* length (in entries) of hash table */
+       char    attr[Ndbalen];  /* attribute hashed */
+
+       uint8_t buf[256];       /* hash file buffer */
+       long    off;            /* offset of first byte of buffer */
+       int     len;            /* length of valid data in buffer */
+};
+
+char*          _ndbparsetuple(char*, struct ndbtuple**);
+struct ndbtuple*       _ndbparseline(char*);
+
+#define ISWHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\r')
+#define EATWHITE(x) while(ISWHITE(*(x)))(x)++
+
+extern struct ndbtuple *_ndbtfree;
+
+/* caches */
+void   _ndbcacheflush(struct ndb *db);
+int    _ndbcachesearch(struct ndb *db, struct ndbs *s, char *attr, char *val,
+                          struct ndbtuple **t);
+struct ndbtuple* _ndbcacheadd(struct ndb *db, struct ndbs *s, char *attr, char *val,
+                             struct ndbtuple *t);
+
+__END_DECLS
index 9f3d175..03cd8d1 100755 (executable)
@@ -17,7 +17,7 @@
 #include <fcntl.h>
 #include <iplib/iplib.h>
 #include <ndblib/ndb.h>
-#include "ndbhf.h"
+#include <ndblib/ndbhf.h>
 
 static struct ndb*     doopen(char*);
 static void    hffree(struct ndb*);
diff --git a/user/parlib/include/arc.h b/user/parlib/include/arc.h
deleted file mode 100644 (file)
index cff6545..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// Header for Asynch Remote Call, currently only support remote syscalls.
-#pragma once
-
-#include <parlib/parlib.h>
-#include <error.h>
-#include <parlib/pool.h>
-#include <parlib/assert.h>
-#include <sys/queue.h>
-#include <ros/syscall.h>
-#include <ros/ring_syscall.h>
-#include <parlib/mcs.h>
-
-__BEGIN_DECLS
-
-struct arsc_channel {
-       mcs_lock_t aclock;
-       syscall_sring_t* ring_page;
-       syscall_front_ring_t sysfr;
-}; 
-
-typedef struct arsc_channel arsc_channel_t;
-
-#define SYS_CHANNEL (global_ac)
-extern arsc_channel_t global_ac;
-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;
-       struct arsc_channel* channel;
-       uint32_t idx;
-};
-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(struct arsc_channel* ac);
-
-int async_syscall(arsc_channel_t* chan, syscall_req_t* req, syscall_desc_t** desc_ptr2);
-
-/* Generic Async Call */
-int waiton_syscall(syscall_desc_t* desc);
-
-/* Async group call */
-// not sure how to get results back for these?
-
-int waiton_group_call(async_desc_t* desc, async_rsp_t* rsp);
-
-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);
-
-// helper function to make arc calls
-
-syscall_desc_t* arc_call(long int num, ...);
-
-__END_DECLS
diff --git a/user/parlib/include/assert.h b/user/parlib/include/assert.h
deleted file mode 100644 (file)
index 1347846..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* See COPYRIGHT for copyright information. */
-
-#pragma once
-
-#ifdef BUILDING_PARLIB
-# include_next "assert.h"
-#else
-# include <assert.h>
-#endif
-/* For __BEGIN_DECLS.  Most every header gets it already from features.h. */
-#include <sys/cdefs.h>
-/* So we can undefine warn */
-#include <err.h>
-
-__BEGIN_DECLS
-
-#undef assert
-#undef warn
-
-void _warn(const char*, int, const char*, ...);
-void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
-void _assert_failed(const char *file, int line, const char *msg)
-     __attribute__((noreturn));
-
-#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
-#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
-
-#define assert(x)                                                                 \
-       do {                                                                       \
-               if (!(x))                                                              \
-                       _assert_failed(__FILE__, __LINE__, #x);                            \
-       } while (0)
-
-// parlib_static_assert(x) will generate a compile-time error if 'x' is false.
-#define parlib_static_assert(x)        switch (x) case 0: case (x):
-
-__END_DECLS
diff --git a/user/parlib/include/bitmask.h b/user/parlib/include/bitmask.h
deleted file mode 100644 (file)
index d883ced..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#pragma once
-
-#include <parlib/arch/bitmask.h>
-
-__BEGIN_DECLS
-
-static inline bool BITMASK_IS_SET_IN_RANGE(uint8_t* m, size_t beg, size_t end)
-{
-       for(size_t i=beg; i<end; i++) {
-               if(!GET_BITMASK_BIT(m, i))
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-static inline bool BITMASK_IS_CLR_IN_RANGE(uint8_t* m, size_t beg, size_t end)
-{
-       for(size_t i=beg; i<end; i++) {
-               if(GET_BITMASK_BIT(m, i))
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-static inline void SET_BITMASK_RANGE(uint8_t* m, size_t beg, size_t end)
-{
-       for(size_t i=beg; i<end; i++) {
-               SET_BITMASK_BIT(m, i);
-       }
-}
-
-static inline void CLR_BITMASK_RANGE(uint8_t* m, size_t beg, size_t end)
-{
-       for(size_t i=beg; i<end; i++) {
-               CLR_BITMASK_BIT(m, i);
-       }
-}
-
-/* Runs *work on every bit in the bitmask, passing *work the value of the bit
- * that is set.  Optionally clears the bit from the bitmask. 
- *
- * We need this to be a macro, so that the calling code doesn't need the
- * address for work_fn.  This matters for code that has nested functions that
- * use local variables, since taking the address of work_fn will force the
- * compiler to put the function on the stack and incur icache coherency
- * overheads. */
-#define BITMASK_FOREACH_SET(name, size, work_fn, clear)                        \
-{                                                                              \
-       for (int i = 0; i < (size); i++) {                                         \
-               bool present = GET_BITMASK_BIT((name), i);                             \
-               if (present && (clear))                                                \
-                       CLR_BITMASK_BIT_ATOMIC((name), i);                                 \
-               if (present)                                                           \
-                       (work_fn)(i);                                                      \
-       }                                                                          \
-}                                                                              
-                                                                               
-__END_DECLS
diff --git a/user/parlib/include/ceq.h b/user/parlib/include/ceq.h
deleted file mode 100644 (file)
index 0789181..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2015 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Coalescing Event Queue: encapuslates the essence of epoll/kqueue in shared
- * memory: a dense array of sticky status bits.
- *
- * User side (consumer).
- *
- * When initializing, the nr_events is the maximum count of events you are
- * tracking, e.g. 100 FDs being tapped, but not the actual FD numbers.
- *
- * The ring_sz is a rough guess of the number of concurrent events.  It's not a
- * big deal what you pick, but it must be a power of 2.  Otherwise the kernel
- * will probably scribble over your memory.  If you pick a value that is too
- * small, then the ring may overflow, triggering an O(n) scan of the events
- * array.  You could make it == nr_events, for reasonable behavior at the
- * expense of memory. */
-
-#pragma once
-
-#include <ros/ceq.h>
-#include <ros/event.h>
-
-__BEGIN_DECLS
-
-/* If you get a non-raw event queue (with mbox, initialized by event code), then
- * you'll get a CEQ with 128 events and 128 ring slots with the OR operation.
- * It's actually doable to have the user grow the CEQ, but we don't have support
- * for that yet, so just pick a size in advance.  If you're using a CEQ, you'll
- * probably want to do it yourself. */
-#define CEQ_DEFAULT_SZ 128
-
-void ceq_init(struct ceq *ceq, uint8_t op, size_t nr_events, size_t ring_sz);
-bool get_ceq_msg(struct ceq *ceq, struct event_msg *msg);
-bool ceq_is_empty(struct ceq *ceq);
-void ceq_cleanup(struct ceq *ceq);
-
-__END_DECLS
diff --git a/user/parlib/include/common.h b/user/parlib/include/common.h
deleted file mode 100644 (file)
index b812130..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright (c) 2015 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Common helpers for Akaros user programs. */
-
-#pragma once
-
-#include <ros/common.h>
-#include <parlib/assert.h>
-#include <parlib/stdio.h>
-
-#define IS_PWR2(x) ((x) && !((x) & (x - 1)))
diff --git a/user/parlib/include/dtls.h b/user/parlib/include/dtls.h
deleted file mode 100644 (file)
index 3ad1c11..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2012 The Regents of the University of California
- * Kevin Klues <klueska@cs.berkeley.edu>
- *
- * This file is part of Parlib.
- * 
- * Parlib is free software: you can redistribute it and/or modify
- * it under the terms of the Lesser GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * Parlib is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * Lesser GNU General Public License for more details.
- * 
- * See COPYING.LESSER for details on the GNU Lesser General Public License.
- * See COPYING for details on the GNU General Public License.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <stdlib.h>
-
-__BEGIN_DECLS
-
-#ifndef __GNUC__
-  #error "You need to be using gcc to compile this library..."
-#endif 
-
-/* Declaration of types needed for dynamically allocatable tls */
-typedef struct dtls_key *dtls_key_t;
-typedef void (*dtls_dtor_t)(void*);
-
-/* Initialize a dtls_key for dynamically setting/getting uthread local storage
- * on a uthread or vcore. */
-dtls_key_t dtls_key_create(dtls_dtor_t dtor);
-
-/* Destroy a dtls key. */
-void dtls_key_delete(dtls_key_t key);
-
-/* Set dtls storage for the provided dtls key on the current uthread or vcore. */
-void set_dtls(dtls_key_t key, void *dtls);
-
-/* Get dtls storage for the provided dtls key on the current uthread or vcore. */
-void *get_dtls(dtls_key_t key);
-
-/* Destroy all dtls storage associated with the current uthread or vcore. */
-void destroy_dtls();
-
-__END_DECLS
diff --git a/user/parlib/include/evbitmap.h b/user/parlib/include/evbitmap.h
deleted file mode 100644 (file)
index d536666..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright (c) 2015 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Event bitmaps.  These are a type of event mailbox where the message type is
- * translated to a bit, which is set in the bitmap. */
-
-#pragma once
-
-#include <ros/evbitmap.h>
-
-__BEGIN_DECLS
-
-void evbitmap_init(struct evbitmap *evbm);
-void evbitmap_cleanup(struct evbitmap *evbm);
-bool evbitmap_is_empty(struct evbitmap *evbm);
-void evbitmap_init(struct evbitmap *evbm);
-bool get_evbitmap_msg(struct evbitmap *evbm, struct event_msg *ev_msg);
-
-__END_DECLS
diff --git a/user/parlib/include/event.h b/user/parlib/include/event.h
deleted file mode 100644 (file)
index aedb35f..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Copyright (c) 2011-2014 The Regents of the University of California
- * Copyright (c) 2015 Google Inc
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Userspace utility functions for receiving events and notifications (IPIs).
- * Some are higher level than others; just use what you need. */ 
-
-#pragma once
-
-#include <ros/event.h>
-#include <ros/syscall.h>
-#include <parlib/common.h>
-
-__BEGIN_DECLS
-
-/********* Event_q Setup / Registration  ***********/
-struct event_queue *get_eventq(int mbox_type);
-struct event_queue *get_eventq_raw(void);
-struct event_queue *get_eventq_slim(void);
-struct event_queue *get_eventq_vcpd(uint32_t vcoreid, int ev_flags);
-void put_eventq(struct event_queue *ev_q);
-void put_eventq_raw(struct event_queue *ev_q);
-void put_eventq_slim(struct event_queue *ev_q);
-void put_eventq_vcpd(struct event_queue *ev_q);
-
-void event_mbox_init(struct event_mbox *ev_mbox, int mbox_type);
-void event_mbox_cleanup(struct event_mbox *ev_mbox);
-
-void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type);
-struct event_queue *clear_kevent_q(unsigned int ev_type);
-void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags);
-struct event_queue *disable_kevent(unsigned int ev_type);
-
-/********* Event Handling / Reception ***********/
-unsigned int get_event_type(struct event_mbox *ev_mbox);
-bool register_evq(struct syscall *sysc, struct event_queue *ev_q);
-void deregister_evq(struct syscall *sysc);
-
-typedef void (*handle_event_t)(struct event_msg *ev_msg, unsigned int ev_type,
-                               void *data);
-struct ev_handler {
-       struct ev_handler                       *next;
-       handle_event_t                          func;
-       void                                            *data;
-};
-int register_ev_handler(unsigned int ev_type, handle_event_t handler,
-                        void *data);
-int deregister_ev_handler(unsigned int ev_type, handle_event_t handler,
-                          void *data);
-
-/* Default event handlers */
-void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type, void *data);
-
-int handle_events(uint32_t vcoreid);
-void handle_event_q(struct event_queue *ev_q);
-bool extract_one_mbox_msg(struct event_mbox *ev_mbox, struct event_msg *ev_msg);
-int handle_one_mbox_msg(struct event_mbox *ev_mbox);
-int handle_mbox(struct event_mbox *ev_mbox);
-bool mbox_is_empty(struct event_mbox *ev_mbox);
-void send_self_vc_msg(struct event_msg *ev_msg);
-void handle_vcpd_mbox(uint32_t rem_vcoreid);
-void try_handle_remote_mbox(void);
-
-/* Event handler helpers */
-bool ev_might_not_return(void);
-void ev_we_returned(bool were_handling_remotes);
-
-/* Debugging */
-void print_ev_msg(struct event_msg *msg);
-
-/* Uthreads blocking on event queues.  M uthreads can block on subsets of N
- * event queues.  The structs and details are buried in event.c.  We can move
- * some of them here if users need greater control over their evqs. */
-void evq_attach_wakeup_ctlr(struct event_queue *ev_q);
-void evq_remove_wakeup_ctlr(struct event_queue *ev_q);
-/* Handler, attaches to the ev_q.  Most people won't need this directly. */
-void evq_wakeup_handler(struct event_queue *ev_q);
-void uth_blockon_evqs_arr(struct event_msg *ev_msg,
-                          struct event_queue **which_evq,
-                          struct event_queue *evqs[], size_t nr_evqs);
-void uth_blockon_evqs(struct event_msg *ev_msg, struct event_queue **which_evq,
-                      size_t nr_evqs, ...);
-bool uth_check_evqs(struct event_msg *ev_msg, struct event_queue **which_evq,
-                    size_t nr_evqs, ...);
-
-__END_DECLS
diff --git a/user/parlib/include/mcs.h b/user/parlib/include/mcs.h
deleted file mode 100644 (file)
index 570c569..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#pragma once
-
-#include <parlib/vcore.h>
-#include <parlib/arch/arch.h>
-
-__BEGIN_DECLS
-
-#define MCS_LOCK_INIT {0}
-#define MCS_QNODE_INIT {0, 0}
-
-typedef struct mcs_lock_qnode
-{
-       struct mcs_lock_qnode *next;
-       int locked;
-}__attribute__((aligned(ARCH_CL_SIZE))) mcs_lock_qnode_t;
-
-typedef struct mcs_lock
-{
-       mcs_lock_qnode_t* lock;
-} 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(struct mcs_lock *lock);
-/* Caller needs to alloc (and zero) their own qnode to spin on.  The memory
- * should be on a cacheline that is 'per-thread'.  This could be on the stack,
- * in a thread control block, etc. */
-void mcs_lock_lock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
-void mcs_lock_unlock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
-void mcs_lock_unlock_cas(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
-/* If you lock the lock from vcore context, you must use these. */
-void mcs_lock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
-void mcs_unlock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
-
-/* Preemption detection and recovering MCS locks.
- *
- * The basic idea is that when spinning, vcores make sure someone else is
- * making progress that will lead to them not spinning.  Usually, it'll be to
- * make sure the lock holder (if known) is running.  If we don't know the lock
- * holder, we ensure the end of whatever chain we can see is running, which
- * will make sure its predecessor runs, which will eventually unjam the system.
- * */
-
-/* Old style.  Has trouble getting out of 'preempt/change-to storms' under
- * heavy contention and with preemption. */
-struct mcs_pdro_qnode
-{
-       struct mcs_pdro_qnode *next;
-       int locked;
-       uint32_t vcoreid;
-}__attribute__((aligned(ARCH_CL_SIZE)));
-
-struct mcs_pdro_lock
-{
-       struct mcs_pdro_qnode *lock;
-};
-
-#define MCSPDRO_LOCK_INIT {0}
-#define MCSPDRO_QNODE_INIT {0, 0, 0}
-
-void mcs_pdro_init(struct mcs_pdro_lock *lock);
-void mcs_pdro_fini(struct mcs_pdro_lock *lock);
-void mcs_pdro_lock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
-void mcs_pdro_unlock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
-
-/* Only call these if you have notifs disabled and know your vcore's qnode.
- * Mostly used for debugging, benchmarks, or critical code. */
-void __mcs_pdro_lock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
-void __mcs_pdro_unlock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
-void __mcs_pdro_unlock_no_cas(struct mcs_pdro_lock *lock,
-                             struct mcs_pdro_qnode *qnode);
-
-/* New style: under heavy contention with preemption, they won't enter the
- * 'preempt/change_to storm' that can happen to PDRs, at the cost of some
- * performance.  This is the default. */
-struct mcs_pdr_qnode
-{
-       struct mcs_pdr_qnode *next;
-       int locked;
-}__attribute__((aligned(ARCH_CL_SIZE)));
-
-struct mcs_pdr_lock
-{
-       struct mcs_pdr_qnode *lock __attribute__((aligned(ARCH_CL_SIZE)));
-       uint32_t lockholder_vcoreid __attribute__((aligned(ARCH_CL_SIZE)));
-       struct mcs_pdr_qnode *qnodes __attribute__((aligned(ARCH_CL_SIZE)));
-};
-
-#define MCSPDR_NO_LOCKHOLDER ((uint32_t)-1)
-
-void mcs_pdr_init(struct mcs_pdr_lock *lock);
-void mcs_pdr_fini(struct mcs_pdr_lock *lock);
-void mcs_pdr_lock(struct mcs_pdr_lock *lock);
-void mcs_pdr_unlock(struct mcs_pdr_lock *lock);
-
-__END_DECLS
diff --git a/user/parlib/include/net.h b/user/parlib/include/net.h
deleted file mode 100644 (file)
index d72b31e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright (c) 2014 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Networking helpers for dealing with the plan 9 interface. */
-
-#pragma once
-
-__BEGIN_DECLS
-
-static inline int snprintf_overflow(int ret, char *buf, size_t buf_len)
-{
-       return (ret == buf_len) && (buf[buf_len - 1] != 0);
-}
-
-int cheap_dial(char *addr, char *local, char *dir, int *cfdp);
-
-__END_DECLS
diff --git a/user/parlib/include/parlib b/user/parlib/include/parlib
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
diff --git a/user/parlib/include/parlib.h b/user/parlib/include/parlib.h
deleted file mode 100644 (file)
index 56c6ab0..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// Main public header file for our user-land support library,
-// whose code lives in the lib directory.
-// This library is roughly our OS's version of a standard C library,
-// and is intended to be linked into all user-mode applications
-// (NOT the kernel or boot loader).
-
-#pragma once
-
-#ifndef __ASSEMBLER__
-
-#include <parlib/common.h>
-#include <ros/memlayout.h>
-#include <ros/syscall.h>
-#include <ros/procinfo.h>
-#include <ros/procdata.h>
-#include <signal.h>
-#include <stdint.h>
-#include <errno.h>
-#include <parlib/ros_debug.h>
-#include <ros/fdtap.h>
-
-__BEGIN_DECLS
-
-enum {
-       PG_RDONLY = 4,
-       PG_RDWR   = 6,
-};
-
-ssize_t     sys_cputs(const uint8_t *s, size_t len);
-uint16_t    sys_cgetc(void);
-int         sys_null(void);
-size_t      sys_getpcoreid(void);
-/* Process Management */
-int         sys_getpid(void);
-int         sys_proc_destroy(int pid, int exitcode);
-void        sys_yield(bool being_nice);
-int         sys_proc_create(const char *path, size_t path_l, char *const argv[],
-                            char *const envp[], int flags);
-int         sys_proc_run(int pid);
-ssize_t     sys_shared_page_alloc(void **addr, pid_t p2, 
-                                  int p1_flags, int p2_flags);
-ssize_t     sys_shared_page_free(void *addr, pid_t p2);
-void        sys_reboot();
-void           *sys_mmap(void *addr, size_t length, int prot, int flags,
-                      int fd, size_t offset);
-int                    sys_provision(int pid, unsigned int res_type, long res_val);
-int         sys_notify(int pid, unsigned int ev_type, struct event_msg *u_msg);
-int         sys_self_notify(uint32_t vcoreid, unsigned int ev_type,
-                            struct event_msg *u_msg, bool priv);
-int         sys_halt_core(unsigned int usec);
-void*          sys_init_arsc();
-int         sys_block(unsigned int usec);
-int         sys_change_vcore(uint32_t vcoreid, bool enable_my_notif);
-int         sys_change_to_m(void);
-int         sys_poke_ksched(int pid, unsigned int res_type);
-int         sys_abort_sysc(struct syscall *sysc);
-int         sys_abort_sysc_fd(int fd);
-int         sys_tap_fds(struct fd_tap_req *tap_reqs, size_t nr_reqs);
-
-void           syscall_async(struct syscall *sysc, unsigned long num, ...);
-
-/* Control variables */
-extern bool parlib_wants_to_be_mcp;    /* instructs the 2LS to be an MCP */
-
-__END_DECLS
-
-#endif // !ASSEMBLER
diff --git a/user/parlib/include/parlib/arc.h b/user/parlib/include/parlib/arc.h
new file mode 100644 (file)
index 0000000..cff6545
--- /dev/null
@@ -0,0 +1,95 @@
+// Header for Asynch Remote Call, currently only support remote syscalls.
+#pragma once
+
+#include <parlib/parlib.h>
+#include <error.h>
+#include <parlib/pool.h>
+#include <parlib/assert.h>
+#include <sys/queue.h>
+#include <ros/syscall.h>
+#include <ros/ring_syscall.h>
+#include <parlib/mcs.h>
+
+__BEGIN_DECLS
+
+struct arsc_channel {
+       mcs_lock_t aclock;
+       syscall_sring_t* ring_page;
+       syscall_front_ring_t sysfr;
+}; 
+
+typedef struct arsc_channel arsc_channel_t;
+
+#define SYS_CHANNEL (global_ac)
+extern arsc_channel_t global_ac;
+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;
+       struct arsc_channel* channel;
+       uint32_t idx;
+};
+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(struct arsc_channel* ac);
+
+int async_syscall(arsc_channel_t* chan, syscall_req_t* req, syscall_desc_t** desc_ptr2);
+
+/* Generic Async Call */
+int waiton_syscall(syscall_desc_t* desc);
+
+/* Async group call */
+// not sure how to get results back for these?
+
+int waiton_group_call(async_desc_t* desc, async_rsp_t* rsp);
+
+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);
+
+// helper function to make arc calls
+
+syscall_desc_t* arc_call(long int num, ...);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/assert.h b/user/parlib/include/parlib/assert.h
new file mode 100644 (file)
index 0000000..1347846
--- /dev/null
@@ -0,0 +1,37 @@
+/* See COPYRIGHT for copyright information. */
+
+#pragma once
+
+#ifdef BUILDING_PARLIB
+# include_next "assert.h"
+#else
+# include <assert.h>
+#endif
+/* For __BEGIN_DECLS.  Most every header gets it already from features.h. */
+#include <sys/cdefs.h>
+/* So we can undefine warn */
+#include <err.h>
+
+__BEGIN_DECLS
+
+#undef assert
+#undef warn
+
+void _warn(const char*, int, const char*, ...);
+void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
+void _assert_failed(const char *file, int line, const char *msg)
+     __attribute__((noreturn));
+
+#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
+
+#define assert(x)                                                                 \
+       do {                                                                       \
+               if (!(x))                                                              \
+                       _assert_failed(__FILE__, __LINE__, #x);                            \
+       } while (0)
+
+// parlib_static_assert(x) will generate a compile-time error if 'x' is false.
+#define parlib_static_assert(x)        switch (x) case 0: case (x):
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/bitmask.h b/user/parlib/include/parlib/bitmask.h
new file mode 100644 (file)
index 0000000..d883ced
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+
+#include <parlib/arch/bitmask.h>
+
+__BEGIN_DECLS
+
+static inline bool BITMASK_IS_SET_IN_RANGE(uint8_t* m, size_t beg, size_t end)
+{
+       for(size_t i=beg; i<end; i++) {
+               if(!GET_BITMASK_BIT(m, i))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static inline bool BITMASK_IS_CLR_IN_RANGE(uint8_t* m, size_t beg, size_t end)
+{
+       for(size_t i=beg; i<end; i++) {
+               if(GET_BITMASK_BIT(m, i))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static inline void SET_BITMASK_RANGE(uint8_t* m, size_t beg, size_t end)
+{
+       for(size_t i=beg; i<end; i++) {
+               SET_BITMASK_BIT(m, i);
+       }
+}
+
+static inline void CLR_BITMASK_RANGE(uint8_t* m, size_t beg, size_t end)
+{
+       for(size_t i=beg; i<end; i++) {
+               CLR_BITMASK_BIT(m, i);
+       }
+}
+
+/* Runs *work on every bit in the bitmask, passing *work the value of the bit
+ * that is set.  Optionally clears the bit from the bitmask. 
+ *
+ * We need this to be a macro, so that the calling code doesn't need the
+ * address for work_fn.  This matters for code that has nested functions that
+ * use local variables, since taking the address of work_fn will force the
+ * compiler to put the function on the stack and incur icache coherency
+ * overheads. */
+#define BITMASK_FOREACH_SET(name, size, work_fn, clear)                        \
+{                                                                              \
+       for (int i = 0; i < (size); i++) {                                         \
+               bool present = GET_BITMASK_BIT((name), i);                             \
+               if (present && (clear))                                                \
+                       CLR_BITMASK_BIT_ATOMIC((name), i);                                 \
+               if (present)                                                           \
+                       (work_fn)(i);                                                      \
+       }                                                                          \
+}                                                                              
+                                                                               
+__END_DECLS
diff --git a/user/parlib/include/parlib/ceq.h b/user/parlib/include/parlib/ceq.h
new file mode 100644 (file)
index 0000000..0789181
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Coalescing Event Queue: encapuslates the essence of epoll/kqueue in shared
+ * memory: a dense array of sticky status bits.
+ *
+ * User side (consumer).
+ *
+ * When initializing, the nr_events is the maximum count of events you are
+ * tracking, e.g. 100 FDs being tapped, but not the actual FD numbers.
+ *
+ * The ring_sz is a rough guess of the number of concurrent events.  It's not a
+ * big deal what you pick, but it must be a power of 2.  Otherwise the kernel
+ * will probably scribble over your memory.  If you pick a value that is too
+ * small, then the ring may overflow, triggering an O(n) scan of the events
+ * array.  You could make it == nr_events, for reasonable behavior at the
+ * expense of memory. */
+
+#pragma once
+
+#include <ros/ceq.h>
+#include <ros/event.h>
+
+__BEGIN_DECLS
+
+/* If you get a non-raw event queue (with mbox, initialized by event code), then
+ * you'll get a CEQ with 128 events and 128 ring slots with the OR operation.
+ * It's actually doable to have the user grow the CEQ, but we don't have support
+ * for that yet, so just pick a size in advance.  If you're using a CEQ, you'll
+ * probably want to do it yourself. */
+#define CEQ_DEFAULT_SZ 128
+
+void ceq_init(struct ceq *ceq, uint8_t op, size_t nr_events, size_t ring_sz);
+bool get_ceq_msg(struct ceq *ceq, struct event_msg *msg);
+bool ceq_is_empty(struct ceq *ceq);
+void ceq_cleanup(struct ceq *ceq);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/common.h b/user/parlib/include/parlib/common.h
new file mode 100644 (file)
index 0000000..b812130
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Common helpers for Akaros user programs. */
+
+#pragma once
+
+#include <ros/common.h>
+#include <parlib/assert.h>
+#include <parlib/stdio.h>
+
+#define IS_PWR2(x) ((x) && !((x) & (x - 1)))
diff --git a/user/parlib/include/parlib/dtls.h b/user/parlib/include/parlib/dtls.h
new file mode 100644 (file)
index 0000000..3ad1c11
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 The Regents of the University of California
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ *
+ * This file is part of Parlib.
+ * 
+ * Parlib is free software: you can redistribute it and/or modify
+ * it under the terms of the Lesser GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * Parlib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * Lesser GNU General Public License for more details.
+ * 
+ * See COPYING.LESSER for details on the GNU Lesser General Public License.
+ * See COPYING for details on the GNU General Public License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+__BEGIN_DECLS
+
+#ifndef __GNUC__
+  #error "You need to be using gcc to compile this library..."
+#endif 
+
+/* Declaration of types needed for dynamically allocatable tls */
+typedef struct dtls_key *dtls_key_t;
+typedef void (*dtls_dtor_t)(void*);
+
+/* Initialize a dtls_key for dynamically setting/getting uthread local storage
+ * on a uthread or vcore. */
+dtls_key_t dtls_key_create(dtls_dtor_t dtor);
+
+/* Destroy a dtls key. */
+void dtls_key_delete(dtls_key_t key);
+
+/* Set dtls storage for the provided dtls key on the current uthread or vcore. */
+void set_dtls(dtls_key_t key, void *dtls);
+
+/* Get dtls storage for the provided dtls key on the current uthread or vcore. */
+void *get_dtls(dtls_key_t key);
+
+/* Destroy all dtls storage associated with the current uthread or vcore. */
+void destroy_dtls();
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/evbitmap.h b/user/parlib/include/parlib/evbitmap.h
new file mode 100644 (file)
index 0000000..d536666
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Event bitmaps.  These are a type of event mailbox where the message type is
+ * translated to a bit, which is set in the bitmap. */
+
+#pragma once
+
+#include <ros/evbitmap.h>
+
+__BEGIN_DECLS
+
+void evbitmap_init(struct evbitmap *evbm);
+void evbitmap_cleanup(struct evbitmap *evbm);
+bool evbitmap_is_empty(struct evbitmap *evbm);
+void evbitmap_init(struct evbitmap *evbm);
+bool get_evbitmap_msg(struct evbitmap *evbm, struct event_msg *ev_msg);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/event.h b/user/parlib/include/parlib/event.h
new file mode 100644 (file)
index 0000000..aedb35f
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 2011-2014 The Regents of the University of California
+ * Copyright (c) 2015 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace utility functions for receiving events and notifications (IPIs).
+ * Some are higher level than others; just use what you need. */ 
+
+#pragma once
+
+#include <ros/event.h>
+#include <ros/syscall.h>
+#include <parlib/common.h>
+
+__BEGIN_DECLS
+
+/********* Event_q Setup / Registration  ***********/
+struct event_queue *get_eventq(int mbox_type);
+struct event_queue *get_eventq_raw(void);
+struct event_queue *get_eventq_slim(void);
+struct event_queue *get_eventq_vcpd(uint32_t vcoreid, int ev_flags);
+void put_eventq(struct event_queue *ev_q);
+void put_eventq_raw(struct event_queue *ev_q);
+void put_eventq_slim(struct event_queue *ev_q);
+void put_eventq_vcpd(struct event_queue *ev_q);
+
+void event_mbox_init(struct event_mbox *ev_mbox, int mbox_type);
+void event_mbox_cleanup(struct event_mbox *ev_mbox);
+
+void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type);
+struct event_queue *clear_kevent_q(unsigned int ev_type);
+void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags);
+struct event_queue *disable_kevent(unsigned int ev_type);
+
+/********* Event Handling / Reception ***********/
+unsigned int get_event_type(struct event_mbox *ev_mbox);
+bool register_evq(struct syscall *sysc, struct event_queue *ev_q);
+void deregister_evq(struct syscall *sysc);
+
+typedef void (*handle_event_t)(struct event_msg *ev_msg, unsigned int ev_type,
+                               void *data);
+struct ev_handler {
+       struct ev_handler                       *next;
+       handle_event_t                          func;
+       void                                            *data;
+};
+int register_ev_handler(unsigned int ev_type, handle_event_t handler,
+                        void *data);
+int deregister_ev_handler(unsigned int ev_type, handle_event_t handler,
+                          void *data);
+
+/* Default event handlers */
+void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type, void *data);
+
+int handle_events(uint32_t vcoreid);
+void handle_event_q(struct event_queue *ev_q);
+bool extract_one_mbox_msg(struct event_mbox *ev_mbox, struct event_msg *ev_msg);
+int handle_one_mbox_msg(struct event_mbox *ev_mbox);
+int handle_mbox(struct event_mbox *ev_mbox);
+bool mbox_is_empty(struct event_mbox *ev_mbox);
+void send_self_vc_msg(struct event_msg *ev_msg);
+void handle_vcpd_mbox(uint32_t rem_vcoreid);
+void try_handle_remote_mbox(void);
+
+/* Event handler helpers */
+bool ev_might_not_return(void);
+void ev_we_returned(bool were_handling_remotes);
+
+/* Debugging */
+void print_ev_msg(struct event_msg *msg);
+
+/* Uthreads blocking on event queues.  M uthreads can block on subsets of N
+ * event queues.  The structs and details are buried in event.c.  We can move
+ * some of them here if users need greater control over their evqs. */
+void evq_attach_wakeup_ctlr(struct event_queue *ev_q);
+void evq_remove_wakeup_ctlr(struct event_queue *ev_q);
+/* Handler, attaches to the ev_q.  Most people won't need this directly. */
+void evq_wakeup_handler(struct event_queue *ev_q);
+void uth_blockon_evqs_arr(struct event_msg *ev_msg,
+                          struct event_queue **which_evq,
+                          struct event_queue *evqs[], size_t nr_evqs);
+void uth_blockon_evqs(struct event_msg *ev_msg, struct event_queue **which_evq,
+                      size_t nr_evqs, ...);
+bool uth_check_evqs(struct event_msg *ev_msg, struct event_queue **which_evq,
+                    size_t nr_evqs, ...);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/mcs.h b/user/parlib/include/parlib/mcs.h
new file mode 100644 (file)
index 0000000..570c569
--- /dev/null
@@ -0,0 +1,113 @@
+#pragma once
+
+#include <parlib/vcore.h>
+#include <parlib/arch/arch.h>
+
+__BEGIN_DECLS
+
+#define MCS_LOCK_INIT {0}
+#define MCS_QNODE_INIT {0, 0}
+
+typedef struct mcs_lock_qnode
+{
+       struct mcs_lock_qnode *next;
+       int locked;
+}__attribute__((aligned(ARCH_CL_SIZE))) mcs_lock_qnode_t;
+
+typedef struct mcs_lock
+{
+       mcs_lock_qnode_t* lock;
+} 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(struct mcs_lock *lock);
+/* Caller needs to alloc (and zero) their own qnode to spin on.  The memory
+ * should be on a cacheline that is 'per-thread'.  This could be on the stack,
+ * in a thread control block, etc. */
+void mcs_lock_lock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+void mcs_lock_unlock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+void mcs_lock_unlock_cas(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+/* If you lock the lock from vcore context, you must use these. */
+void mcs_lock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+void mcs_unlock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+
+/* Preemption detection and recovering MCS locks.
+ *
+ * The basic idea is that when spinning, vcores make sure someone else is
+ * making progress that will lead to them not spinning.  Usually, it'll be to
+ * make sure the lock holder (if known) is running.  If we don't know the lock
+ * holder, we ensure the end of whatever chain we can see is running, which
+ * will make sure its predecessor runs, which will eventually unjam the system.
+ * */
+
+/* Old style.  Has trouble getting out of 'preempt/change-to storms' under
+ * heavy contention and with preemption. */
+struct mcs_pdro_qnode
+{
+       struct mcs_pdro_qnode *next;
+       int locked;
+       uint32_t vcoreid;
+}__attribute__((aligned(ARCH_CL_SIZE)));
+
+struct mcs_pdro_lock
+{
+       struct mcs_pdro_qnode *lock;
+};
+
+#define MCSPDRO_LOCK_INIT {0}
+#define MCSPDRO_QNODE_INIT {0, 0, 0}
+
+void mcs_pdro_init(struct mcs_pdro_lock *lock);
+void mcs_pdro_fini(struct mcs_pdro_lock *lock);
+void mcs_pdro_lock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
+void mcs_pdro_unlock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
+
+/* Only call these if you have notifs disabled and know your vcore's qnode.
+ * Mostly used for debugging, benchmarks, or critical code. */
+void __mcs_pdro_lock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
+void __mcs_pdro_unlock(struct mcs_pdro_lock *lock, struct mcs_pdro_qnode *qnode);
+void __mcs_pdro_unlock_no_cas(struct mcs_pdro_lock *lock,
+                             struct mcs_pdro_qnode *qnode);
+
+/* New style: under heavy contention with preemption, they won't enter the
+ * 'preempt/change_to storm' that can happen to PDRs, at the cost of some
+ * performance.  This is the default. */
+struct mcs_pdr_qnode
+{
+       struct mcs_pdr_qnode *next;
+       int locked;
+}__attribute__((aligned(ARCH_CL_SIZE)));
+
+struct mcs_pdr_lock
+{
+       struct mcs_pdr_qnode *lock __attribute__((aligned(ARCH_CL_SIZE)));
+       uint32_t lockholder_vcoreid __attribute__((aligned(ARCH_CL_SIZE)));
+       struct mcs_pdr_qnode *qnodes __attribute__((aligned(ARCH_CL_SIZE)));
+};
+
+#define MCSPDR_NO_LOCKHOLDER ((uint32_t)-1)
+
+void mcs_pdr_init(struct mcs_pdr_lock *lock);
+void mcs_pdr_fini(struct mcs_pdr_lock *lock);
+void mcs_pdr_lock(struct mcs_pdr_lock *lock);
+void mcs_pdr_unlock(struct mcs_pdr_lock *lock);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/net.h b/user/parlib/include/parlib/net.h
new file mode 100644 (file)
index 0000000..d72b31e
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Networking helpers for dealing with the plan 9 interface. */
+
+#pragma once
+
+__BEGIN_DECLS
+
+static inline int snprintf_overflow(int ret, char *buf, size_t buf_len)
+{
+       return (ret == buf_len) && (buf[buf_len - 1] != 0);
+}
+
+int cheap_dial(char *addr, char *local, char *dir, int *cfdp);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/parlib.h b/user/parlib/include/parlib/parlib.h
new file mode 100644 (file)
index 0000000..56c6ab0
--- /dev/null
@@ -0,0 +1,67 @@
+// Main public header file for our user-land support library,
+// whose code lives in the lib directory.
+// This library is roughly our OS's version of a standard C library,
+// and is intended to be linked into all user-mode applications
+// (NOT the kernel or boot loader).
+
+#pragma once
+
+#ifndef __ASSEMBLER__
+
+#include <parlib/common.h>
+#include <ros/memlayout.h>
+#include <ros/syscall.h>
+#include <ros/procinfo.h>
+#include <ros/procdata.h>
+#include <signal.h>
+#include <stdint.h>
+#include <errno.h>
+#include <parlib/ros_debug.h>
+#include <ros/fdtap.h>
+
+__BEGIN_DECLS
+
+enum {
+       PG_RDONLY = 4,
+       PG_RDWR   = 6,
+};
+
+ssize_t     sys_cputs(const uint8_t *s, size_t len);
+uint16_t    sys_cgetc(void);
+int         sys_null(void);
+size_t      sys_getpcoreid(void);
+/* Process Management */
+int         sys_getpid(void);
+int         sys_proc_destroy(int pid, int exitcode);
+void        sys_yield(bool being_nice);
+int         sys_proc_create(const char *path, size_t path_l, char *const argv[],
+                            char *const envp[], int flags);
+int         sys_proc_run(int pid);
+ssize_t     sys_shared_page_alloc(void **addr, pid_t p2, 
+                                  int p1_flags, int p2_flags);
+ssize_t     sys_shared_page_free(void *addr, pid_t p2);
+void        sys_reboot();
+void           *sys_mmap(void *addr, size_t length, int prot, int flags,
+                      int fd, size_t offset);
+int                    sys_provision(int pid, unsigned int res_type, long res_val);
+int         sys_notify(int pid, unsigned int ev_type, struct event_msg *u_msg);
+int         sys_self_notify(uint32_t vcoreid, unsigned int ev_type,
+                            struct event_msg *u_msg, bool priv);
+int         sys_halt_core(unsigned int usec);
+void*          sys_init_arsc();
+int         sys_block(unsigned int usec);
+int         sys_change_vcore(uint32_t vcoreid, bool enable_my_notif);
+int         sys_change_to_m(void);
+int         sys_poke_ksched(int pid, unsigned int res_type);
+int         sys_abort_sysc(struct syscall *sysc);
+int         sys_abort_sysc_fd(int fd);
+int         sys_tap_fds(struct fd_tap_req *tap_reqs, size_t nr_reqs);
+
+void           syscall_async(struct syscall *sysc, unsigned long num, ...);
+
+/* Control variables */
+extern bool parlib_wants_to_be_mcp;    /* instructs the 2LS to be an MCP */
+
+__END_DECLS
+
+#endif // !ASSEMBLER
diff --git a/user/parlib/include/parlib/poke.h b/user/parlib/include/parlib/poke.h
new file mode 100644 (file)
index 0000000..342fce0
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2012 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Post work and poke synchronization.  This is a wait-free way to make sure
+ * some code is run, usually by the calling core, but potentially by any core.
+ * Under contention, everyone just posts work, and one core will carry out the
+ * work.  Callers post work (the meaning of which is particular to their
+ * subsystem), then call this function.  The function is not run concurrently
+ * with itself.
+ *
+ * As far as uthreads, vcores, and preemption go, poking is safe in uthread
+ * context and if preemptions occur.  However, a uthread running the poke
+ * function that gets preempted could delay the execution of the poke
+ * indefinitely.  In general, post-and-poke does not provide any guarantee about
+ * *when* the poke finally occurs.  If delays of this sort are a problem, then
+ * run poke() from vcore context.
+ *
+ * Adapted from the kernel's implementation. */
+
+#pragma once
+
+#include <ros/atomic.h>
+
+__BEGIN_DECLS
+
+struct poke_tracker {
+       atomic_t                        need_to_run;
+       atomic_t                        run_in_progress;
+       void                            (*func)(void *);
+};
+
+void poke(struct poke_tracker *tracker, void *arg);
+
+static inline void poke_init(struct poke_tracker *tracker, void (*func)(void*))
+{
+       tracker->need_to_run = 0;
+       tracker->run_in_progress = 0;
+       tracker->func = func;
+}
+
+#define POKE_INITIALIZER(f) {.func = f}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/pool.h b/user/parlib/include/parlib/pool.h
new file mode 100644 (file)
index 0000000..c4365b5
--- /dev/null
@@ -0,0 +1,76 @@
+/* See COPYRIGHT for copyright information. */
+/* Kevin Klues <klueska@cs.berkeley.edu>       */
+
+#pragma once
+
+#include <string.h>
+
+__BEGIN_DECLS
+
+#define POOL_TYPE_DEFINE(_type, p, sz)                                                \
+typedef struct struct_##p {                                                             \
+       uint32_t size;                                                         \
+       uint32_t free;                                                         \
+       uint32_t index;                                                        \
+       _type *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)
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/printf-ext.h b/user/parlib/include/parlib/printf-ext.h
new file mode 100644 (file)
index 0000000..14e3c6d
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Common printf format extensions.  For now, %r is installed by default
+ * (in early init code), and the others need to be requested.
+ *
+ * To register, for example %i for ipaddr, call:
+ *             register_printf_specifier('i', printf_ipaddr, printf_ipaddr_info);
+ */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <printf.h>
+
+__BEGIN_DECLS
+
+/* Commonly used as %i, will print out a 16-byte plan9 IP address */
+int printf_ipaddr(FILE *stream, const struct printf_info *info,
+                  const void *const *args);
+int printf_ipaddr_info(const struct printf_info* info, size_t n, int *argtypes,
+                       int *size);
+
+/* Commonly used as %M, will print out a plan9 IPv6 mask, preferably as /xx */
+int printf_ipmask(FILE *stream, const struct printf_info *info,
+                  const void *const *args);
+int printf_ipmask_info(const struct printf_info* info, size_t n, int *argtypes,
+                       int *size);
+
+/* Commonly used as %E, will print out an ethernet address */
+int printf_ethaddr(FILE *stream, const struct printf_info *info,
+                   const void *const *args);
+int printf_ethaddr_info(const struct printf_info* info, size_t n, int *argtypes,
+                        int *size);
+
+/* Installed by default, will print the errstr for %r */
+int printf_errstr(FILE *stream, const struct printf_info *info,
+                  const void *const *args);
+int printf_errstr_info(const struct printf_info* info, size_t n, int *argtypes,
+                       int *size);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/riscv/arch.h b/user/parlib/include/parlib/riscv/arch.h
new file mode 100644 (file)
index 0000000..143306e
--- /dev/null
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+#include <ros/arch/arch.h>
+
+__BEGIN_DECLS
+
+#define internal_function
+
+#define ARCH_CL_SIZE 64
+
+static __inline void
+set_stack_pointer(void* sp)
+{
+       asm volatile ("move sp, %0" : : "r"(sp) : "memory");
+}
+
+static __inline void
+breakpoint(void)
+{
+       asm volatile ("break");
+}
+
+static __inline uint64_t
+read_tsc(void)
+{
+       unsigned long cycles;
+       asm ("rdcycle %0" : "=r"(cycles));
+       return (uint64_t)cycles;
+}
+
+static __inline uint64_t
+read_tsc_serialized(void)
+{
+       return read_tsc();
+}
+
+static __inline void
+cpu_relax(void)
+{
+       long ctr;
+       asm volatile("li %0, 8; 1: addi %0, %0, -1; bnez %0, 1b" : "=r"(ctr) : : "memory");
+}
+
+static inline void save_fp_state(struct ancillary_state* silly)
+{
+       uint32_t fsr = read_fsr();
+
+       asm("fsd fs0,%0" : "=m"(silly->fpr[0]));
+       asm("fsd fs1,%0" : "=m"(silly->fpr[1]));
+       asm("fsd fs2,%0" : "=m"(silly->fpr[2]));
+       asm("fsd fs3,%0" : "=m"(silly->fpr[3]));
+       asm("fsd fs4,%0" : "=m"(silly->fpr[4]));
+       asm("fsd fs5,%0" : "=m"(silly->fpr[5]));
+       asm("fsd fs6,%0" : "=m"(silly->fpr[6]));
+       asm("fsd fs7,%0" : "=m"(silly->fpr[7]));
+       asm("fsd fs8,%0" : "=m"(silly->fpr[8]));
+       asm("fsd fs9,%0" : "=m"(silly->fpr[9]));
+       asm("fsd fs10,%0" : "=m"(silly->fpr[10]));
+       asm("fsd fs11,%0" : "=m"(silly->fpr[11]));
+       asm("fsd fs12,%0" : "=m"(silly->fpr[12]));
+       asm("fsd fs13,%0" : "=m"(silly->fpr[13]));
+       asm("fsd fs14,%0" : "=m"(silly->fpr[14]));
+       asm("fsd fs15,%0" : "=m"(silly->fpr[15]));
+
+       silly->fsr = fsr;
+}
+
+static inline void restore_fp_state(struct ancillary_state* silly)
+{
+       uint32_t fsr = silly->fsr;
+
+       asm("fld fs0,%0" : : "m"(silly->fpr[0]));
+       asm("fld fs1,%0" : : "m"(silly->fpr[1]));
+       asm("fld fs2,%0" : : "m"(silly->fpr[2]));
+       asm("fld fs3,%0" : : "m"(silly->fpr[3]));
+       asm("fld fs4,%0" : : "m"(silly->fpr[4]));
+       asm("fld fs5,%0" : : "m"(silly->fpr[5]));
+       asm("fld fs6,%0" : : "m"(silly->fpr[6]));
+       asm("fld fs7,%0" : : "m"(silly->fpr[7]));
+       asm("fld fs8,%0" : : "m"(silly->fpr[8]));
+       asm("fld fs9,%0" : : "m"(silly->fpr[9]));
+       asm("fld fs10,%0" : : "m"(silly->fpr[10]));
+       asm("fld fs11,%0" : : "m"(silly->fpr[11]));
+       asm("fld fs12,%0" : : "m"(silly->fpr[12]));
+       asm("fld fs13,%0" : : "m"(silly->fpr[13]));
+       asm("fld fs14,%0" : : "m"(silly->fpr[14]));
+       asm("fld fs15,%0" : : "m"(silly->fpr[15]));
+
+       write_fsr(fsr);
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/riscv/atomic.h b/user/parlib/include/parlib/riscv/atomic.h
new file mode 100644 (file)
index 0000000..994deb4
--- /dev/null
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/atomic.h>
+#include <ros/arch/membar.h>
+
+__BEGIN_DECLS
+
+#define SPINLOCK_INITIALIZER {0}
+
+static inline void atomic_init(atomic_t *number, long val);
+static inline long atomic_read(atomic_t *number);
+static inline void atomic_set(atomic_t *number, long val);
+static inline void atomic_inc(atomic_t *number);
+static inline void atomic_dec(atomic_t *number);
+static inline long atomic_fetch_and_add(atomic_t *number, long val);
+static inline long atomic_swap(atomic_t *addr, long val);
+static inline void *atomic_swap_ptr(void **addr, void *val);
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
+static inline void atomic_or_int(volatile int *number, int mask);
+
+/* Inlined functions declared above */
+
+static inline void atomic_init(atomic_t *number, long val)
+{
+       *(volatile long*)number = val;
+}
+
+static inline long atomic_read(atomic_t *number)
+{
+       return *(volatile long*)number;
+}
+
+static inline void ros_atomic_add(atomic_t *number, long inc)
+{
+       atomic_fetch_and_add(number, inc);
+}
+
+static inline void atomic_set(atomic_t *number, long val)
+{
+       atomic_init(number, val);
+}
+
+static inline void atomic_inc(atomic_t *number)
+{
+       ros_atomic_add(number, 1);
+}
+
+static inline void atomic_dec(atomic_t *number)
+{
+       ros_atomic_add(number, -1);
+}
+
+/* Adds val to number, returning number's original value */
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
+{
+       return __sync_fetch_and_add((long*)number, val);
+}
+
+static inline long atomic_swap(atomic_t *addr, long val)
+{
+       return __sync_lock_test_and_set((long*)addr, val);
+}
+
+static inline void *atomic_swap_ptr(void **addr, void *val)
+{
+       return __sync_lock_test_and_set(addr, val);
+}
+
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
+{
+       return __sync_lock_test_and_set(addr, val);
+}
+
+// RISC-V has atomic word ops, not byte ops, so we must manipulate addresses
+static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
+{
+       uintptr_t offset = (uintptr_t)number & 3;
+       uint32_t wmask = (1<<(8*offset+8)) - (1<<(8*offset));
+       wmask = ~wmask | ((uint32_t)mask << (8*offset));
+
+       __sync_fetch_and_and((uint32_t*)((uintptr_t)number & ~3), wmask);
+}
+
+static inline void atomic_orb(volatile uint8_t* number, uint8_t mask)
+{
+       uintptr_t offset = (uintptr_t)number & 3;
+       uint32_t wmask = (uint32_t)mask << (8*offset);
+
+       __sync_fetch_and_or((uint32_t*)((uintptr_t)number & ~3), wmask);
+}
+
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline void atomic_or_int(volatile int *number, int mask)
+{
+       __sync_fetch_and_or(number, mask);
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/riscv/bitmask.h b/user/parlib/include/parlib/riscv/bitmask.h
new file mode 100644 (file)
index 0000000..14bf590
--- /dev/null
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <parlib/arch/atomic.h>
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+#define DECL_BITMASK(name, size) \
+       uint8_t (name)[BYTES_FOR_BITMASK((size))]
+
+#define BYTES_FOR_BITMASK(size) \
+       (((size) - 1) / 8 + 1)
+
+#define BYTES_FOR_BITMASK_WITH_CHECK(size) \
+       ((size) ? ((size) - (1)) / (8) + (1) : (0))
+
+static bool GET_BITMASK_BIT(uint8_t* name, size_t bit) 
+{
+       return (((name)[(bit)/8] & (1 << ((bit) % 8))) ? 1 : 0);
+}
+
+#define SET_BITMASK_BIT(name, bit) \
+       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
+/*
+static void SET_BITMASK_BIT(uint8_t* name, size_t bit)
+{
+       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
+}
+*/
+
+#define CLR_BITMASK_BIT(name, bit) \
+       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
+/*
+static void CLR_BITMASK_BIT(uint8_t* name, size_t bit) 
+{
+       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
+}
+*/
+
+static void SET_BITMASK_BIT_ATOMIC(uint8_t* name, size_t bit) 
+{
+       (atomic_orb(&(name)[(bit)/8], (1 << ((bit) % 8))));
+}
+
+#define CLR_BITMASK_BIT_ATOMIC(name, bit) \
+       (atomic_andb(&(name)[(bit)/8], ~(1 << ((bit) % 8))))
+
+#define CLR_BITMASK(name, size) \
+({ \
+       memset((void*)((uintptr_t)(name)), 0, BYTES_FOR_BITMASK((size))); \
+})
+
+#define FILL_BITMASK(name, size) \
+({ \
+       memset((void*)((uintptr_t)(name)), 255, BYTES_FOR_BITMASK((size))); \
+       (name)[BYTES_FOR_BITMASK((size))-1] >>= (((size) % 8) ? (8 - ((size) % 8)) : 0 ); \
+}) 
+
+#define COPY_BITMASK(newmask, oldmask, size) \
+({ \
+       memcpy((void*)((uintptr_t)(newmask)), \
+           (void*)((uintptr_t)(oldmask)), \
+           BYTES_FOR_BITMASK((size))); \
+})
+
+// this checks the entire last byte, so keep it 0 in the other macros
+#define BITMASK_IS_CLEAR(name, size) ({ \
+       uint32_t __n = BYTES_FOR_BITMASK((size)); \
+       bool clear = 1; \
+       while (__n-- > 0) { \
+               if ((name)[__n]) { \
+                       clear = 0; \
+                       break;\
+               }\
+       } \
+       clear; })
+
+static inline bool BITMASK_IS_FULL(uint8_t* map, size_t size)
+{
+       int _size = size;
+       for (int i = 0; i < BYTES_FOR_BITMASK(size); i++) {
+               for (int j = 0; j < MIN(8,_size); j++)
+                       if(!((map[i] >> j) &1))
+                               return FALSE;
+                       _size--;
+       }
+       return TRUE;
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/riscv/trap.h b/user/parlib/include/parlib/riscv/trap.h
new file mode 100644 (file)
index 0000000..7a4060e
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Arch-specific defines for traps, vmexits, and similar things */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+
+__BEGIN_DECLS
+
+#error fix these numbers
+
+#define HW_TRAP_DIV_ZERO               0
+#define HW_TRAP_GP_FAULT               1
+#define HW_TRAP_PAGE_FAULT             2
+
+#error implement these
+static bool has_refl_fault(struct user_context *ctx)
+{
+       return 0;
+}
+
+static void clear_refl_fault(struct user_context *ctx)
+{
+}
+
+static unsigned int __arch_refl_get_nr(struct user_context *ctx)
+{
+       return 0;
+}
+
+static unsigned int __arch_refl_get_err(struct user_context *ctx)
+{
+       return 0;
+}
+
+static unsigned long __arch_refl_get_aux(struct user_context *ctx)
+{
+       return 0;
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/riscv/vcore.h b/user/parlib/include/parlib/riscv/vcore.h
new file mode 100644 (file)
index 0000000..dba6b97
--- /dev/null
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+#include <parlib/arch/arch.h>
+#include <ros/syscall.h>
+#include <ros/procdata.h>
+#include <parlib/assert.h>
+#include <sys/tls.h>
+
+__BEGIN_DECLS
+
+#ifdef __riscv64
+# define REG_L "ld"
+# define REG_S "sd"
+#else
+# define REG_L "lw"
+# define REG_S "sw"
+#endif
+
+/* Register saves and restores happen in asm. */
+typedef void (*helper_fn)(struct hw_trapframe*, struct preempt_data*, uint32_t);
+void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd,
+                    uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
+void __save_ros_tf_regs(struct hw_trapframe *tf) __attribute__((returns_twice));
+
+/* Helper function that may handle notifications after re-enabling them. */
+static void __pop_ros_tf_notifs(struct hw_trapframe *tf,
+                                struct preempt_data* vcpd, uint32_t vcoreid)
+{
+       vcpd->notif_disabled = FALSE;
+
+       __sync_synchronize();
+
+       if(vcpd->notif_pending)
+               ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0);
+}
+
+/* Helper function that won't handle notifications after re-enabling them. */
+static void __pop_ros_tf_notifs_raw(struct hw_trapframe *tf,
+                                    struct preempt_data* vcpd, uint32_t vcoreid)
+{
+       vcpd->notif_disabled = FALSE;
+}
+
+static inline void __pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid,
+                                helper_fn helper)
+{
+       // since we're changing the stack, move stuff into regs for now
+       register uint32_t _vcoreid = vcoreid;
+       register struct hw_trapframe* _tf = tf;
+
+       set_stack_pointer((void*)tf->gpr[GPR_SP]);
+
+       tf = _tf;
+       vcoreid = _vcoreid;
+       struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       __pop_ros_tf_regs(tf, vcpd, vcoreid, helper);
+}
+
+/* Pops a user context, 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_user_ctx(struct user_context *ctx, uint32_t vcoreid)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+       __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
+}
+
+/* Like the regular pop_user_ctx, but this one doesn't check or clear
+ * notif_pending. */
+static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+       __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
+}
+
+/* Save the current context/registers into the given ctx, setting the pc of the
+ * tf to the end of this function.  You only need to save that which you later
+ * restore with pop_user_ctx(). */
+static inline void save_user_ctx(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       __save_ros_tf_regs(tf);
+}
+
+static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt,
+                                 uint32_t stack_top)
+{
+       struct hw_trapframe *u_tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       memset(u_tf, 0, sizeof(*u_tf));
+       u_tf->gpr[GPR_SP] = stack_top;
+       u_tf->epc = entry_pt;
+}
+
+static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.gpr[GPR_SP];
+}
+
+#define __vcore_id_on_entry \
+({ \
+       register int temp asm ("a0"); \
+       temp; \
+})
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/ros_debug.h b/user/parlib/include/parlib/ros_debug.h
new file mode 100644 (file)
index 0000000..9de59b4
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <parlib/common.h>
+#include <parlib/parlib.h>
+#include <parlib/vcore.h>
+
+__BEGIN_DECLS
+
+#define I_AM_HERE printf("Vcore %d is in %s() at %s:%d\n", vcore_id(), \
+                         __FUNCTION__, __FILE__, __LINE__);
+
+/* For a poor-mans function tracer (can add these with spatch) */
+void __print_func_entry(const char *func, const char *file);
+void __print_func_exit(const char *func, const char *file);
+#define print_func_entry() __print_func_entry(__FUNCTION__, __FILE__)
+#define print_func_exit() __print_func_exit(__FUNCTION__, __FILE__)
+
+/* user/parlib/hexdump.c */
+void hexdump(FILE *f, void *v, int length);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/serialize.h b/user/parlib/include/parlib/serialize.h
new file mode 100644 (file)
index 0000000..d97eaf0
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2015 Google Inc., All Rights Reserved.
+ * Kevin Klues <klueska@google.com>
+ * See LICENSE for details. */
+
+#pragma once
+
+#include <stddef.h>
+
+struct serialized_data {
+       size_t len;
+       char buf[];
+};
+extern struct serialized_data *serialize_argv_envp(char *const argv[],
+                                                   char *const envp[]);
+extern void free_serialized_data(struct serialized_data *sd);
diff --git a/user/parlib/include/parlib/signal.h b/user/parlib/include/parlib/signal.h
new file mode 100644 (file)
index 0000000..eb9ca33
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (c) 2015 Google Inc.
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * See LICENSE for details.
+ */
+
+#pragma once
+#ifdef BUILDING_PARLIB
+#include_next "signal.h"
+#else
+#include <signal.h>
+#endif
+
+#include <ros/procinfo.h>
+
+struct uthread;
+
+/* Data we need to carry around as part of handling posix signals on akaros. */
+struct sigdata {
+       struct user_context u_ctx;
+       struct ancillary_state as;
+       struct siginfo info;
+};
+struct sigstate {
+       sigset_t mask;
+       sigset_t pending;
+       struct sigdata *data;
+};
+
+/* A set of functions related to handling posix signals on akaros. The
+ * implementation of these functions is 2LS specific. */
+struct signal_ops {
+       /* Standard ops */
+       int (*sigaltstack)(__const struct sigaltstack *__restrict,
+                       struct sigaltstack *__restrict);
+       int (*siginterrupt)(int, int);
+       int (*sigpending)(sigset_t *);
+       int (*sigprocmask)(int, __const sigset_t *__restrict, sigset_t *__restrict);
+       int (*sigqueue)(__pid_t, int, __const union sigval);
+       int (*sigreturn)(struct sigcontext *__scp);
+       int (*sigstack)(struct sigstack *, struct sigstack *);
+       int (*sigsuspend)(__const sigset_t *);
+       int (*sigtimedwait)(__const sigset_t *__restrict, siginfo_t *__restrict,
+                           __const struct timespec *__restrict);
+       int (*sigwait)(__const sigset_t *__restrict, int *__restrict);
+       int (*sigwaitinfo)(__const sigset_t *__restrict, siginfo_t *__restrict);
+
+       /* Extended ops */
+       int (*sigself)(int signo);
+};
+
+/* Glibc defines the symbol for signal_ops so that the function pointers
+ * assigned in it can be used from within glibc itself. */
+extern struct signal_ops *signal_ops;
+
+/* External API for initializing and generating posix signals inside a 2LS. */
+void init_posix_signals(void);
+void trigger_posix_signal(int sig_nr, struct siginfo *info, void *aux);
+void uthread_prep_pending_signals(struct uthread *uthread);
+void uthread_prep_signal_from_fault(struct uthread *uthread,
+                                    int signo, int code, void *addr);
+int uthread_signal(struct uthread *uthread, int signo);
diff --git a/user/parlib/include/parlib/slab.h b/user/parlib/include/parlib/slab.h
new file mode 100644 (file)
index 0000000..7195819
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Slab allocator, based on the SunOS 5.4 allocator paper.
+ *
+ * There is a list of kmem_cache, which are the caches of objects of a given
+ * size.  This list is sorted in order of size.  Each kmem_cache has three
+ * lists of slabs: full, partial, and empty.  
+ *
+ * For large objects, the kmem_slabs point to bufctls, which have the address
+ * of their large buffers.  These slabs can consist of more than one contiguous
+ * page.
+ *
+ * For small objects, the slabs do not use the bufctls.  Instead, they point to
+ * the next free object in the slab.  The free objects themselves hold the
+ * address of the next free item.  The slab structure is stored at the end of
+ * the page.  There is only one page per slab.
+ *
+ * TODO: Note, that this is a minor pain in the ass, and worth thinking about
+ * before implementing.  To keep the constructor's state valid, we can't just
+ * overwrite things, so we need to add an extra 4-8 bytes per object for the
+ * pointer, and then pass over that data when we return the actual object's
+ * address.  This also might fuck with alignment.
+ *
+ * Ported directly from the kernel's slab allocator. */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/arch/mmu.h>
+#include <sys/queue.h>
+#include <parlib/arch/atomic.h>
+#include <parlib/spinlock.h>
+
+__BEGIN_DECLS
+
+/* Back in the day, their cutoff for "large objects" was 512B, based on
+ * measurements and on not wanting more than 1/8 of internal fragmentation. */
+#define NUM_BUF_PER_SLAB 8
+#define SLAB_LARGE_CUTOFF (PGSIZE / NUM_BUF_PER_SLAB)
+
+struct kmem_slab;
+
+/* Control block for buffers for large-object slabs */
+struct kmem_bufctl {
+       TAILQ_ENTRY(kmem_bufctl) link;
+       void *buf_addr;
+       struct kmem_slab *my_slab;
+};
+TAILQ_HEAD(kmem_bufctl_list, kmem_bufctl);
+
+/* Slabs contain the objects.  Can be either full, partial, or empty,
+ * determined by checking the number of objects busy vs total.  For large
+ * slabs, the bufctl list is used to find a free buffer.  For small, the void*
+ * is used instead.*/
+struct kmem_slab {
+       TAILQ_ENTRY(kmem_slab) link;
+       size_t obj_size;
+       size_t num_busy_obj;
+       size_t num_total_obj;
+       union {
+               struct kmem_bufctl_list bufctl_freelist;
+               void *free_small_obj;
+       };
+};
+TAILQ_HEAD(kmem_slab_list, kmem_slab);
+
+/* Actual cache */
+struct kmem_cache {
+       SLIST_ENTRY(kmem_cache) link;
+       struct spin_pdr_lock cache_lock;
+       const char *name;
+       size_t obj_size;
+       int align;
+       int flags;
+       struct kmem_slab_list full_slab_list;
+       struct kmem_slab_list partial_slab_list;
+       struct kmem_slab_list empty_slab_list;
+       void (*ctor)(void *, size_t);
+       void (*dtor)(void *, size_t);
+       unsigned long nr_cur_alloc;
+};
+
+/* List of all kmem_caches, sorted in order of size */
+SLIST_HEAD(kmem_cache_list, kmem_cache);
+extern struct kmem_cache_list kmem_caches;
+
+/* Cache management */
+struct kmem_cache *kmem_cache_create(const char *name, size_t obj_size,
+                                     int align, int flags,
+                                     void (*ctor)(void *, size_t),
+                                     void (*dtor)(void *, size_t));
+void kmem_cache_destroy(struct kmem_cache *cp);
+/* Front end: clients of caches use these */
+void *kmem_cache_alloc(struct kmem_cache *cp, int flags);
+void kmem_cache_free(struct kmem_cache *cp, void *buf);
+/* Back end: internal functions */
+void kmem_cache_init(void);
+void kmem_cache_reap(struct kmem_cache *cp);
+
+/* Debug */
+void print_kmem_cache(struct kmem_cache *kc);
+void print_kmem_slab(struct kmem_slab *slab);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/spinlock.h b/user/parlib/include/parlib/spinlock.h
new file mode 100644 (file)
index 0000000..f4ffea1
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ *
+ * Spinlocks and Spin-PDR locks (preemption detection/recovery)
+ *
+ * This file is part of Parlib.
+ * 
+ * Parlib is free software: you can redistribute it and/or modify
+ * it under the terms of the Lesser GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * Parlib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * Lesser GNU General Public License for more details.
+ * 
+ * See COPYING.LESSER for details on the GNU Lesser General Public License.
+ * See COPYING for details on the GNU General Public License. */
+
+#pragma once
+
+#include <parlib/arch/arch.h>
+#include <parlib/arch/atomic.h>
+
+__BEGIN_DECLS
+
+#define SPINLOCK_INITIALIZER {0}
+
+typedef struct {
+  int lock;
+} spinlock_t;
+
+void spinlock_init(spinlock_t *lock);
+int spinlock_trylock(spinlock_t *lock);
+void spinlock_lock(spinlock_t *lock);
+void spinlock_unlock(spinlock_t *lock);
+bool spinlock_locked(spinlock_t *lock);
+
+/* RISCV doesn't support CAS, so til it does, we use the NO_CAS, even if they
+ * didn't ask for it in their config. */
+#ifdef __riscv__
+# ifndef CONFIG_SPINPDR_NO_CAS
+#  define CONFIG_SPINPDR_NO_CAS 1
+# endif
+#endif
+
+/* Two different versions, with and without CAS.  Default is with CAS. */
+#ifndef CONFIG_SPINPDR_NO_CAS
+
+# define SPINPDR_UNLOCKED ((uint32_t)-1)
+
+struct spin_pdr_lock {
+       uint32_t lock;
+};
+# define SPINPDR_INITIALIZER {SPINPDR_UNLOCKED}
+
+#else /* NO_CAS */
+
+# define SPINPDR_VCOREID_UNKNOWN ((uint32_t)-1)
+
+struct spin_pdr_lock {
+       /* consider putting these on separate cache lines, if we ever use them */
+       spinlock_t spinlock;
+       uint32_t lockholder;
+};
+# define SPINPDR_INITIALIZER {SPINLOCK_INITIALIZER, SPINPDR_VCOREID_UNKNOWN}
+
+#endif /* CONFIG_SPINPDR_NO_CAS */
+
+typedef struct spin_pdr_lock spinpdrlock_t;
+
+void spin_pdr_init(struct spin_pdr_lock *pdr_lock);
+void spin_pdr_lock(struct spin_pdr_lock *pdr_lock);
+void spin_pdr_unlock(struct spin_pdr_lock *pdr_lock);
+bool spin_pdr_locked(struct spin_pdr_lock *pdr_lock);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/stdio.h b/user/parlib/include/parlib/stdio.h
new file mode 100644 (file)
index 0000000..0c5ddab
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Print routines for Akaros user programs. */
+
+#pragma once
+
+#ifdef BUILDING_PARLIB
+# include_next "stdio.h"
+#else
+# include <stdio.h>
+#endif
+#include <stdarg.h>
+
+__BEGIN_DECLS
+
+void akaros_vprintfmt(void (*putch)(int, void**), void **putdat,
+                      const char *fmt, va_list);
+int akaros_vprintf(const char *fmt, va_list);
+/* This is the same as our sysdep for glibc's printf.  We use this to print in
+ * a few places in glibc that can't link directly against printf.  (the
+ * 'multiple libcs' problem). */
+int akaros_printf(const char *format, ...);
+
+#ifdef PRINTD_DEBUG
+#define printd(args...) printf(args)
+#else
+#define printd(args...) {}
+#endif
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/timing.h b/user/parlib/include/parlib/timing.h
new file mode 100644 (file)
index 0000000..86833a6
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <stdint.h>
+#include <parlib/tsc-compat.h>
+
+__BEGIN_DECLS
+
+void udelay(uint64_t usec);
+void ndelay(uint64_t nsec);
+uint64_t udiff(uint64_t begin, uint64_t end);
+uint64_t ndiff(uint64_t begin, uint64_t end);
+
+/* Conversion btw tsc ticks and time units.  From Akaros's kern/src/time.c */
+uint64_t tsc2sec(uint64_t tsc_time);
+uint64_t tsc2msec(uint64_t tsc_time);
+uint64_t tsc2usec(uint64_t tsc_time);
+uint64_t tsc2nsec(uint64_t tsc_time);
+uint64_t sec2tsc(uint64_t sec);
+uint64_t msec2tsc(uint64_t msec);
+uint64_t usec2tsc(uint64_t usec);
+uint64_t nsec2tsc(uint64_t nsec);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/tsc-compat.h b/user/parlib/include/parlib/tsc-compat.h
new file mode 100644 (file)
index 0000000..47c9c59
--- /dev/null
@@ -0,0 +1,173 @@
+/* Basic TSC compatability helpers, callable from Akaros or Linux. Supports:
+ *             uint64_t read_tsc()
+ *             uint64_t read_tsc_serialized()
+ *             uint64_t get_tsc_freq()
+ *             uint64_t get_tsc_overhead()
+ *
+ * Note this relies on specifics of procinfo, which isn't stable.  If procinfo
+ * changes, this will need to change as well.  You'll know when this doesn't
+ * compile (say, if timing_overhead moves).  */
+
+#pragma once
+
+#if defined(__i386__) || defined(__x86_64__)
+#else
+#error "Platform not supported for read_tsc()"
+#endif
+
+__BEGIN_DECLS
+
+#ifdef __ros__
+
+#include <parlib/arch/arch.h>
+#include <ros/procinfo.h>
+
+static inline uint64_t get_tsc_freq(void)
+{
+       return __procinfo.tsc_freq;
+}
+
+static inline uint64_t get_tsc_overhead(void)
+{
+       return __procinfo.timing_overhead;
+}
+
+#else /* ! _ros_ (linux) */
+
+#include <sys/time.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/* Akaros has this helper in ros/common.h. (it returns a bool btw)
+ *
+ * We wraparound if UINT_MAX < a * b, which is also UINT_MAX / a < b. */
+static inline int mult_will_overflow_u64(uint64_t a, uint64_t b)
+{
+       if (!a)
+               return false;
+       return (uint64_t)(-1) / a < b;
+}
+
+# ifdef __i386__
+
+static inline uint64_t read_tsc(void)
+{
+       uint64_t tsc;
+       asm volatile("rdtsc" : "=A" (tsc));
+       return tsc;
+}
+
+static inline uint64_t read_tsc_serialized(void)
+{
+       uint64_t tsc;
+       asm volatile("lfence; rdtsc" : "=A" (tsc));
+       return tsc;
+}
+
+# elif __x86_64__
+
+static inline uint64_t read_tsc(void)
+{
+       uint32_t lo, hi;
+       /* We cannot use "=A", since this would use %rax on x86_64 */
+       asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+       return (uint64_t)hi << 32 | lo;
+}
+
+static inline uint64_t read_tsc_serialized(void)
+{
+       uint32_t lo, hi;
+       asm volatile("lfence; rdtsc" : "=a" (lo), "=d" (hi));
+       return (uint64_t)hi << 32 | lo;
+}
+
+# else
+#  error "Which arch is this?"
+# endif /* __i386__ | __x86_64__ */
+
+static inline uint64_t get_tsc_freq(void)
+{
+       struct timeval prev;
+       struct timeval curr;
+       uint64_t beg = read_tsc_serialized();
+       gettimeofday(&prev, 0);
+       while (1) {
+               gettimeofday(&curr, 0);
+               if (curr.tv_sec > (prev.tv_sec + 1) ||
+                       (curr.tv_sec > prev.tv_sec && curr.tv_usec > prev.tv_usec))
+                       break;
+       }
+       uint64_t end = read_tsc_serialized();
+       return end - beg;
+}
+
+/* Don't have a good way to get the overhead on Linux in userspace. */
+static inline uint64_t get_tsc_overhead(void)
+{
+       return 0;
+}
+
+static inline uint64_t tsc2sec(uint64_t tsc_time)
+{
+       return tsc_time / get_tsc_freq();
+}
+
+static inline uint64_t tsc2msec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000))
+               return tsc2sec(tsc_time) * 1000;
+       else
+               return (tsc_time * 1000) / get_tsc_freq();
+}
+
+static inline uint64_t tsc2usec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000000))
+               return tsc2msec(tsc_time) * 1000;
+       else
+               return (tsc_time * 1000000) / get_tsc_freq();
+}
+
+static inline uint64_t tsc2nsec(uint64_t tsc_time)
+{
+       if (mult_will_overflow_u64(tsc_time, 1000000000))
+               return tsc2usec(tsc_time) * 1000;
+       else
+               return (tsc_time * 1000000000) / get_tsc_freq();
+}
+
+static inline uint64_t sec2tsc(uint64_t sec)
+{
+       if (mult_will_overflow_u64(sec, get_tsc_freq()))
+               return (uint64_t)(-1);
+       else
+               return sec * get_tsc_freq();
+}
+
+static inline uint64_t msec2tsc(uint64_t msec)
+{
+       if (mult_will_overflow_u64(msec, get_tsc_freq()))
+               return sec2tsc(msec / 1000);
+       else
+               return (msec * get_tsc_freq()) / 1000;
+}
+
+static inline uint64_t usec2tsc(uint64_t usec)
+{
+       if (mult_will_overflow_u64(usec, get_tsc_freq()))
+               return msec2tsc(usec / 1000);
+       else
+               return (usec * get_tsc_freq()) / 1000000;
+}
+
+static inline uint64_t nsec2tsc(uint64_t nsec)
+{
+       if (mult_will_overflow_u64(nsec, get_tsc_freq()))
+               return usec2tsc(nsec / 1000);
+       else
+               return (nsec * get_tsc_freq()) / 1000000000;
+}
+
+#endif /* ! _ros_ */
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/ucq.h b/user/parlib/include/parlib/ucq.h
new file mode 100644 (file)
index 0000000..7a7ba0c
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Unbounded concurrent queues, user side.  Check k/i/r/ucq.h or the
+ * Documentation for more info. */
+
+#pragma once
+
+#include <ros/ucq.h>
+
+__BEGIN_DECLS
+
+void ucq_init_raw(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2);
+void ucq_init(struct ucq *ucq);
+void ucq_free_pgs(struct ucq *ucq);
+bool get_ucq_msg(struct ucq *ucq, struct event_msg *msg);
+bool ucq_is_empty(struct ucq *ucq);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/uthread.h b/user/parlib/include/parlib/uthread.h
new file mode 100644 (file)
index 0000000..b108110
--- /dev/null
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <parlib/vcore.h>
+#include <parlib/signal.h>
+#include <ros/syscall.h>
+
+__BEGIN_DECLS
+
+#define UTHREAD_DONT_MIGRATE           0x001 /* don't move to another vcore */
+#define UTHREAD_SAVED                          0x002 /* uthread's state is in utf */
+#define UTHREAD_FPSAVED                                0x004 /* uthread's FP state is in uth->as */
+#define UTHREAD_IS_THREAD0                     0x008 /* thread0: glibc's main() thread */
+
+/* Thread States */
+#define UT_RUNNING             1
+#define UT_NOT_RUNNING 2
+
+/* Externally blocked thread reasons (for uthread_has_blocked()) */
+#define UTH_EXT_BLK_MUTEX                      1
+#define UTH_EXT_BLK_EVENTQ                     2
+#define UTH_EXT_BLK_JUSTICE                    3       /* whatever.  might need more options */
+
+/* Bare necessities of a user thread.  2LSs should allocate a bigger struct and
+ * cast their threads to uthreads when talking with vcore code.  Vcore/default
+ * 2LS code won't touch udata or beyond. */
+struct uthread {
+       struct user_context u_ctx;
+       struct ancillary_state as;
+       void *tls_desc;
+       int flags;
+       int state;
+       struct sigstate sigstate;
+       int notif_disabled_depth;
+       struct syscall *sysc;   /* syscall we're blocking on, if any */
+       struct syscall local_sysc;      /* for when we don't want to use the stack */
+       void (*yield_func)(struct uthread*, void*);
+       void *yield_arg;
+       int err_no;
+       char err_str[MAX_ERRSTR_LEN];
+};
+extern __thread struct uthread *current_uthread;
+typedef void* uth_mutex_t;
+
+/* 2L-Scheduler operations.  Examples in pthread.c. */
+struct schedule_ops {
+       /**** These functions must be defined ****/
+       /* Functions supporting thread ops */
+       void (*sched_entry)(void);
+       void (*thread_runnable)(struct uthread *);
+       void (*thread_paused)(struct uthread *);
+       void (*thread_blockon_sysc)(struct uthread *, void *);
+       void (*thread_has_blocked)(struct uthread *, int);
+       void (*thread_refl_fault)(struct uthread *, struct user_context *);
+       /**** Defining these functions is optional. ****/
+       /* 2LSs can leave the mutex funcs empty for a default implementation */
+       uth_mutex_t (*mutex_alloc)(void);
+       void (*mutex_free)(uth_mutex_t);
+       void (*mutex_lock)(uth_mutex_t);
+       void (*mutex_unlock)(uth_mutex_t);
+       /* Functions event handling wants */
+       void (*preempt_pending)(void);
+};
+extern struct schedule_ops *sched_ops;
+
+/* Low-level _S code calls this for basic uthreading without a 2LS */
+void uthread_lib_init(void);
+/* Call this, passing it a uthread representing thread0, from your 2LS init
+ * routines.  When it returns, you're in _M mode (thread0 on vcore0) */
+void uthread_2ls_init(struct uthread *uthread, struct schedule_ops *ops);
+/* Call this to become an mcp capable of worling with uthreads. */
+void uthread_mcp_init(void);
+
+/* Functions to make/manage uthreads.  Can be called by functions such as
+ * pthread_create(), which can wrap these with their own stuff (like attrs,
+ * retvals, etc). */
+
+/* uthread_init() does the uthread initialization of a uthread that the caller
+ * created.  Call this whenever you are "starting over" with a thread.  Pass in
+ * attr, if you want to override any defaults. */
+struct uth_thread_attr {
+       bool want_tls;          /* default, no */
+};
+void uthread_init(struct uthread *new_thread, struct uth_thread_attr *attr);
+/* Call this when you are done with a uthread, forever, but before you free it */
+void uthread_cleanup(struct uthread *uthread);
+void uthread_runnable(struct uthread *uthread);
+void uthread_yield(bool save_state, void (*yield_func)(struct uthread*, void*),
+                   void *yield_arg);
+void uthread_sleep(unsigned int seconds);
+void uthread_usleep(unsigned int usecs);
+void uthread_has_blocked(struct uthread *uthread, int flags);
+void uthread_paused(struct uthread *uthread);
+
+/* Utility functions */
+bool __check_preempt_pending(uint32_t vcoreid);        /* careful: check the code */
+void uth_disable_notifs(void);
+void uth_enable_notifs(void);
+
+/* Helpers, which sched_entry() can call */
+void highjack_current_uthread(struct uthread *uthread);
+void run_current_uthread(void);
+void run_uthread(struct uthread *uthread);
+
+/* Asking for trouble with this API, when we just want stacktop (or whatever
+ * the SP will be). */
+static inline void init_uthread_ctx(struct uthread *uth, void (*entry)(void),
+                                    void *stack_bottom, uint32_t size)
+{
+       init_user_ctx(&uth->u_ctx, (long)entry, (long)(stack_bottom) + size);
+}
+
+#define uthread_set_tls_var(uth, name, val)                                    \
+({                                                                             \
+       typeof(val) __val = val;                                                   \
+       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
+       name = __val;                                                              \
+       end_access_tls_vars();                                                     \
+})
+
+#define uthread_get_tls_var(uth, name)                                         \
+({                                                                             \
+       typeof(name) val;                                                          \
+       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
+       val = name;                                                                \
+       end_access_tls_vars();                                                     \
+       val;                                                                       \
+})
+
+/* Generic Uthread Mutexes.  2LSs implement their own methods, but we need a
+ * 2LS-independent interface and default implementation. */
+uth_mutex_t uth_mutex_alloc(void);
+void uth_mutex_free(uth_mutex_t m);
+void uth_mutex_lock(uth_mutex_t m);
+void uth_mutex_unlock(uth_mutex_t m);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/vcore.h b/user/parlib/include/parlib/vcore.h
new file mode 100644 (file)
index 0000000..a965591
--- /dev/null
@@ -0,0 +1,306 @@
+#pragma once
+
+#include <parlib/arch/vcore.h>
+#include <parlib/arch/atomic.h>
+#include <sys/param.h>
+#include <string.h>
+#include <parlib/timing.h>
+#include <parlib/common.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+/* TODO: This is a complete hack, but necessary for vcore stuff to work for now
+ * The issue is that exit sometimes calls sys_yield(), and we can't recover from
+ * that properly under our vcore model (we shouldn't though).  We really need to
+ * rethink what sys_yield 'should' do when in multicore mode, or else come up 
+ * with a different syscall entirely. */
+#undef exit
+extern void _exit (int status);
+extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
+#define exit(status) _exit(status)
+/*****************************************************************************/
+
+#define LOG2_MAX_VCORES 6
+#define MAX_VCORES (1 << LOG2_MAX_VCORES)
+
+#define TRANSITION_STACK_PAGES 2
+#define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
+
+/* Defined in vcore.c */
+extern void vcore_entry();
+extern __thread bool __vcore_context;
+extern __thread int __vcoreid;
+extern __thread struct syscall __vcore_one_sysc;       /* see sys_change_vcore */
+
+/* Vcore API functions */
+static inline uint32_t max_vcores(void);
+static inline uint32_t num_vcores(void);
+static inline int vcore_id(void);
+static inline bool in_vcore_context(void);
+static inline bool in_multi_mode(void);
+static inline void __enable_notifs(uint32_t vcoreid);
+static inline void __disable_notifs(uint32_t vcoreid);
+static inline bool notif_is_enabled(uint32_t vcoreid);
+static inline bool vcore_is_mapped(uint32_t vcoreid);
+static inline bool vcore_is_preempted(uint32_t vcoreid);
+static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
+static inline bool preempt_is_pending(uint32_t vcoreid);
+static inline bool __preempt_is_pending(uint32_t vcoreid);
+static inline void *get_vcpd_tls_desc(uint32_t vcoreid);
+static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc);
+static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid);
+static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid);
+void vcore_lib_init(void);
+void vcore_change_to_m(void);
+int vcore_request(long nr_new_vcores);
+void vcore_yield(bool preempt_pending);
+void vcore_reenter(void (*entry_func)(void));
+void enable_notifs(uint32_t vcoreid);
+void disable_notifs(uint32_t vcoreid);
+void vcore_idle(void);
+void ensure_vcore_runs(uint32_t vcoreid);
+void cpu_relax_vc(uint32_t vcoreid);
+uint32_t get_vcoreid(void);
+bool check_vcoreid(const char *str, uint32_t vcoreid);
+void print_hw_tf(struct hw_trapframe *tf);
+void print_sw_tf(struct sw_trapframe *sw_tf);
+void print_user_context(struct user_context *ctx);
+
+/* This works so long as we don't dlopen parlib (which we never do) */
+#define get_tlsvar_linaddr(_vcoreid, _var)                                     \
+({                                                                             \
+       uintptr_t vc_tls_desc = (uintptr_t)get_vcpd_tls_desc(_vcoreid);            \
+       uintptr_t var_off = (uintptr_t)&_var - (uintptr_t)get_tls_desc();          \
+       (typeof(_var) *)(vc_tls_desc + var_off);                                   \
+})
+
+/* Static inlines */
+static inline uint32_t max_vcores(void)
+{
+       return MAX(1, MIN(__procinfo.max_vcores, MAX_VCORES));
+}
+
+static inline uint32_t num_vcores(void)
+{
+       return __procinfo.num_vcores;
+}
+
+static inline int vcore_id(void)
+{
+       return __vcoreid;
+}
+
+static inline bool in_vcore_context(void)
+{
+       return __vcore_context;
+}
+
+static inline bool in_multi_mode(void)
+{
+       return __procinfo.is_mcp;
+}
+
+/* Only call this if you know what you are doing. */
+static inline void __enable_notifs(uint32_t vcoreid)
+{
+       vcpd_of(vcoreid)->notif_disabled = FALSE;
+}
+
+static inline void __disable_notifs(uint32_t vcoreid)
+{
+       vcpd_of(vcoreid)->notif_disabled = TRUE;
+}
+
+static inline bool notif_is_enabled(uint32_t vcoreid)
+{
+       return !vcpd_of(vcoreid)->notif_disabled;
+}
+
+static inline bool vcore_is_mapped(uint32_t vcoreid)
+{
+       return __procinfo.vcoremap[vcoreid].valid;
+}
+
+/* We could also check for VC_K_LOCK, but that's a bit much. */
+static inline bool vcore_is_preempted(uint32_t vcoreid)
+{
+       struct preempt_data *vcpd = vcpd_of(vcoreid);
+       return atomic_read(&vcpd->flags) & VC_PREEMPTED;
+}
+
+static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
+{
+       return &__procdata.vcore_preempt_data[vcoreid];
+}
+
+/* Uthread's can call this in case they care if a preemption is coming.  If a
+ * preempt is incoming, this will return TRUE, if you are in uthread context.  A
+ * reasonable response for a uthread is to yield, and vcore_entry will deal with
+ * the preempt pending.
+ *
+ * If you call this from vcore context, it will do nothing.  In general, it's
+ * not safe to just yield (or do whatever you plan on doing) from arbitrary
+ * places in vcore context.  So we just lie about PP. */
+static inline bool preempt_is_pending(uint32_t vcoreid)
+{
+       if (in_vcore_context())
+               return FALSE;
+       return __preempt_is_pending(vcoreid);
+}
+
+static inline bool __preempt_is_pending(uint32_t vcoreid)
+{
+       return __procinfo.vcoremap[vcoreid].preempt_pending;
+}
+
+/* The kernel interface uses uintptr_t, but we have a lot of older code that
+ * uses void *, hence the casting. */
+static inline void *get_vcpd_tls_desc(uint32_t vcoreid)
+{
+       return (void*)__procdata.vcore_preempt_data[vcoreid].vcore_tls_desc;
+}
+
+static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc)
+{
+       __procdata.vcore_preempt_data[vcoreid].vcore_tls_desc = (uintptr_t)tls_desc;
+}
+
+static inline uint64_t vcore_account_resume_ticks(uint32_t vcoreid)
+{
+       return __procinfo.vcoremap[vcoreid].resume_ticks;
+}
+
+static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid)
+{
+       return tsc2nsec(vcore_account_resume_ticks(vcoreid));
+}
+
+static inline uint64_t vcore_account_total_ticks(uint32_t vcoreid)
+{
+       return __procinfo.vcoremap[vcoreid].total_ticks;
+}
+
+static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid)
+{
+       return tsc2nsec(vcore_account_total_ticks(vcoreid));
+}
+
+static inline uint64_t vcore_account_uptime_ticks(uint32_t vcoreid)
+{
+       uint64_t resume = __procinfo.vcoremap[vcoreid].resume_ticks; 
+       uint64_t total = __procinfo.vcoremap[vcoreid].total_ticks; 
+       uint64_t now = read_tsc();
+       return now - resume + total;
+}
+
+static inline uint64_t vcore_account_uptime_nsec(uint32_t vcoreid)
+{
+       return tsc2nsec(vcore_account_uptime_ticks(vcoreid));
+}
+
+#ifndef __PIC__
+
+#define begin_safe_access_tls_vars()
+
+#define end_safe_access_tls_vars()
+
+#else
+
+#include <features.h>
+
+/* These macro acrobatics trick the compiler into not caching the (linear)
+ * address of TLS variables across loads/stores of the TLS descriptor, in lieu
+ * of a "TLS cmb()". */
+#define begin_safe_access_tls_vars()                                           \
+{                                                                              \
+       void __attribute__((noinline, optimize("O0")))                             \
+       safe_access_tls_var_internal() {                                           \
+               asm("");                                                               \
+
+#define end_safe_access_tls_vars()                                             \
+       } safe_access_tls_var_internal();                                          \
+}
+
+#endif // __PIC__
+
+/* Switches into the TLS 'tls_desc'.  Capable of being called from either
+ * uthread or vcore context.  Pairs with end_access_tls_vars(). */
+#define begin_access_tls_vars(tls_desc)                                        \
+{                                                                              \
+       struct uthread *caller;                                                    \
+       uint32_t vcoreid;                                                          \
+       void *temp_tls_desc;                                                       \
+       bool invcore = in_vcore_context();                                         \
+       if (!invcore) {                                                            \
+               caller = current_uthread;                                              \
+               /* If you have no current_uthread, you might be called too early in the
+                * process's lifetime.  Make sure something like uthread_slim_init() has
+                * been run. */                                                        \
+               assert(caller);                                                        \
+               /* We need to disable notifs here (in addition to not migrating), since
+                * we could get interrupted when we're in the other TLS, and when the
+                * vcore restarts us, it will put us in our old TLS, not the one we were
+                * in when we were interrupted.  We need to not migrate, since once we
+                * know the vcoreid, we depend on being on the same vcore throughout.*/\
+               caller->flags |= UTHREAD_DONT_MIGRATE;                                 \
+               /* Not concerned about cross-core memory ordering, so no CPU mbs needed.
+                * The cmb is to prevent the compiler from issuing the vcore read before
+                * the DONT_MIGRATE write. */                                          \
+               cmb();                                                                 \
+               vcoreid = vcore_id();                                                  \
+               disable_notifs(vcoreid);                                               \
+       } else { /* vcore context */                                               \
+               vcoreid = vcore_id();                                                  \
+       }                                                                          \
+       temp_tls_desc = get_tls_desc();                                            \
+       set_tls_desc(tls_desc);                                                    \
+       begin_safe_access_tls_vars();
+
+#define end_access_tls_vars()                                                  \
+       end_safe_access_tls_vars();                                                \
+       set_tls_desc(temp_tls_desc);                                               \
+       if (!invcore) {                                                            \
+               /* Note we reenable migration before enabling notifs, which is reverse
+                * from how we disabled notifs.  We must enabling migration before
+                * enabling notifs.  See 6c7fb12 and 5e4825eb4 for details. */         \
+               caller->flags &= ~UTHREAD_DONT_MIGRATE;                                \
+               cmb();  /* turn off DONT_MIGRATE before enabling notifs */             \
+               enable_notifs(vcoreid);                                                \
+       }                                                                          \
+}
+
+#define safe_set_tls_var(name, val)                                            \
+({                                                                             \
+       begin_safe_access_tls_vars();                                              \
+       name = val;                                                                \
+       end_safe_access_tls_vars();                                                \
+})
+
+#define safe_get_tls_var(name)                                                 \
+({                                                                             \
+       typeof(name) __val;                                                        \
+       begin_safe_access_tls_vars();                                              \
+       __val = name;                                                              \
+       end_safe_access_tls_vars();                                                \
+       __val;                                                                     \
+})
+
+#define vcore_set_tls_var(name, val)                                           \
+({                                                                             \
+       typeof(val) __val = val;                                                   \
+       begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
+       name = __val;                                                              \
+       end_access_tls_vars();                                                     \
+})
+
+#define vcore_get_tls_var(name)                                                \
+({                                                                             \
+       typeof(name) val;                                                          \
+       begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
+       val = name;                                                                \
+       end_access_tls_vars();                                                     \
+       val;                                                                       \
+})
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/waitfreelist.h b/user/parlib/include/parlib/waitfreelist.h
new file mode 100644 (file)
index 0000000..da527c8
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * Andrew Waterman <waterman@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * A wait-free unordered list data structure.
+ * 
+ */
+
+#pragma once
+
+#include <string.h>
+
+__BEGIN_DECLS
+
+struct wfl_entry {
+  struct wfl_entry *next;
+  void *data;
+};
+
+struct wfl {
+  struct wfl_entry *head;
+  struct wfl_entry first;
+};
+
+#define WFL_INITIALIZER(list) {&(list).first, {0, 0}}
+
+void wfl_init(struct wfl *list);
+void wfl_destroy(struct wfl *list);
+size_t wfl_capacity(struct wfl *list);
+size_t wfl_size(struct wfl *list);
+void wfl_insert(struct wfl *list, void *data);
+void *wfl_remove(struct wfl *list);
+size_t wfl_remove_all(struct wfl *list, void *data);
+
+/* Iterate over list.  Safe w.r.t. inserts, but not w.r.t. removals. */
+#define wfl_foreach_unsafe(elm, list) \
+  for (struct wfl_entry *_p = (list)->head; \
+       elm = _p == NULL ? NULL : _p->data, _p != NULL; \
+       _p = _p->next) \
+    if (elm)
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/arch.h b/user/parlib/include/parlib/x86/arch.h
new file mode 100644 (file)
index 0000000..0392ad1
--- /dev/null
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <ros/trapframe.h>
+#include <ros/arch/mmu.h>
+
+__BEGIN_DECLS
+
+#define ARCH_CL_SIZE 64
+#ifdef __x86_64__
+
+#define internal_function 
+#define X86_REG_BP                                     "rbp"
+#define X86_REG_SP                                     "rsp"
+#define X86_REG_IP                                     "rip"
+#define X86_REG_AX                                     "rax"
+#define X86_REG_BX                                     "rbx"
+#define X86_REG_CX                                     "rcx"
+#define X86_REG_DX                                     "rdx"
+
+#else /* 32 bit */
+
+#define internal_function   __attribute ((regparm (3), stdcall))
+#define X86_REG_BP                                     "ebp"
+#define X86_REG_SP                                     "esp"
+#define X86_REG_IP                                     "eip"
+#define X86_REG_AX                                     "eax"
+#define X86_REG_BX                                     "ebx"
+#define X86_REG_CX                                     "ecx"
+#define X86_REG_DX                                     "edx"
+
+#endif /* 64bit / 32bit */
+
+/* Make sure you subtract off/save enough space at the top of the stack for
+ * whatever you compiler might want to use when calling a noreturn function or
+ * to handle a HW spill or whatever. */
+static inline void __attribute__((always_inline))
+set_stack_pointer(void *sp)
+{
+       asm volatile("mov %0,%%"X86_REG_SP"" : : "r"(sp) : "memory", X86_REG_SP);
+}
+
+static inline void breakpoint(void)
+{
+       asm volatile("int3");
+}
+
+static inline uint64_t read_tsc(void)
+{
+       uint32_t edx, eax;
+       asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
+       return (uint64_t)edx << 32 | eax;
+}
+
+/* Check out k/a/x86/rdtsc_test.c for more info */
+static inline uint64_t read_tsc_serialized(void)
+{
+       asm volatile("lfence"); /* mfence on amd */
+       return read_tsc();
+}
+
+static inline void cpu_relax(void)
+{
+       asm volatile("pause" : : : "memory");
+}
+
+static inline void save_fp_state(struct ancillary_state *silly)
+{
+       asm volatile("fxsave %0" : : "m"(*silly));
+}
+
+static inline void restore_fp_state(struct ancillary_state *silly)
+{
+       asm volatile("fxrstor %0" : : "m"(*silly));
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/atomic.h b/user/parlib/include/parlib/x86/atomic.h
new file mode 100644 (file)
index 0000000..da31c58
--- /dev/null
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/atomic.h>
+
+__BEGIN_DECLS
+
+static inline void atomic_init(atomic_t *number, long val);
+static inline long atomic_read(atomic_t *number);
+static inline void atomic_set(atomic_t *number, long val);
+static inline void atomic_inc(atomic_t *number);
+static inline void atomic_dec(atomic_t *number);
+static inline long atomic_fetch_and_add(atomic_t *number, long val);
+static inline long atomic_swap(atomic_t *addr, long val);
+static inline void *atomic_swap_ptr(void **addr, void *val);
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
+static inline void atomic_andb(volatile uint8_t *number, uint8_t mask);
+static inline void atomic_orb(volatile uint8_t *number, uint8_t mask);
+
+/* Inlined functions declared above */
+static inline void atomic_init(atomic_t *number, long val)
+{
+       asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
+}
+
+static inline long atomic_read(atomic_t *number)
+{
+       long val;
+       asm volatile("mov %1,%0" : "=r"(val) : "m"(*number));
+       return val;
+}
+
+static inline void atomic_set(atomic_t *number, long val)
+{
+       asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
+}
+
+static inline void atomic_inc(atomic_t *number)
+{
+       __sync_fetch_and_add(number, 1);
+}
+
+static inline void atomic_dec(atomic_t *number)
+{
+       __sync_fetch_and_sub(number, 1);
+}
+
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
+{
+       return (long)__sync_fetch_and_add(number, val);
+}
+
+static inline long atomic_swap(atomic_t *addr, long val)
+{
+       /* This poorly named function does an xchg */
+       return (long)__sync_lock_test_and_set(addr, val);
+}
+
+static inline void *atomic_swap_ptr(void **addr, void *val)
+{
+       return (void*)__sync_lock_test_and_set(addr, val);
+}
+
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
+{
+       return (uint32_t)__sync_lock_test_and_set(addr, val);
+}
+
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
+}
+
+static inline void atomic_andb(volatile uint8_t *number, uint8_t mask)
+{
+       __sync_fetch_and_and(number, mask);
+}
+
+static inline void atomic_orb(volatile uint8_t *number, uint8_t mask)
+{
+       __sync_fetch_and_or(number, mask);
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/bitmask.h b/user/parlib/include/parlib/x86/bitmask.h
new file mode 100644 (file)
index 0000000..95a8593
--- /dev/null
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <parlib/arch/atomic.h>
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+#define DECL_BITMASK(name, size) \
+       uint8_t (name)[BYTES_FOR_BITMASK((size))]
+
+#define BYTES_FOR_BITMASK(size) \
+       (((size) - 1) / 8 + 1)
+
+#define BYTES_FOR_BITMASK_WITH_CHECK(size) \
+       ((size) ? ((size) - (1)) / (8) + (1) : (0))
+
+static bool GET_BITMASK_BIT(uint8_t* name, size_t bit) 
+{
+       return (((name)[(bit)/8] & (1 << ((bit) % 8))) ? 1 : 0);
+}
+
+#define SET_BITMASK_BIT(name, bit) \
+       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
+/*
+static void SET_BITMASK_BIT(uint8_t* name, size_t bit)
+{
+       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
+}
+*/
+
+#define CLR_BITMASK_BIT(name, bit) \
+       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
+/*
+static void CLR_BITMASK_BIT(uint8_t* name, size_t bit) 
+{
+       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
+}
+*/
+
+static void SET_BITMASK_BIT_ATOMIC(uint8_t* name, size_t bit) 
+{
+       (atomic_orb(&(name)[(bit)/8], (1 << ((bit) % 8))));
+}
+
+#define CLR_BITMASK_BIT_ATOMIC(name, bit) \
+       (atomic_andb(&(name)[(bit)/8], ~(1 << ((bit) % 8))))
+
+#define CLR_BITMASK(name, size) \
+({ \
+       memset((void*)((uintptr_t)(name)), 0, BYTES_FOR_BITMASK((size))); \
+})
+
+#define FILL_BITMASK(name, size) \
+({ \
+       memset((void*)((uintptr_t)(name)), 255, BYTES_FOR_BITMASK((size))); \
+       (name)[BYTES_FOR_BITMASK((size))-1] >>= (((size) % 8) ? (8 - ((size) % 8)) : 0 ); \
+}) 
+
+#define COPY_BITMASK(newmask, oldmask, size) \
+({ \
+       memcpy((void*)((uintptr_t)(newmask)), \
+           (void*)((uintptr_t)(oldmask)), \
+           BYTES_FOR_BITMASK((size))); \
+})
+
+// this checks the entire last byte, so keep it 0 in the other macros
+#define BITMASK_IS_CLEAR(name, size) ({ \
+       uint32_t __n = BYTES_FOR_BITMASK((size)); \
+       bool clear = 1; \
+       while (__n-- > 0) { \
+               if ((name)[__n]) { \
+                       clear = 0; \
+                       break;\
+               }\
+       } \
+       clear; })
+
+static inline bool BITMASK_IS_FULL(uint8_t* map, size_t size)
+{
+       int _size = size;
+       for (int i = 0; i < BYTES_FOR_BITMASK(size); i++) {
+               for (int j = 0; j < MIN(8,_size); j++)
+                       if(!((map[i] >> j) &1))
+                               return FALSE;
+                       _size--;
+       }
+       return TRUE;
+}
+
+#define PRINT_BITMASK(name, size) { \
+       int i;  \
+       int _size = size; \
+       for (i = 0; i < BYTES_FOR_BITMASK(size); i++) { \
+               int j;  \
+               for (j = 0; j < MIN(8,_size); j++) \
+                       printf("%x", ((name)[i] >> j) & 1);     \
+                       _size--; \
+       } \
+       printf("\n"); \
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/trap.h b/user/parlib/include/parlib/x86/trap.h
new file mode 100644 (file)
index 0000000..541fd04
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Arch-specific defines for traps, vmexits, and similar things */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+
+__BEGIN_DECLS
+
+#define HW_TRAP_DIV_ZERO               0
+#define HW_TRAP_GP_FAULT               13
+#define HW_TRAP_PAGE_FAULT             14
+
+static bool has_refl_fault(struct user_context *ctx)
+{
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               return ctx->tf.hw_tf.tf_padding3 == ROS_ARCH_REFL_ID;
+       case ROS_SW_CTX:
+               return FALSE;
+       case ROS_VM_CTX:
+               return ctx->tf.vm_tf.tf_flags & VMCTX_FL_HAS_FAULT ? TRUE : FALSE;
+       }
+}
+
+static void clear_refl_fault(struct user_context *ctx)
+{
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               ctx->tf.hw_tf.tf_padding3 = 0;
+               break;
+       case ROS_SW_CTX:
+               /* Should never attempt this on an SW ctx */
+               assert(0);
+               break;
+       case ROS_VM_CTX:
+               ctx->tf.vm_tf.tf_flags &= ~VMCTX_FL_HAS_FAULT;
+               break;
+       }
+}
+
+static unsigned int __arch_refl_get_nr(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_trapno;
+}
+
+static unsigned int __arch_refl_get_err(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_err;
+}
+
+static unsigned long __arch_refl_get_aux(struct user_context *ctx)
+{
+       return ((unsigned long)ctx->tf.hw_tf.tf_padding5 << 32) |
+              ctx->tf.hw_tf.tf_padding4;
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/vcore.h b/user/parlib/include/parlib/x86/vcore.h
new file mode 100644 (file)
index 0000000..fdd40ca
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#define PARLIB_ARCH_VCORE_H
+
+#ifdef __x86_64__
+#include <parlib/arch/vcore64.h>
+#else
+#include <parlib/arch/vcore32.h>
+#endif
+
+__BEGIN_DECLS
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/vcore32.h b/user/parlib/include/parlib/x86/vcore32.h
new file mode 100644 (file)
index 0000000..483c97a
--- /dev/null
@@ -0,0 +1,357 @@
+#pragma once
+
+#ifndef PARLIB_ARCH_VCORE_H
+#error "Do not include include vcore32.h directly"
+#endif
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+#include <ros/procdata.h>
+#include <ros/syscall.h>
+#include <ros/arch/mmu.h>
+#include <sys/tls.h>
+
+__BEGIN_DECLS
+
+/* Here's how the HW popping works:  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_disabled, 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 uthread's stack will look like (growing down):
+ *
+ * Target ESP -> |   u_thread's old stuff   | the future %esp, tf->tf_esp
+ *               |   new eip                | 0x04 below %esp (one slot is 0x04)
+ *               |   eflags space           | 0x08 below
+ *               |   eax save space         | 0x0c below
+ *               |   actual syscall         | 0x10 below (0x30 space)
+ *               |   *sysc ptr to syscall   | 0x40 below (0x10 + 0x30)
+ *               |   notif_pending_loc      | 0x44 below (0x10 + 0x30)
+ *               |   notif_disabled_loc     | 0x48 below (0x10 + 0x30)
+ *
+ * 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.
+ *
+ * Related to that is whether or not our stack pointer is sufficiently far down
+ * so that restarting *this* code won't clobber shit we need later.  The way we
+ * do this is that we do any "stack jumping" before we enable interrupts/notifs.
+ * These jumps are when we directly modify esp, specifically in the down
+ * direction (subtracts).  Adds would be okay.
+ *
+ * Another related concern is the storage for sysc.  It used to be on the
+ * vcore's stack, but if an interrupt comes in before we use it, we trash the
+ * vcore's stack (and thus the storage for sysc!).  Instead, we put it on the
+ * stack of the user tf.  Moral: don't touch a vcore's stack with notifs
+ * enabled. */
+
+/* Helper for writing the info we need later to the u_tf's stack.  Note, this
+ * could get fucked if the struct syscall isn't a multiple of 4-bytes.  Also,
+ * note this goes backwards, since memory reads up the stack. */
+struct restart_helper {
+       uint32_t                                        notif_disab_loc;
+       uint32_t                                        notif_pend_loc;
+       struct syscall                          *sysc;
+       struct syscall                          local_sysc;     /* unused for now */
+       uint32_t                                        eax_save;
+       uint32_t                                        eflags;
+       uint32_t                                        eip;
+};
+
+/* Static syscall, used for self-notifying.  We never wait on it, and we
+ * actually might submit it multiple times in parallel on different cores!
+ * While this may seem dangerous, the kernel needs to be able to handle this
+ * scenario.  It's also important that we never wait on this, since for all but
+ * the first call, the DONE flag will be set.  (Set once, then never reset) */
+extern struct syscall vc_entry;        /* in x86/vcore.c */
+
+static inline void pop_hw_tf(struct hw_trapframe *tf, uint32_t vcoreid)
+{
+       struct restart_helper *rst;
+       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;
+       }
+       /* The stuff we need to write will be below the current stack of the utf */
+       rst = (struct restart_helper*)((void*)tf->tf_esp -
+                                      sizeof(struct restart_helper));
+       /* Fill in the info we'll need later */
+       rst->notif_disab_loc = (uint32_t)&vcpd->notif_disabled;
+       rst->notif_pend_loc = (uint32_t)&vcpd->notif_pending;
+       rst->sysc = &vc_entry;
+       rst->eax_save = 0;                      /* avoid bugs */
+       rst->eflags = tf->tf_eflags;
+       rst->eip = tf->tf_eip;
+
+       asm volatile ("movl %0,%%esp;        " /* jump esp to the utf */
+                     "popal;                " /* restore normal registers */
+                     "addl $0x24,%%esp;     " /* move to the esp slot in the tf */
+                     "popl %%esp;           " /* change to the utf's %esp */
+                     "subl $0x08,%%esp;     " /* move esp to below eax's slot */
+                     "pushl %%eax;          " /* save eax, will clobber soon */
+                                 "movl %2,%%eax;        " /* sizeof struct syscall */
+                                 "addl $0x0c,%%eax;     " /* more offset btw eax/notif_en_loc*/
+                     "subl %%eax,%%esp;     " /* move to notif_en_loc slot */
+                     "popl %%eax;           " /* load notif_disabled addr */
+                     "movb $0x00,(%%eax);   " /* enable notifications */
+                                 /* Need a wrmb() here so the write of enable_notif can't pass
+                                  * the read of notif_pending (racing with a potential
+                                  * cross-core call with proc_notify()). */
+                                 "lock addl $0,(%%esp); " /* LOCK is a CPU mb() */
+                                 /* From here down, we can get interrupted and restarted */
+                     "popl %%eax;           " /* get notif_pending status */
+                     "testb $0x01,(%%eax);  " /* test if a notif is pending */
+                     "jz 1f;                " /* if not pending, skip syscall */
+                                 /* Actual syscall.  Note we don't wait on the async call */
+                     "popl %%eax;           " /* &sysc, trap arg0 */
+                     "pushl %%edx;          " /* save edx, will be trap arg1 */
+                     "movl $0x1,%%edx;      " /* sending one async syscall: arg1 */
+                     "int %1;               " /* fire the syscall */
+                     "popl %%edx;           " /* restore regs after syscall */
+                     "jmp 2f;               " /* skip 1:, already popped */
+                                 "1: popl %%eax;        " /* discard &sysc (on non-sc path) */
+                     "2: addl %2,%%esp;     " /* jump over the sysc (both paths) */
+                     "popl %%eax;           " /* restore tf's %eax */
+                                 "popfl;                " /* restore utf's eflags */
+                     "ret;                  " /* return to the new PC */
+                     :
+                     : "g"(tf), "i"(T_SYSCALL), "i"(sizeof(struct syscall))
+                     : "memory");
+}
+
+static inline void pop_sw_tf(struct sw_trapframe *sw_tf, uint32_t vcoreid)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+
+       /* Restore callee-saved FPU state.  We need to clear exceptions before
+        * reloading the FP CW, in case the new CW unmasks any.  We also need to
+        * reset the tag word to clear out the stack.
+        *
+        * The main issue here is that while our context was saved in an
+        * ABI-complaint manner, we may be starting up on a somewhat random FPU
+        * state.  Having gibberish in registers isn't a big deal, but some of the
+        * FP environment settings could cause trouble.  If fnclex; emms isn't
+        * enough, we could also save/restore the entire FP env with fldenv, or do
+        * an fninit before fldcw. */
+       asm volatile ("ldmxcsr %0" : : "m"(sw_tf->tf_mxcsr));
+       asm volatile ("fnclex; emms; fldcw %0" : : "m"(sw_tf->tf_fpucw));
+       /* Basic plan: restore all regs, off ecx as the sw_tf.  Switch to the new
+        * stack, push the PC so we can pop it later.  Use eax and edx for the
+        * locations of sysc and vcpd.  Once on the new stack, we enable notifs,
+        * check if we missed one, and if so, self notify. */
+       asm volatile ("movl 0x00(%0),%%ebp;  " /* restore regs */
+                     "movl 0x04(%0),%%ebx;  "
+                     "movl 0x08(%0),%%esi;  "
+                     "movl 0x0c(%0),%%edi;  "
+                     "movl 0x10(%0),%%esp;  " /* jump to future stack */
+                     "pushl 0x14(%0);       " /* save PC for future ret */
+                     "movl %2,%%ecx;        " /* vcpd loc into ecx */
+                     "addl %4,%%ecx;        " /* notif_disabled loc into ecx */
+                     "movb $0x00,(%%ecx);   " /* enable notifications */
+                     /* Need a wrmb() here so the write of enable_notif can't pass
+                      * the read of notif_pending (racing with a potential
+                      * cross-core call with proc_notify()). */
+                     "lock addl $0,(%%esp); " /* LOCK is a CPU mb() */
+                     /* From here down, we can get interrupted and restarted */
+                     "movl %2,%%ecx;        " /* vcpd loc into ecx */
+                     "addl %5,%%ecx;        " /* notif_pending loc into ecx */
+                     "testb $0x01,(%%ecx);  " /* test if a notif is pending */
+                     "jz 1f;                " /* if not pending, skip syscall */
+                     /* Actual syscall.  Note we don't wait on the async call.
+                      * &sysc is already in eax (trap arg0). */
+                     "movl $0x1,%%edx;      " /* sending one async syscall: arg1 */
+                     "int %3;               " /* fire the syscall */
+                     "1: ret;               " /* retaddr was pushed earlier */
+                     :
+                     : "c"(sw_tf),
+                       "a"(&vc_entry),
+                       "d"(vcpd),
+                       "i"(T_SYSCALL),
+                       "i"(offsetof(struct preempt_data, notif_disabled)),
+                       "i"(offsetof(struct preempt_data, notif_pending))
+                     : "memory");
+}
+
+/* Pops a user context, reanabling notifications at the same time.  A Userspace
+ * scheduler can call this when transitioning off the transition stack.
+ *
+ * At some point in vcore context before calling this, you need to clear
+ * notif_pending (do this by calling handle_events()).  As a potential
+ * optimization, consider clearing the notif_pending flag / handle_events again
+ * (right before popping), right 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. */
+static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
+{
+       if (ctx->type == ROS_HW_CTX)
+               pop_hw_tf(&ctx->tf.hw_tf, vcoreid);
+       else
+               pop_sw_tf(&ctx->tf.sw_tf, vcoreid);
+}
+
+/* Like the regular pop_user_ctx, but this one doesn't check or clear
+ * notif_pending.  The only case where we use this is when an IRQ/notif
+ * interrupts a uthread that is in the process of disabling notifs. */
+static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+       struct restart_helper *rst;
+       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;
+       }
+       /* The stuff we need to write will be below the current stack of the utf */
+       rst = (struct restart_helper*)((void*)tf->tf_esp -
+                                      sizeof(struct restart_helper));
+       /* Fill in the info we'll need later */
+       rst->notif_disab_loc = (uint32_t)&vcpd->notif_disabled;
+       rst->eax_save = 0;                      /* avoid bugs */
+       rst->eflags = tf->tf_eflags;
+       rst->eip = tf->tf_eip;
+
+       asm volatile ("movl %0,%%esp;        " /* jump esp to the utf */
+                     "popal;                " /* restore normal registers */
+                     "addl $0x24,%%esp;     " /* move to the esp slot in the tf */
+                     "popl %%esp;           " /* change to the utf's %esp */
+                     "subl $0x08,%%esp;     " /* move esp to below eax's slot */
+                     "pushl %%eax;          " /* save eax, will clobber soon */
+                                 "movl %2,%%eax;        " /* sizeof struct syscall */
+                                 "addl $0x0c,%%eax;     " /* more offset btw eax/notif_en_loc*/
+                     "subl %%eax,%%esp;     " /* move to notif_en_loc slot */
+                     "popl %%eax;           " /* load notif_disabled addr */
+                     "movb $0x00,(%%eax);   " /* enable notifications */
+                                 /* Here's where we differ from the regular pop_user_ctx().
+                                  * We do the same pops/esp moves, just to keep things similar
+                                  * and simple, but don't do test, clear notif_pending, or
+                                  * call a syscall. */
+                                 /* From here down, we can get interrupted and restarted */
+                     "popl %%eax;           " /* get notif_pending status */
+                                 "popl %%eax;           " /* discard &sysc (on non-sc path) */
+                     "addl %2,%%esp;        " /* jump over the sysc (both paths) */
+                     "popl %%eax;           " /* restore tf's %eax */
+                                 "popfl;                " /* restore utf's eflags */
+                     "ret;                  " /* return to the new PC */
+                     :
+                     : "g"(tf), "i"(T_SYSCALL), "i"(sizeof(struct syscall))
+                     : "memory");
+}
+
+/* Save's a SW context, setting the PC to the end of this function.  We only
+ * save callee-saved registers (of the sysv abi).  The compiler knows to save
+ * the others via the input/clobber lists.
+ *
+ * Callers of this function need to have at least one
+ * 'calling-convention-compliant' function call between this and any floating
+ * point, so that the compiler saves any caller-saved FP before getting to
+ * here.
+ *
+ * To some extent, TLS is 'callee-saved', in that no one ever expects it to
+ * change.  We handle uthread TLS changes separately, since we often change to
+ * them early to set some variables.  Arguably we should do this different. */
+static inline void save_user_ctx(struct user_context *ctx)
+{
+       struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
+       long dummy;
+       ctx->type = ROS_SW_CTX;
+       asm volatile ("stmxcsr %0" : "=m"(sw_tf->tf_mxcsr));
+       asm volatile ("fnstcw %0" : "=m"(sw_tf->tf_fpucw));
+       /* Pretty simple: save all the regs, IAW the sys-v ABI */
+       asm volatile ("movl %%ebp,0x00(%0);   "
+                     "movl %%ebx,0x04(%0);   "
+                     "movl %%esi,0x08(%0);   "
+                     "movl %%edi,0x0c(%0);   "
+                     "movl %%esp,0x10(%0);   "
+                     "leal 1f,%%eax;         " /* get future eip */
+                     "movl %%eax,0x14(%0);   "
+                     "1:                     " /* where this tf will restart */
+                     : "=c"(dummy)     /* force clobber for ecx */
+                     : "c"(sw_tf)
+                     : "eax", "edx", "memory", "cc");
+} __attribute__((always_inline, returns_twice))
+
+/* The old version, kept around for testing */
+static inline void save_user_ctx_hw(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       memset(tf, 0, sizeof(struct hw_trapframe)); /* sanity */
+       /* set CS and make sure eflags is okay */
+       tf->tf_cs = GD_UT | 3;
+       tf->tf_eflags = 0x00000200; /* interrupts enabled.  bare minimum eflags. */
+       /* Save the regs and the future esp. */
+       asm volatile("movl %%esp,(%0);       " /* save esp in it's slot*/
+                    "pushl %%eax;           " /* temp save eax */
+                    "leal 1f,%%eax;         " /* get future eip */
+                    "movl %%eax,(%1);       " /* store future eip */
+                    "popl %%eax;            " /* restore eax */
+                    "movl %2,%%esp;         " /* move to the beginning of the tf */
+                    "addl $0x20,%%esp;      " /* move to after the push_regs */
+                    "pushal;                " /* save regs */
+                    "addl $0x44,%%esp;      " /* move to esp slot */
+                    "popl %%esp;            " /* restore esp */
+                    "1:                     " /* where this tf will restart */
+                    : 
+                    : "g"(&tf->tf_esp), "g"(&tf->tf_eip), "g"(tf)
+                    : "eax", "memory", "cc");
+} __attribute__((always_inline, returns_twice))
+
+static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt,
+                                 uint32_t stack_top)
+{
+       struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
+       ctx->type = ROS_SW_CTX;
+       /* No need to bother with setting the other GP registers; the called
+        * function won't care about their contents. */
+       sw_tf->tf_esp = stack_top;
+       sw_tf->tf_eip = entry_pt;
+       sw_tf->tf_mxcsr = 0x00001f80;   /* x86 default mxcsr */
+       sw_tf->tf_fpucw = 0x037f;               /* x86 default FP CW */
+}
+
+static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
+{
+       if (ctx->type == ROS_HW_CTX)
+               return ctx->tf.hw_tf.tf_esp;
+       else
+               return ctx->tf.sw_tf.tf_esp;
+}
+
+// this is how we get our thread id on entry.
+#define __vcore_id_on_entry \
+({ \
+       register int temp asm ("ebx"); \
+       temp; \
+})
+
+static bool has_refl_fault(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_padding3 == ROS_ARCH_REFL_ID;
+}
+
+static void clear_refl_fault(struct user_context *ctx)
+{
+       ctx->tf.hw_tf.tf_padding3 = 0;
+}
+
+static unsigned int __arch_refl_get_nr(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_trapno;
+}
+
+static unsigned int __arch_refl_get_err(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_err;
+}
+
+static unsigned long __arch_refl_get_aux(struct user_context *ctx)
+{
+       return ctx->tf.hw_tf.tf_regs.reg_oesp;
+}
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/x86/vcore64.h b/user/parlib/include/parlib/x86/vcore64.h
new file mode 100644 (file)
index 0000000..b1a8bcd
--- /dev/null
@@ -0,0 +1,391 @@
+#pragma once
+
+#ifndef PARLIB_ARCH_VCORE_H
+#error "Do not include include vcore32.h directly"
+#endif
+
+#include <parlib/common.h>
+#include <ros/trapframe.h>
+#include <ros/procdata.h>
+#include <ros/syscall.h>
+#include <ros/arch/mmu.h>
+#include <sys/tls.h>
+
+__BEGIN_DECLS
+
+/* Here's how the HW popping works:  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_disabled, 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 uthread's stack will look like (growing down):
+ *
+ * Target RSP -> |   u_thread's old stuff   | the future %rsp, tf->tf_rsp
+ *               |   new rip                | 0x08 below %rsp (one slot is 0x08)
+ *               |   rflags space           | 0x10 below
+ *               |   rdi save space         | 0x18 below
+ *               |   *sysc ptr to syscall   | 0x20 below
+ *               |   notif_pending_loc      | 0x28 below
+ *               |   notif_disabled_loc     | 0x30 below
+ *
+ * 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.
+ *
+ * Related to that is whether or not our stack pointer is sufficiently far down
+ * so that restarting *this* code won't clobber shit we need later.  The way we
+ * do this is that we do any "stack jumping" before we enable interrupts/notifs.
+ * These jumps are when we directly modify rsp, specifically in the down
+ * direction (subtracts).  Adds would be okay.
+ *
+ * Another 64-bit concern is the red-zone.  The AMD64 ABI allows the use of
+ * space below the stack pointer by regular programs.  If we allowed this, we
+ * would clobber that space when we do our TF restarts, much like with OSs and
+ * IRQ handlers.  Thus we have the cross compiler automatically disabling the
+ * redzone (-mno-red-zone is a built-in option).
+ *
+ * When compared to the 32 bit code, notice we use rdi, instead of eax, for our
+ * work.  This is because rdi is the arg0 of a syscall.  Using it saves us some
+ * extra moves, since we need to pop the *sysc before saving any other
+ * registers. */
+
+/* Helper for writing the info we need later to the u_tf's stack.  Also, note
+ * this goes backwards, since memory reads up the stack. */
+struct restart_helper {
+       void                                            *notif_disab_loc;
+       void                                            *notif_pend_loc;
+       struct syscall                          *sysc;
+       uint64_t                                        rdi_save;
+       uint64_t                                        rflags;
+       uint64_t                                        rip;
+};
+
+/* Static syscall, used for self-notifying.  We never wait on it, and we
+ * actually might submit it multiple times in parallel on different cores!
+ * While this may seem dangerous, the kernel needs to be able to handle this
+ * scenario.  It's also important that we never wait on this, since for all but
+ * the first call, the DONE flag will be set.  (Set once, then never reset) */
+extern struct syscall vc_entry;        /* in x86/vcore.c */
+
+static inline void pop_hw_tf(struct hw_trapframe *tf, uint32_t vcoreid)
+{
+       struct restart_helper *rst;
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       /* The stuff we need to write will be below the current stack of the utf */
+       rst = (struct restart_helper*)((void*)tf->tf_rsp -
+                                      sizeof(struct restart_helper));
+       /* Fill in the info we'll need later */
+       rst->notif_disab_loc = &vcpd->notif_disabled;
+       rst->notif_pend_loc = &vcpd->notif_pending;
+       rst->sysc = &vc_entry;
+       rst->rdi_save = 0;                      /* avoid bugs */
+       rst->rflags = tf->tf_rflags;
+       rst->rip = tf->tf_rip;
+
+       asm volatile ("movq %0, %%rsp;       " /* jump rsp to the utf */
+                     "popq %%rax;           " /* restore registers */
+                     "popq %%rbx;           "
+                     "popq %%rcx;           "
+                     "popq %%rdx;           "
+                     "popq %%rbp;           "
+                     "popq %%rsi;           "
+                     "popq %%rdi;           "
+                     "popq %%r8;            "
+                     "popq %%r9;            "
+                     "popq %%r10;           "
+                     "popq %%r11;           "
+                     "popq %%r12;           "
+                     "popq %%r13;           "
+                     "popq %%r14;           "
+                     "popq %%r15;           "
+                     "addq $0x28, %%rsp;    " /* move to the rsp slot in the tf */
+                     "popq %%rsp;           " /* change to the utf's %rsp */
+                     "subq $0x10, %%rsp;    " /* move rsp to below rdi's slot */
+                     "pushq %%rdi;          " /* save rdi, will clobber soon */
+                     "subq $0x18, %%rsp;    " /* move to notif_dis_loc slot */
+                     "popq %%rdi;           " /* load notif_disabled addr */
+                     "movb $0x00, (%%rdi);  " /* enable notifications */
+                                 /* Need a wrmb() here so the write of enable_notif can't pass
+                                  * the read of notif_pending (racing with a potential
+                                  * cross-core call with proc_notify()). */
+                                 "lock addq $0, (%%rdi);" /* LOCK is a CPU mb() */
+                                 /* From here down, we can get interrupted and restarted */
+                     "popq %%rdi;           " /* get notif_pending status loc */
+                     "testb $0x01, (%%rdi); " /* test if a notif is pending */
+                     "jz 1f;                " /* if not pending, skip syscall */
+                                 /* Actual syscall.  Note we don't wait on the async call */
+                     "popq %%rdi;           " /* &sysc, trap arg0 */
+                     "pushq %%rsi;          " /* save rax, will be trap arg1 */
+                     "pushq %%rax;          " /* save rax, will be trap ret */
+                     "movq $0x1, %%rsi;     " /* sending one async syscall: arg1 */
+                     "int %1;               " /* fire the syscall */
+                     "popq %%rax;           " /* restore regs after syscall */
+                     "popq %%rsi;           "
+                     "jmp 2f;               " /* skip 1:, already popped */
+                                 "1: addq $0x08, %%rsp; " /* discard &sysc (on non-sc path) */
+                     "2: popq %%rdi;        " /* restore tf's %rdi (both paths) */
+                                 "popfq;                " /* restore utf's rflags */
+                     "ret;                  " /* return to the new PC */
+                     :
+                     : "g"(&tf->tf_rax), "i"(T_SYSCALL)
+                     : "memory");
+}
+
+static inline void pop_sw_tf(struct sw_trapframe *sw_tf, uint32_t vcoreid)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       /* Restore callee-saved FPU state.  We need to clear exceptions before
+        * reloading the FP CW, in case the new CW unmasks any.  We also need to
+        * reset the tag word to clear out the stack.
+        *
+        * The main issue here is that while our context was saved in an
+        * ABI-complaint manner, we may be starting up on a somewhat random FPU
+        * state.  Having gibberish in registers isn't a big deal, but some of the
+        * FP environment settings could cause trouble.  If fnclex; emms isn't
+        * enough, we could also save/restore the entire FP env with fldenv, or do
+        * an fninit before fldcw. */
+       asm volatile ("ldmxcsr %0" : : "m"(sw_tf->tf_mxcsr));
+       asm volatile ("fnclex; emms; fldcw %0" : : "m"(sw_tf->tf_fpucw));
+       /* Basic plan: restore all regs, off rcx as the sw_tf.  Switch to the new
+        * stack, save the PC so we can jump to it later.  Use clobberably
+        * registers for the locations of sysc, notif_dis, and notif_pend. Once on
+        * the new stack, we enable notifs, check if we missed one, and if so, self
+        * notify.  Note the syscall clobbers rax. */
+       asm volatile ("movq 0x00(%0), %%rbx; " /* restore regs */
+                     "movq 0x08(%0), %%rbp; "
+                     "movq 0x10(%0), %%r12; "
+                     "movq 0x18(%0), %%r13; "
+                     "movq 0x20(%0), %%r14; "
+                     "movq 0x28(%0), %%r15; "
+                     "movq 0x30(%0), %%r8;  " /* save rip in r8 */
+                     "movq 0x38(%0), %%rsp; " /* jump to future stack */
+                     "movb $0x00, (%2);     " /* enable notifications */
+                     /* Need a wrmb() here so the write of enable_notif can't pass
+                      * the read of notif_pending (racing with a potential
+                      * cross-core call with proc_notify()). */
+                     "lock addq $0, (%2);   " /* LOCK is a CPU mb() */
+                     /* From here down, we can get interrupted and restarted */
+                     "testb $0x01, (%3);    " /* test if a notif is pending */
+                     "jz 1f;                " /* if not pending, skip syscall */
+                     /* Actual syscall.  Note we don't wait on the async call.
+                      * &vc_entry is already in rdi (trap arg0). */
+                     "movq $0x1, %%rsi;     " /* sending one async syscall: arg1 */
+                     "int %4;               " /* fire the syscall */
+                     "1: jmp *%%r8;         " /* ret saved earlier */
+                     :
+                     : "c"(&sw_tf->tf_rbx),
+                       "D"(&vc_entry),
+                       "S"(&vcpd->notif_disabled),
+                       "d"(&vcpd->notif_pending),
+                       "i"(T_SYSCALL)
+                     : "memory");
+}
+
+/* Pops a user context, reanabling notifications at the same time.  A Userspace
+ * scheduler can call this when transitioning off the transition stack.
+ *
+ * At some point in vcore context before calling this, you need to clear
+ * notif_pending (do this by calling handle_events()).  As a potential
+ * optimization, consider clearing the notif_pending flag / handle_events again
+ * (right before popping), right 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. */
+static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
+{
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               pop_hw_tf(&ctx->tf.hw_tf, vcoreid);
+               break;
+       case ROS_SW_CTX:
+               pop_sw_tf(&ctx->tf.sw_tf, vcoreid);
+               break;
+       case ROS_VM_CTX:
+               ros_syscall(SYS_pop_ctx, ctx, 0, 0, 0, 0, 0);
+               break;
+       }
+       assert(0);
+}
+
+/* Like the regular pop_user_ctx, but this one doesn't check or clear
+ * notif_pending.  The only case where we use this is when an IRQ/notif
+ * interrupts a uthread that is in the process of disabling notifs.
+ *
+ * If we need to support VM_CTXs here, we'll need to tell the kernel whether or
+ * not we want to enable_notifs (flag to SYS_pop_ctx).  The only use case for
+ * this is when disabling notifs.  Currently, a VM can't do this or do things
+ * like uthread_yield.  It doesn't have access to the vcore's or uthread's TLS
+ * to bootstrap any of that stuff. */
+static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+       struct restart_helper *rst;
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       /* The stuff we need to write will be below the current stack of the utf */
+       rst = (struct restart_helper*)((void*)tf->tf_rsp -
+                                      sizeof(struct restart_helper));
+       /* Fill in the info we'll need later */
+       rst->notif_disab_loc = &vcpd->notif_disabled;
+       rst->rdi_save = 0;                      /* avoid bugs */
+       rst->rflags = tf->tf_rflags;
+       rst->rip = tf->tf_rip;
+
+       asm volatile ("movq %0, %%rsp;       " /* jump esp to the utf */
+                     "popq %%rax;           " /* restore registers */
+                     "popq %%rbx;           "
+                     "popq %%rcx;           "
+                     "popq %%rdx;           "
+                     "popq %%rbp;           "
+                     "popq %%rsi;           "
+                     "popq %%rdi;           "
+                     "popq %%r8;            "
+                     "popq %%r9;            "
+                     "popq %%r10;           "
+                     "popq %%r11;           "
+                     "popq %%r12;           "
+                     "popq %%r13;           "
+                     "popq %%r14;           "
+                     "popq %%r15;           "
+                     "addq $0x28, %%rsp;    " /* move to the rsp slot in the tf */
+                     "popq %%rsp;           " /* change to the utf's %rsp */
+                     "subq $0x10, %%rsp;    " /* move rsp to below rdi's slot */
+                     "pushq %%rdi;          " /* save rdi, will clobber soon */
+                     "subq $0x18, %%rsp;    " /* move to notif_dis_loc slot */
+                     "popq %%rdi;           " /* load notif_disabled addr */
+                     "movb $0x00, (%%rdi);  " /* enable notifications */
+                                 /* Here's where we differ from the regular pop_user_ctx().
+                                  * We need to adjust rsp and whatnot, but don't do test,
+                                  * clear notif_pending, or call a syscall. */
+                                 /* From here down, we can get interrupted and restarted */
+                     "addq $0x10, %%rsp;    " /* move to rdi save slot */
+                     "popq %%rdi;           " /* restore tf's %rdi */
+                                 "popfq;                " /* restore utf's rflags */
+                     "ret;                  " /* return to the new PC */
+                     :
+                     : "g"(&tf->tf_rax)
+                     : "memory");
+}
+
+/* Save's a SW context, setting the PC to the end of this function.  We only
+ * save callee-saved registers (of the sysv abi).  The compiler knows to save
+ * the others via the input/clobber lists.
+ *
+ * Callers of this function need to have at least one
+ * 'calling-convention-compliant' function call between this and any floating
+ * point, so that the compiler saves any caller-saved FP before getting to
+ * here.
+ *
+ * To some extent, TLS is 'callee-saved', in that no one ever expects it to
+ * change.  We handle uthread TLS changes separately, since we often change to
+ * them early to set some variables.  Arguably we should do this different. */
+static inline void save_user_ctx(struct user_context *ctx)
+{
+       struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
+       long dummy;
+       ctx->type = ROS_SW_CTX;
+       asm volatile ("stmxcsr %0" : "=m"(sw_tf->tf_mxcsr));
+       asm volatile ("fnstcw %0" : "=m"(sw_tf->tf_fpucw));
+       /* Pretty simple: save all the regs, IAW the sys-v ABI */
+       asm volatile("mov %%rsp, 0x48(%0);   " /* save rsp in its slot*/
+                    "leaq 1f(%%rip), %%rax; " /* get future rip */
+                    "mov %%rax, 0x40(%0);   " /* save rip in its slot*/
+                    "mov %%r15, 0x38(%0);   "
+                    "mov %%r14, 0x30(%0);   "
+                    "mov %%r13, 0x28(%0);   "
+                    "mov %%r12, 0x20(%0);   "
+                    "mov %%rbp, 0x18(%0);   "
+                    "mov %%rbx, 0x10(%0);   "
+                    "1:                     " /* where this tf will restart */
+                    : "=D"(dummy) /* force clobber for rdi */
+                                : "D"(sw_tf)
+                    : "rax", "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11",
+                      "memory", "cc");
+} __attribute__((always_inline, returns_twice))
+
+/* The old version, kept around for testing */
+/* Hasn't been used yet for 64 bit.  If you use this, it's worth checking to
+ * make sure rax isn't selected for 0, 1, or 2. (and we probably don't need to
+ * save rax in the beginning) */
+static inline void save_user_ctx_hw(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       memset(tf, 0, sizeof(struct hw_trapframe)); /* sanity */
+       /* set CS and make sure eflags is okay */
+       tf->tf_cs = GD_UT | 3;
+       tf->tf_rflags = 0x200; /* interrupts enabled.  bare minimum rflags. */
+       /* Save the regs and the future rsp. */
+       asm volatile("movq %%rsp, (%0);      " /* save rsp in it's slot*/
+                    "pushq %%rax;           " /* temp save rax */
+                    "leaq 1f, %%rax;        " /* get future rip */
+                    "movq %%rax, (%1);      " /* store future rip */
+                    "popq %%rax;            " /* restore rax */
+                    "movq %2, %%rsp;        " /* move to the rax slot of the tf */
+                    "addl $0x78,%%esp;      " /* move to just past r15 */
+                    "pushq %%r15;           " /* save regs */
+                    "pushq %%r14;           "
+                    "pushq %%r13;           "
+                    "pushq %%r12;           "
+                    "pushq %%r11;           "
+                    "pushq %%r10;           "
+                    "pushq %%r9;            "
+                    "pushq %%r8;            "
+                    "pushq %%rdi;           "
+                    "pushq %%rsi;           "
+                    "pushq %%rbp;           "
+                    "pushq %%rdx;           "
+                    "pushq %%rcx;           "
+                    "pushq %%rbx;           "
+                    "pushq %%rax;           "
+                    "addq $0xa0, %%rsp;     " /* move to rsp slot */
+                    "popq %%rsp;            " /* restore saved/original rsp */
+                    "1:                     " /* where this tf will restart */
+                    : 
+                    : "g"(&tf->tf_rsp), "g"(&tf->tf_rip), "g"(tf->tf_rax)
+                    : "rax", "memory", "cc");
+} __attribute__((always_inline, returns_twice))
+
+static inline void init_user_ctx(struct user_context *ctx, uintptr_t entry_pt,
+                                 uintptr_t stack_top)
+{
+       struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
+       ctx->type = ROS_SW_CTX;
+       /* Stack pointers in a fresh stackframe need to be such that adding or
+        * subtracting 8 will result in 16 byte alignment (AMD64 ABI).  The reason
+        * is so that input arguments (on the stack) are 16 byte aligned.  The
+        * extra 8 bytes is the retaddr, pushed on the stack.  Compilers know they
+        * can subtract 8 to get 16 byte alignment for instructions like movaps. */
+       sw_tf->tf_rsp = ROUNDDOWN(stack_top, 16) - 8;
+       sw_tf->tf_rip = entry_pt;
+       sw_tf->tf_rbp = 0;      /* for potential backtraces */
+       /* No need to bother with setting the other GP registers; the called
+        * function won't care about their contents. */
+       sw_tf->tf_mxcsr = 0x00001f80;   /* x86 default mxcsr */
+       sw_tf->tf_fpucw = 0x037f;               /* x86 default FP CW */
+}
+
+static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
+{
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               return ctx->tf.hw_tf.tf_rsp;
+       case ROS_SW_CTX:
+               return ctx->tf.sw_tf.tf_rsp;
+       case ROS_VM_CTX:
+               return ctx->tf.vm_tf.tf_rsp;
+       default:
+               assert(0);
+       }
+}
+
+// this is how we get our thread id on entry.
+#define __vcore_id_on_entry \
+({ \
+       register int temp asm ("rbx"); \
+       temp; \
+})
+
+__END_DECLS
diff --git a/user/parlib/include/poke.h b/user/parlib/include/poke.h
deleted file mode 100644 (file)
index 342fce0..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (c) 2012 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Post work and poke synchronization.  This is a wait-free way to make sure
- * some code is run, usually by the calling core, but potentially by any core.
- * Under contention, everyone just posts work, and one core will carry out the
- * work.  Callers post work (the meaning of which is particular to their
- * subsystem), then call this function.  The function is not run concurrently
- * with itself.
- *
- * As far as uthreads, vcores, and preemption go, poking is safe in uthread
- * context and if preemptions occur.  However, a uthread running the poke
- * function that gets preempted could delay the execution of the poke
- * indefinitely.  In general, post-and-poke does not provide any guarantee about
- * *when* the poke finally occurs.  If delays of this sort are a problem, then
- * run poke() from vcore context.
- *
- * Adapted from the kernel's implementation. */
-
-#pragma once
-
-#include <ros/atomic.h>
-
-__BEGIN_DECLS
-
-struct poke_tracker {
-       atomic_t                        need_to_run;
-       atomic_t                        run_in_progress;
-       void                            (*func)(void *);
-};
-
-void poke(struct poke_tracker *tracker, void *arg);
-
-static inline void poke_init(struct poke_tracker *tracker, void (*func)(void*))
-{
-       tracker->need_to_run = 0;
-       tracker->run_in_progress = 0;
-       tracker->func = func;
-}
-
-#define POKE_INITIALIZER(f) {.func = f}
-
-__END_DECLS
diff --git a/user/parlib/include/pool.h b/user/parlib/include/pool.h
deleted file mode 100644 (file)
index c4365b5..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* See COPYRIGHT for copyright information. */
-/* Kevin Klues <klueska@cs.berkeley.edu>       */
-
-#pragma once
-
-#include <string.h>
-
-__BEGIN_DECLS
-
-#define POOL_TYPE_DEFINE(_type, p, sz)                                                \
-typedef struct struct_##p {                                                             \
-       uint32_t size;                                                         \
-       uint32_t free;                                                         \
-       uint32_t index;                                                        \
-       _type *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)
-
-__END_DECLS
diff --git a/user/parlib/include/printf-ext.h b/user/parlib/include/printf-ext.h
deleted file mode 100644 (file)
index 14e3c6d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Common printf format extensions.  For now, %r is installed by default
- * (in early init code), and the others need to be requested.
- *
- * To register, for example %i for ipaddr, call:
- *             register_printf_specifier('i', printf_ipaddr, printf_ipaddr_info);
- */
-
-#pragma once
-
-#include <parlib/common.h>
-#include <printf.h>
-
-__BEGIN_DECLS
-
-/* Commonly used as %i, will print out a 16-byte plan9 IP address */
-int printf_ipaddr(FILE *stream, const struct printf_info *info,
-                  const void *const *args);
-int printf_ipaddr_info(const struct printf_info* info, size_t n, int *argtypes,
-                       int *size);
-
-/* Commonly used as %M, will print out a plan9 IPv6 mask, preferably as /xx */
-int printf_ipmask(FILE *stream, const struct printf_info *info,
-                  const void *const *args);
-int printf_ipmask_info(const struct printf_info* info, size_t n, int *argtypes,
-                       int *size);
-
-/* Commonly used as %E, will print out an ethernet address */
-int printf_ethaddr(FILE *stream, const struct printf_info *info,
-                   const void *const *args);
-int printf_ethaddr_info(const struct printf_info* info, size_t n, int *argtypes,
-                        int *size);
-
-/* Installed by default, will print the errstr for %r */
-int printf_errstr(FILE *stream, const struct printf_info *info,
-                  const void *const *args);
-int printf_errstr_info(const struct printf_info* info, size_t n, int *argtypes,
-                       int *size);
-
-__END_DECLS
diff --git a/user/parlib/include/riscv/arch.h b/user/parlib/include/riscv/arch.h
deleted file mode 100644 (file)
index 143306e..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#pragma once
-
-#include <parlib/common.h>
-#include <ros/trapframe.h>
-#include <ros/arch/arch.h>
-
-__BEGIN_DECLS
-
-#define internal_function
-
-#define ARCH_CL_SIZE 64
-
-static __inline void
-set_stack_pointer(void* sp)
-{
-       asm volatile ("move sp, %0" : : "r"(sp) : "memory");
-}
-
-static __inline void
-breakpoint(void)
-{
-       asm volatile ("break");
-}
-
-static __inline uint64_t
-read_tsc(void)
-{
-       unsigned long cycles;
-       asm ("rdcycle %0" : "=r"(cycles));
-       return (uint64_t)cycles;
-}
-
-static __inline uint64_t
-read_tsc_serialized(void)
-{
-       return read_tsc();
-}
-
-static __inline void
-cpu_relax(void)
-{
-       long ctr;
-       asm volatile("li %0, 8; 1: addi %0, %0, -1; bnez %0, 1b" : "=r"(ctr) : : "memory");
-}
-
-static inline void save_fp_state(struct ancillary_state* silly)
-{
-       uint32_t fsr = read_fsr();
-
-       asm("fsd fs0,%0" : "=m"(silly->fpr[0]));
-       asm("fsd fs1,%0" : "=m"(silly->fpr[1]));
-       asm("fsd fs2,%0" : "=m"(silly->fpr[2]));
-       asm("fsd fs3,%0" : "=m"(silly->fpr[3]));
-       asm("fsd fs4,%0" : "=m"(silly->fpr[4]));
-       asm("fsd fs5,%0" : "=m"(silly->fpr[5]));
-       asm("fsd fs6,%0" : "=m"(silly->fpr[6]));
-       asm("fsd fs7,%0" : "=m"(silly->fpr[7]));
-       asm("fsd fs8,%0" : "=m"(silly->fpr[8]));
-       asm("fsd fs9,%0" : "=m"(silly->fpr[9]));
-       asm("fsd fs10,%0" : "=m"(silly->fpr[10]));
-       asm("fsd fs11,%0" : "=m"(silly->fpr[11]));
-       asm("fsd fs12,%0" : "=m"(silly->fpr[12]));
-       asm("fsd fs13,%0" : "=m"(silly->fpr[13]));
-       asm("fsd fs14,%0" : "=m"(silly->fpr[14]));
-       asm("fsd fs15,%0" : "=m"(silly->fpr[15]));
-
-       silly->fsr = fsr;
-}
-
-static inline void restore_fp_state(struct ancillary_state* silly)
-{
-       uint32_t fsr = silly->fsr;
-
-       asm("fld fs0,%0" : : "m"(silly->fpr[0]));
-       asm("fld fs1,%0" : : "m"(silly->fpr[1]));
-       asm("fld fs2,%0" : : "m"(silly->fpr[2]));
-       asm("fld fs3,%0" : : "m"(silly->fpr[3]));
-       asm("fld fs4,%0" : : "m"(silly->fpr[4]));
-       asm("fld fs5,%0" : : "m"(silly->fpr[5]));
-       asm("fld fs6,%0" : : "m"(silly->fpr[6]));
-       asm("fld fs7,%0" : : "m"(silly->fpr[7]));
-       asm("fld fs8,%0" : : "m"(silly->fpr[8]));
-       asm("fld fs9,%0" : : "m"(silly->fpr[9]));
-       asm("fld fs10,%0" : : "m"(silly->fpr[10]));
-       asm("fld fs11,%0" : : "m"(silly->fpr[11]));
-       asm("fld fs12,%0" : : "m"(silly->fpr[12]));
-       asm("fld fs13,%0" : : "m"(silly->fpr[13]));
-       asm("fld fs14,%0" : : "m"(silly->fpr[14]));
-       asm("fld fs15,%0" : : "m"(silly->fpr[15]));
-
-       write_fsr(fsr);
-}
-
-__END_DECLS
diff --git a/user/parlib/include/riscv/atomic.h b/user/parlib/include/riscv/atomic.h
deleted file mode 100644 (file)
index 994deb4..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#pragma once
-
-#include <parlib/common.h>
-#include <ros/atomic.h>
-#include <ros/arch/membar.h>
-
-__BEGIN_DECLS
-
-#define SPINLOCK_INITIALIZER {0}
-
-static inline void atomic_init(atomic_t *number, long val);
-static inline long atomic_read(atomic_t *number);
-static inline void atomic_set(atomic_t *number, long val);
-static inline void atomic_inc(atomic_t *number);
-static inline void atomic_dec(atomic_t *number);
-static inline long atomic_fetch_and_add(atomic_t *number, long val);
-static inline long atomic_swap(atomic_t *addr, long val);
-static inline void *atomic_swap_ptr(void **addr, void *val);
-static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
-static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
-static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
-static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
-                                  uint32_t new_val);
-static inline void atomic_or_int(volatile int *number, int mask);
-
-/* Inlined functions declared above */
-
-static inline void atomic_init(atomic_t *number, long val)
-{
-       *(volatile long*)number = val;
-}
-
-static inline long atomic_read(atomic_t *number)
-{
-       return *(volatile long*)number;
-}
-
-static inline void ros_atomic_add(atomic_t *number, long inc)
-{
-       atomic_fetch_and_add(number, inc);
-}
-
-static inline void atomic_set(atomic_t *number, long val)
-{
-       atomic_init(number, val);
-}
-
-static inline void atomic_inc(atomic_t *number)
-{
-       ros_atomic_add(number, 1);
-}
-
-static inline void atomic_dec(atomic_t *number)
-{
-       ros_atomic_add(number, -1);
-}
-
-/* Adds val to number, returning number's original value */
-static inline long atomic_fetch_and_add(atomic_t *number, long val)
-{
-       return __sync_fetch_and_add((long*)number, val);
-}
-
-static inline long atomic_swap(atomic_t *addr, long val)
-{
-       return __sync_lock_test_and_set((long*)addr, val);
-}
-
-static inline void *atomic_swap_ptr(void **addr, void *val)
-{
-       return __sync_lock_test_and_set(addr, val);
-}
-
-static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
-{
-       return __sync_lock_test_and_set(addr, val);
-}
-
-// RISC-V has atomic word ops, not byte ops, so we must manipulate addresses
-static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
-{
-       uintptr_t offset = (uintptr_t)number & 3;
-       uint32_t wmask = (1<<(8*offset+8)) - (1<<(8*offset));
-       wmask = ~wmask | ((uint32_t)mask << (8*offset));
-
-       __sync_fetch_and_and((uint32_t*)((uintptr_t)number & ~3), wmask);
-}
-
-static inline void atomic_orb(volatile uint8_t* number, uint8_t mask)
-{
-       uintptr_t offset = (uintptr_t)number & 3;
-       uint32_t wmask = (uint32_t)mask << (8*offset);
-
-       __sync_fetch_and_or((uint32_t*)((uintptr_t)number & ~3), wmask);
-}
-
-static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
-{
-       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
-}
-
-static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
-{
-       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
-}
-
-static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
-                                  uint32_t new_val)
-{
-       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
-}
-
-static inline void atomic_or_int(volatile int *number, int mask)
-{
-       __sync_fetch_and_or(number, mask);
-}
-
-__END_DECLS
diff --git a/user/parlib/include/riscv/bitmask.h b/user/parlib/include/riscv/bitmask.h
deleted file mode 100644 (file)
index 14bf590..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#pragma once
-
-#include <string.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <parlib/arch/atomic.h>
-#include <stdio.h>
-
-__BEGIN_DECLS
-
-#define DECL_BITMASK(name, size) \
-       uint8_t (name)[BYTES_FOR_BITMASK((size))]
-
-#define BYTES_FOR_BITMASK(size) \
-       (((size) - 1) / 8 + 1)
-
-#define BYTES_FOR_BITMASK_WITH_CHECK(size) \
-       ((size) ? ((size) - (1)) / (8) + (1) : (0))
-
-static bool GET_BITMASK_BIT(uint8_t* name, size_t bit) 
-{
-       return (((name)[(bit)/8] & (1 << ((bit) % 8))) ? 1 : 0);
-}
-
-#define SET_BITMASK_BIT(name, bit) \
-       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
-/*
-static void SET_BITMASK_BIT(uint8_t* name, size_t bit)
-{
-       ((name)[(bit)/8] |= (1 << ((bit) % 8)));
-}
-*/
-
-#define CLR_BITMASK_BIT(name, bit) \
-       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
-/*
-static void CLR_BITMASK_BIT(uint8_t* name, size_t bit) 
-{
-       ((name)[(bit)/8] &= ~(1 << ((bit) % 8)));
-}
-*/
-
-static void SET_BITMASK_BIT_ATOMIC(uint8_t* name, size_t bit) 
-{
-       (atomic_orb(&(name)[(bit)/8], (1 << ((bit) % 8))));
-}
-
-#define CLR_BITMASK_BIT_ATOMIC(name, bit) \
-       (atomic_andb(&(name)[(bit)/8], ~(1 << ((bit) % 8))))
-
-#define CLR_BITMASK(name, size) \
-({ \
-       memset((void*)((uintptr_t)(name)), 0, BYTES_FOR_BITMASK((size))); \
-})
-
-#define FILL_BITMASK(name, size) \
-({ \
-       memset((void*)((uintptr_t)(name)), 255, BYTES_FOR_BITMASK((size))); \
-       (name)[BYTES_FOR_BITMASK((size))-1] >>= (((size) % 8) ? (8 - ((size) % 8)) : 0 ); \
-}) 
-
-#define COPY_BITMASK(newmask, oldmask, size) \
-({ \
-       memcpy((void*)((uintptr_t)(newmask)), \
-           (void*)((uintptr_t)(oldmask)), \
-           BYTES_FOR_BITMASK((size))); \
-})
-
-// this checks the entire last byte, so keep it 0 in the other macros
-#define BITMASK_IS_CLEAR(name, size) ({ \
-       uint32_t __n = BYTES_FOR_BITMASK((size)); \
-       bool clear = 1; \
-       while (__n-- > 0) { \
-               if ((name)[__n]) { \
-                       clear = 0; \
-                       break;\
-               }\
-       } \
-       clear; })
-
-static inline bool BITMASK_IS_FULL(uint8_t* map, size_t size)
-{
-       int _size = size;
-       for (int i = 0; i < BYTES_FOR_BITMASK(size); i++) {
-               for (int j = 0; j < MIN(8,_size); j++)
-                       if(!((map[i] >> j) &1))
-                               return FALSE;
-                       _size--;
-       }
-       return TRUE;
-}
-
-__END_DECLS
diff --git a/user/parlib/include/riscv/trap.h b/user/parlib/include/riscv/trap.h
deleted file mode 100644 (file)
index 7a4060e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (c) 2016 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Arch-specific defines for traps, vmexits, and similar things */
-
-#pragma once
-
-#include <parlib/common.h>
-#include <ros/trapframe.h>
-
-__BEGIN_DECLS
-
-#error fix these numbers
-
-#define HW_TRAP_DIV_ZERO               0
-#define HW_TRAP_GP_FAULT               1
-#define HW_TRAP_PAGE_FAULT             2
-
-#error implement these
-static bool has_refl_fault(struct user_context *ctx)
-{
-       return 0;
-}
-
-static void clear_refl_fault(struct user_context *ctx)
-{
-}
-
-static unsigned int __arch_refl_get_nr(struct user_context *ctx)
-{
-       return 0;
-}
-
-static unsigned int __arch_refl_get_err(struct user_context *ctx)
-{
-       return 0;
-}
-
-static unsigned long __arch_refl_get_aux(struct user_context *ctx)
-{
-       return 0;
-}
-
-__END_DECLS
diff --git a/user/parlib/include/riscv/vcore.h b/user/parlib/include/riscv/vcore.h
deleted file mode 100644 (file)
index dba6b97..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#pragma once
-
-#include <parlib/common.h>
-#include <ros/trapframe.h>
-#include <parlib/arch/arch.h>
-#include <ros/syscall.h>
-#include <ros/procdata.h>
-#include <parlib/assert.h>
-#include <sys/tls.h>
-
-__BEGIN_DECLS
-
-#ifdef __riscv64
-# define REG_L "ld"
-# define REG_S "sd"
-#else
-# define REG_L "lw"
-# define REG_S "sw"
-#endif
-
-/* Register saves and restores happen in asm. */
-typedef void (*helper_fn)(struct hw_trapframe*, struct preempt_data*, uint32_t);
-void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd,
-                    uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
-void __save_ros_tf_regs(struct hw_trapframe *tf) __attribute__((returns_twice));
-
-/* Helper function that may handle notifications after re-enabling them. */
-static void __pop_ros_tf_notifs(struct hw_trapframe *tf,
-                                struct preempt_data* vcpd, uint32_t vcoreid)
-{
-       vcpd->notif_disabled = FALSE;
-
-       __sync_synchronize();
-
-       if(vcpd->notif_pending)
-               ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0);
-}
-
-/* Helper function that won't handle notifications after re-enabling them. */
-static void __pop_ros_tf_notifs_raw(struct hw_trapframe *tf,
-                                    struct preempt_data* vcpd, uint32_t vcoreid)
-{
-       vcpd->notif_disabled = FALSE;
-}
-
-static inline void __pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid,
-                                helper_fn helper)
-{
-       // since we're changing the stack, move stuff into regs for now
-       register uint32_t _vcoreid = vcoreid;
-       register struct hw_trapframe* _tf = tf;
-
-       set_stack_pointer((void*)tf->gpr[GPR_SP]);
-
-       tf = _tf;
-       vcoreid = _vcoreid;
-       struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
-       __pop_ros_tf_regs(tf, vcpd, vcoreid, helper);
-}
-
-/* Pops a user context, 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_user_ctx(struct user_context *ctx, uint32_t vcoreid)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       assert(ctx->type == ROS_HW_CTX);
-       __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
-}
-
-/* Like the regular pop_user_ctx, but this one doesn't check or clear
- * notif_pending. */
-static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       assert(ctx->type == ROS_HW_CTX);
-       __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
-}
-
-/* Save the current context/registers into the given ctx, setting the pc of the
- * tf to the end of this function.  You only need to save that which you later
- * restore with pop_user_ctx(). */
-static inline void save_user_ctx(struct user_context *ctx)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       ctx->type = ROS_HW_CTX;
-       __save_ros_tf_regs(tf);
-}
-
-static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt,
-                                 uint32_t stack_top)
-{
-       struct hw_trapframe *u_tf = &ctx->tf.hw_tf;
-       ctx->type = ROS_HW_CTX;
-       memset(u_tf, 0, sizeof(*u_tf));
-       u_tf->gpr[GPR_SP] = stack_top;
-       u_tf->epc = entry_pt;
-}
-
-static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
-{
-       return ctx->tf.hw_tf.gpr[GPR_SP];
-}
-
-#define __vcore_id_on_entry \
-({ \
-       register int temp asm ("a0"); \
-       temp; \
-})
-
-__END_DECLS
diff --git a/user/parlib/include/ros_debug.h b/user/parlib/include/ros_debug.h
deleted file mode 100644 (file)
index 9de59b4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include <parlib/common.h>
-#include <parlib/parlib.h>
-#include <parlib/vcore.h>
-
-__BEGIN_DECLS
-
-#define I_AM_HERE printf("Vcore %d is in %s() at %s:%d\n", vcore_id(), \
-                         __FUNCTION__, __FILE__, __LINE__);
-
-/* For a poor-mans function tracer (can add these with spatch) */
-void __print_func_entry(const char *func, const char *file);
-void __print_func_exit(const char *func, const char *file);
-#define print_func_entry() __print_func_entry(__FUNCTION__, __FILE__)
-#define print_func_exit() __print_func_exit(__FUNCTION__, __FILE__)
-
-/* user/parlib/hexdump.c */
-void hexdump(FILE *f, void *v, int length);
-
-__END_DECLS
diff --git a/user/parlib/include/serialize.h b/user/parlib/include/serialize.h
deleted file mode 100644 (file)
index d97eaf0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Copyright (c) 2015 Google Inc., All Rights Reserved.
- * Kevin Klues <klueska@google.com>
- * See LICENSE for details. */
-
-#pragma once
-
-#include <stddef.h>
-
-struct serialized_data {
-       size_t len;
-       char buf[];
-};
-extern struct serialized_data *serialize_argv_envp(char *const argv[],
-                                                   char *const envp[]);
-extern void free_serialized_data(struct serialized_data *sd);
diff --git a/user/parlib/include/signal.h b/user/parlib/include/signal.h
deleted file mode 100644 (file)
index eb9ca33..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2015 Google Inc.
- * Kevin Klues <klueska@cs.berkeley.edu>
- * See LICENSE for details.
- */
-
-#pragma once
-#ifdef BUILDING_PARLIB
-#include_next "signal.h"
-#else
-#include <signal.h>
-#endif
-
-#include <ros/procinfo.h>
-
-struct uthread;
-
-/* Data we need to carry around as part of handling posix signals on akaros. */
-struct sigdata {
-       struct user_context u_ctx;
-       struct ancillary_state as;
-       struct siginfo info;
-};
-struct sigstate {
-       sigset_t mask;
-       sigset_t pending;
-       struct sigdata *data;
-};
-
-/* A set of functions related to handling posix signals on akaros. The
- * implementation of these functions is 2LS specific. */
-struct signal_ops {
-       /* Standard ops */
-       int (*sigaltstack)(__const struct sigaltstack *__restrict,
-                       struct sigaltstack *__restrict);
-       int (*siginterrupt)(int, int);
-       int (*sigpending)(sigset_t *);
-       int (*sigprocmask)(int, __const sigset_t *__restrict, sigset_t *__restrict);
-       int (*sigqueue)(__pid_t, int, __const union sigval);
-       int (*sigreturn)(struct sigcontext *__scp);
-       int (*sigstack)(struct sigstack *, struct sigstack *);
-       int (*sigsuspend)(__const sigset_t *);
-       int (*sigtimedwait)(__const sigset_t *__restrict, siginfo_t *__restrict,
-                           __const struct timespec *__restrict);
-       int (*sigwait)(__const sigset_t *__restrict, int *__restrict);
-       int (*sigwaitinfo)(__const sigset_t *__restrict, siginfo_t *__restrict);
-
-       /* Extended ops */
-       int (*sigself)(int signo);
-};
-
-/* Glibc defines the symbol for signal_ops so that the function pointers
- * assigned in it can be used from within glibc itself. */
-extern struct signal_ops *signal_ops;
-
-/* External API for initializing and generating posix signals inside a 2LS. */
-void init_posix_signals(void);
-void trigger_posix_signal(int sig_nr, struct siginfo *info, void *aux);
-void uthread_prep_pending_signals(struct uthread *uthread);
-void uthread_prep_signal_from_fault(struct uthread *uthread,
-                                    int signo, int code, void *addr);
-int uthread_signal(struct uthread *uthread, int signo);
diff --git a/user/parlib/include/slab.h b/user/parlib/include/slab.h
deleted file mode 100644 (file)
index 7195819..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2009 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * Kevin Klues <klueska@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Slab allocator, based on the SunOS 5.4 allocator paper.
- *
- * There is a list of kmem_cache, which are the caches of objects of a given
- * size.  This list is sorted in order of size.  Each kmem_cache has three
- * lists of slabs: full, partial, and empty.  
- *
- * For large objects, the kmem_slabs point to bufctls, which have the address
- * of their large buffers.  These slabs can consist of more than one contiguous
- * page.
- *
- * For small objects, the slabs do not use the bufctls.  Instead, they point to
- * the next free object in the slab.  The free objects themselves hold the
- * address of the next free item.  The slab structure is stored at the end of
- * the page.  There is only one page per slab.
- *
- * TODO: Note, that this is a minor pain in the ass, and worth thinking about
- * before implementing.  To keep the constructor's state valid, we can't just
- * overwrite things, so we need to add an extra 4-8 bytes per object for the
- * pointer, and then pass over that data when we return the actual object's
- * address.  This also might fuck with alignment.
- *
- * Ported directly from the kernel's slab allocator. */
-
-#pragma once
-
-#include <parlib/common.h>
-#include <ros/arch/mmu.h>
-#include <sys/queue.h>
-#include <parlib/arch/atomic.h>
-#include <parlib/spinlock.h>
-
-__BEGIN_DECLS
-
-/* Back in the day, their cutoff for "large objects" was 512B, based on
- * measurements and on not wanting more than 1/8 of internal fragmentation. */
-#define NUM_BUF_PER_SLAB 8
-#define SLAB_LARGE_CUTOFF (PGSIZE / NUM_BUF_PER_SLAB)
-
-struct kmem_slab;
-
-/* Control block for buffers for large-object slabs */
-struct kmem_bufctl {
-       TAILQ_ENTRY(kmem_bufctl) link;
-       void *buf_addr;
-       struct kmem_slab *my_slab;
-};
-TAILQ_HEAD(kmem_bufctl_list, kmem_bufctl);
-
-/* Slabs contain the objects.  Can be either full, partial, or empty,
- * determined by checking the number of objects busy vs total.  For large
- * slabs, the bufctl list is used to find a free buffer.  For small, the void*
- * is used instead.*/
-struct kmem_slab {
-       TAILQ_ENTRY(kmem_slab) link;
-       size_t obj_size;
-       size_t num_busy_obj;
-       size_t num_total_obj;
-       union {
-               struct kmem_bufctl_list bufctl_freelist;
-               void *free_small_obj;
-       };
-};
-TAILQ_HEAD(kmem_slab_list, kmem_slab);
-
-/* Actual cache */
-struct kmem_cache {
-       SLIST_ENTRY(kmem_cache) link;
-       struct spin_pdr_lock cache_lock;
-       const char *name;
-       size_t obj_size;
-       int align;
-       int flags;
-       struct kmem_slab_list full_slab_list;
-       struct kmem_slab_list partial_slab_list;
-       struct kmem_slab_list empty_slab_list;
-       void (*ctor)(void *, size_t);
-       void (*dtor)(void *, size_t);
-       unsigned long nr_cur_alloc;
-};
-
-/* List of all kmem_caches, sorted in order of size */
-SLIST_HEAD(kmem_cache_list, kmem_cache);
-extern struct kmem_cache_list kmem_caches;
-
-/* Cache management */
-struct kmem_cache *kmem_cache_create(const char *name, size_t obj_size,
-                                     int align, int flags,
-                                     void (*ctor)(void *, size_t),
-                                     void (*dtor)(void *, size_t));
-void kmem_cache_destroy(struct kmem_cache *cp);
-/* Front end: clients of caches use these */
-void *kmem_cache_alloc(struct kmem_cache *cp, int flags);
-void kmem_cache_free(struct kmem_cache *cp, void *buf);
-/* Back end: internal functions */
-void kmem_cache_init(void);
-void kmem_cache_reap(struct kmem_cache *cp);
-
-/* Debug */
-void print_kmem_cache(struct kmem_cache *kc);
-void print_kmem_slab(struct kmem_slab *slab);
-
-__END_DECLS
diff --git a/user/parlib/include/spinlock.h b/user/parlib/include/spinlock.h
deleted file mode 100644 (file)
index f4ffea1..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * Kevin Klues <klueska@cs.berkeley.edu>
- *
- * Spinlocks and Spin-PDR locks (preemption detection/recovery)
- *
- * This file is part of Parlib.
- * 
- * Parlib is free software: you can redistribute it and/or modify
- * it under the terms of the Lesser GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * Parlib is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * Lesser GNU General Public License for more details.
- * 
- * See COPYING.LESSER for details on the GNU Lesser General Public License.
- * See COPYING for details on the GNU General Public License. */
-
-#pragma once
-
-#include <parlib/arch/arch.h>
-#include <parlib/arch/atomic.h>
-
-__BEGIN_DECLS
-
-#define SPINLOCK_INITIALIZER {0}
-
-typedef struct {
-  int lock;
-} spinlock_t;
-
-void spinlock_init(spinlock_t *lock);
-int spinlock_trylock(spinlock_t *lock);
-void spinlock_lock(spinlock_t *lock);
-void spinlock_unlock(spinlock_t *lock);
-bool spinlock_locked(spinlock_t *lock);
-
-/* RISCV doesn't support CAS, so til it does, we use the NO_CAS, even if they
- * didn't ask for it in their config. */
-#ifdef __riscv__
-# ifndef CONFIG_SPINPDR_NO_CAS
-#  define CONFIG_SPINPDR_NO_CAS 1
-# endif
-#endif
-
-/* Two different versions, with and without CAS.  Default is with CAS. */
-#ifndef CONFIG_SPINPDR_NO_CAS
-
-# define SPINPDR_UNLOCKED ((uint32_t)-1)
-
-struct spin_pdr_lock {
-       uint32_t lock;
-};
-# define SPINPDR_INITIALIZER {SPINPDR_UNLOCKED}
-
-#else /* NO_CAS */
-
-# define SPINPDR_VCOREID_UNKNOWN ((uint32_t)-1)
-
-struct spin_pdr_lock {
-       /* consider putting these on separate cache lines, if we ever use them */
-       spinlock_t spinlock;
-       uint32_t lockholder;
-};
-# define SPINPDR_INITIALIZER {SPINLOCK_INITIALIZER, SPINPDR_VCOREID_UNKNOWN}
-
-#endif /* CONFIG_SPINPDR_NO_CAS */
-
-typedef struct spin_pdr_lock spinpdrlock_t;
-
-void spin_pdr_init(struct spin_pdr_lock *pdr_lock);
-void spin_pdr_lock(struct spin_pdr_lock *pdr_lock);
-void spin_pdr_unlock(struct spin_pdr_lock *pdr_lock);
-bool spin_pdr_locked(struct spin_pdr_lock *pdr_lock);
-
-__END_DECLS
diff --git a/user/parlib/include/stdio.h b/user/parlib/include/stdio.h
deleted file mode 100644 (file)
index 0c5ddab..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 2015 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Print routines for Akaros user programs. */
-
-#pragma once
-
-#ifdef BUILDING_PARLIB
-# include_next "stdio.h"
-#else
-# include <stdio.h>
-#endif
-#include <stdarg.h>
-
-__BEGIN_DECLS
-
-void akaros_vprintfmt(void (*putch)(int, void**), void **putdat,
-                      const char *fmt, va_list);
-int akaros_vprintf(const char *fmt, va_list);
-/* This is the same as our sysdep for glibc's printf.  We use this to print in
- * a few places in glibc that can't link directly against printf.  (the
- * 'multiple libcs' problem). */
-int akaros_printf(const char *format, ...);
-
-#ifdef PRINTD_DEBUG
-#define printd(args...) printf(args)
-#else
-#define printd(args...) {}
-#endif
-
-__END_DECLS
diff --git a/user/parlib/include/timing.h b/user/parlib/include/timing.h
deleted file mode 100644 (file)
index 86833a6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <parlib/tsc-compat.h>
-
-__BEGIN_DECLS
-
-void udelay(uint64_t usec);
-void ndelay(uint64_t nsec);
-uint64_t udiff(uint64_t begin, uint64_t end);
-uint64_t ndiff(uint64_t begin, uint64_t end);
-
-/* Conversion btw tsc ticks and time units.  From Akaros's kern/src/time.c */
-uint64_t tsc2sec(uint64_t tsc_time);
-uint64_t tsc2msec(uint64_t tsc_time);
-uint64_t tsc2usec(uint64_t tsc_time);
-uint64_t tsc2nsec(uint64_t tsc_time);
-uint64_t sec2tsc(uint64_t sec);
-uint64_t msec2tsc(uint64_t msec);
-uint64_t usec2tsc(uint64_t usec);
-uint64_t nsec2tsc(uint64_t nsec);
-
-__END_DECLS
diff --git a/user/parlib/include/tsc-compat.h b/user/parlib/include/tsc-compat.h
deleted file mode 100644 (file)
index 47c9c59..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Basic TSC compatability helpers, callable from Akaros or Linux. Supports:
- *             uint64_t read_tsc()
- *             uint64_t read_tsc_serialized()
- *             uint64_t get_tsc_freq()
- *             uint64_t get_tsc_overhead()
- *
- * Note this relies on specifics of procinfo, which isn't stable.  If procinfo
- * changes, this will need to change as well.  You'll know when this doesn't
- * compile (say, if timing_overhead moves).  */
-
-#pragma once
-
-#if defined(__i386__) || defined(__x86_64__)
-#else
-#error "Platform not supported for read_tsc()"
-#endif
-
-__BEGIN_DECLS
-
-#ifdef __ros__
-
-#include <parlib/arch/arch.h>
-#include <ros/procinfo.h>
-
-static inline uint64_t get_tsc_freq(void)
-{
-       return __procinfo.tsc_freq;
-}
-
-static inline uint64_t get_tsc_overhead(void)
-{
-       return __procinfo.timing_overhead;
-}
-
-#else /* ! _ros_ (linux) */
-
-#include <sys/time.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-/* Akaros has this helper in ros/common.h. (it returns a bool btw)
- *
- * We wraparound if UINT_MAX < a * b, which is also UINT_MAX / a < b. */
-static inline int mult_will_overflow_u64(uint64_t a, uint64_t b)
-{
-       if (!a)
-               return false;
-       return (uint64_t)(-1) / a < b;
-}
-
-# ifdef __i386__
-
-static inline uint64_t read_tsc(void)
-{
-       uint64_t tsc;
-       asm volatile("rdtsc" : "=A" (tsc));
-       return tsc;
-}
-
-static inline uint64_t read_tsc_serialized(void)
-{
-       uint64_t tsc;
-       asm volatile("lfence; rdtsc" : "=A" (tsc));
-       return tsc;
-}
-
-# elif __x86_64__
-
-static inline uint64_t read_tsc(void)
-{
-       uint32_t lo, hi;
-       /* We cannot use "=A", since this would use %rax on x86_64 */
-       asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
-       return (uint64_t)hi << 32 | lo;
-}
-
-static inline uint64_t read_tsc_serialized(void)
-{
-       uint32_t lo, hi;
-       asm volatile("lfence; rdtsc" : "=a" (lo), "=d" (hi));
-       return (uint64_t)hi << 32 | lo;
-}
-
-# else
-#  error "Which arch is this?"
-# endif /* __i386__ | __x86_64__ */
-
-static inline uint64_t get_tsc_freq(void)
-{
-       struct timeval prev;
-       struct timeval curr;
-       uint64_t beg = read_tsc_serialized();
-       gettimeofday(&prev, 0);
-       while (1) {
-               gettimeofday(&curr, 0);
-               if (curr.tv_sec > (prev.tv_sec + 1) ||
-                       (curr.tv_sec > prev.tv_sec && curr.tv_usec > prev.tv_usec))
-                       break;
-       }
-       uint64_t end = read_tsc_serialized();
-       return end - beg;
-}
-
-/* Don't have a good way to get the overhead on Linux in userspace. */
-static inline uint64_t get_tsc_overhead(void)
-{
-       return 0;
-}
-
-static inline uint64_t tsc2sec(uint64_t tsc_time)
-{
-       return tsc_time / get_tsc_freq();
-}
-
-static inline uint64_t tsc2msec(uint64_t tsc_time)
-{
-       if (mult_will_overflow_u64(tsc_time, 1000))
-               return tsc2sec(tsc_time) * 1000;
-       else
-               return (tsc_time * 1000) / get_tsc_freq();
-}
-
-static inline uint64_t tsc2usec(uint64_t tsc_time)
-{
-       if (mult_will_overflow_u64(tsc_time, 1000000))
-               return tsc2msec(tsc_time) * 1000;
-       else
-               return (tsc_time * 1000000) / get_tsc_freq();
-}
-
-static inline uint64_t tsc2nsec(uint64_t tsc_time)
-{
-       if (mult_will_overflow_u64(tsc_time, 1000000000))
-               return tsc2usec(tsc_time) * 1000;
-       else
-               return (tsc_time * 1000000000) / get_tsc_freq();
-}
-
-static inline uint64_t sec2tsc(uint64_t sec)
-{
-       if (mult_will_overflow_u64(sec, get_tsc_freq()))
-               return (uint64_t)(-1);
-       else
-               return sec * get_tsc_freq();
-}
-
-static inline uint64_t msec2tsc(uint64_t msec)
-{
-       if (mult_will_overflow_u64(msec, get_tsc_freq()))
-               return sec2tsc(msec / 1000);
-       else
-               return (msec * get_tsc_freq()) / 1000;
-}
-
-static inline uint64_t usec2tsc(uint64_t usec)
-{
-       if (mult_will_overflow_u64(usec, get_tsc_freq()))
-               return msec2tsc(usec / 1000);
-       else
-               return (usec * get_tsc_freq()) / 1000000;
-}
-
-static inline uint64_t nsec2tsc(uint64_t nsec)
-{
-       if (mult_will_overflow_u64(nsec, get_tsc_freq()))
-               return usec2tsc(nsec / 1000);
-       else
-               return (nsec * get_tsc_freq()) / 1000000000;
-}
-
-#endif /* ! _ros_ */
-
-__END_DECLS
diff --git a/user/parlib/include/ucq.h b/user/parlib/include/ucq.h
deleted file mode 100644 (file)
index 7a7ba0c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright (c) 2011 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Unbounded concurrent queues, user side.  Check k/i/r/ucq.h or the
- * Documentation for more info. */
-
-#pragma once
-
-#include <ros/ucq.h>
-
-__BEGIN_DECLS
-
-void ucq_init_raw(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2);
-void ucq_init(struct ucq *ucq);
-void ucq_free_pgs(struct ucq *ucq);
-bool get_ucq_msg(struct ucq *ucq, struct event_msg *msg);
-bool ucq_is_empty(struct ucq *ucq);
-
-__END_DECLS
diff --git a/user/parlib/include/uthread.h b/user/parlib/include/uthread.h
deleted file mode 100644 (file)
index b108110..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#pragma once
-
-#include <parlib/vcore.h>
-#include <parlib/signal.h>
-#include <ros/syscall.h>
-
-__BEGIN_DECLS
-
-#define UTHREAD_DONT_MIGRATE           0x001 /* don't move to another vcore */
-#define UTHREAD_SAVED                          0x002 /* uthread's state is in utf */
-#define UTHREAD_FPSAVED                                0x004 /* uthread's FP state is in uth->as */
-#define UTHREAD_IS_THREAD0                     0x008 /* thread0: glibc's main() thread */
-
-/* Thread States */
-#define UT_RUNNING             1
-#define UT_NOT_RUNNING 2
-
-/* Externally blocked thread reasons (for uthread_has_blocked()) */
-#define UTH_EXT_BLK_MUTEX                      1
-#define UTH_EXT_BLK_EVENTQ                     2
-#define UTH_EXT_BLK_JUSTICE                    3       /* whatever.  might need more options */
-
-/* Bare necessities of a user thread.  2LSs should allocate a bigger struct and
- * cast their threads to uthreads when talking with vcore code.  Vcore/default
- * 2LS code won't touch udata or beyond. */
-struct uthread {
-       struct user_context u_ctx;
-       struct ancillary_state as;
-       void *tls_desc;
-       int flags;
-       int state;
-       struct sigstate sigstate;
-       int notif_disabled_depth;
-       struct syscall *sysc;   /* syscall we're blocking on, if any */
-       struct syscall local_sysc;      /* for when we don't want to use the stack */
-       void (*yield_func)(struct uthread*, void*);
-       void *yield_arg;
-       int err_no;
-       char err_str[MAX_ERRSTR_LEN];
-};
-extern __thread struct uthread *current_uthread;
-typedef void* uth_mutex_t;
-
-/* 2L-Scheduler operations.  Examples in pthread.c. */
-struct schedule_ops {
-       /**** These functions must be defined ****/
-       /* Functions supporting thread ops */
-       void (*sched_entry)(void);
-       void (*thread_runnable)(struct uthread *);
-       void (*thread_paused)(struct uthread *);
-       void (*thread_blockon_sysc)(struct uthread *, void *);
-       void (*thread_has_blocked)(struct uthread *, int);
-       void (*thread_refl_fault)(struct uthread *, struct user_context *);
-       /**** Defining these functions is optional. ****/
-       /* 2LSs can leave the mutex funcs empty for a default implementation */
-       uth_mutex_t (*mutex_alloc)(void);
-       void (*mutex_free)(uth_mutex_t);
-       void (*mutex_lock)(uth_mutex_t);
-       void (*mutex_unlock)(uth_mutex_t);
-       /* Functions event handling wants */
-       void (*preempt_pending)(void);
-};
-extern struct schedule_ops *sched_ops;
-
-/* Low-level _S code calls this for basic uthreading without a 2LS */
-void uthread_lib_init(void);
-/* Call this, passing it a uthread representing thread0, from your 2LS init
- * routines.  When it returns, you're in _M mode (thread0 on vcore0) */
-void uthread_2ls_init(struct uthread *uthread, struct schedule_ops *ops);
-/* Call this to become an mcp capable of worling with uthreads. */
-void uthread_mcp_init(void);
-
-/* Functions to make/manage uthreads.  Can be called by functions such as
- * pthread_create(), which can wrap these with their own stuff (like attrs,
- * retvals, etc). */
-
-/* uthread_init() does the uthread initialization of a uthread that the caller
- * created.  Call this whenever you are "starting over" with a thread.  Pass in
- * attr, if you want to override any defaults. */
-struct uth_thread_attr {
-       bool want_tls;          /* default, no */
-};
-void uthread_init(struct uthread *new_thread, struct uth_thread_attr *attr);
-/* Call this when you are done with a uthread, forever, but before you free it */
-void uthread_cleanup(struct uthread *uthread);
-void uthread_runnable(struct uthread *uthread);
-void uthread_yield(bool save_state, void (*yield_func)(struct uthread*, void*),
-                   void *yield_arg);
-void uthread_sleep(unsigned int seconds);
-void uthread_usleep(unsigned int usecs);
-void uthread_has_blocked(struct uthread *uthread, int flags);
-void uthread_paused(struct uthread *uthread);
-
-/* Utility functions */
-bool __check_preempt_pending(uint32_t vcoreid);        /* careful: check the code */
-void uth_disable_notifs(void);
-void uth_enable_notifs(void);
-
-/* Helpers, which sched_entry() can call */
-void highjack_current_uthread(struct uthread *uthread);
-void run_current_uthread(void);
-void run_uthread(struct uthread *uthread);
-
-/* Asking for trouble with this API, when we just want stacktop (or whatever
- * the SP will be). */
-static inline void init_uthread_ctx(struct uthread *uth, void (*entry)(void),
-                                    void *stack_bottom, uint32_t size)
-{
-       init_user_ctx(&uth->u_ctx, (long)entry, (long)(stack_bottom) + size);
-}
-
-#define uthread_set_tls_var(uth, name, val)                                    \
-({                                                                             \
-       typeof(val) __val = val;                                                   \
-       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
-       name = __val;                                                              \
-       end_access_tls_vars();                                                     \
-})
-
-#define uthread_get_tls_var(uth, name)                                         \
-({                                                                             \
-       typeof(name) val;                                                          \
-       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
-       val = name;                                                                \
-       end_access_tls_vars();                                                     \
-       val;                                                                       \
-})
-
-/* Generic Uthread Mutexes.  2LSs implement their own methods, but we need a
- * 2LS-independent interface and default implementation. */
-uth_mutex_t uth_mutex_alloc(void);
-void uth_mutex_free(uth_mutex_t m);
-void uth_mutex_lock(uth_mutex_t m);
-void uth_mutex_unlock(uth_mutex_t m);
-
-__END_DECLS
diff --git a/user/parlib/include/vcore.h b/user/parlib/include/vcore.h
deleted file mode 100644 (file)
index a965591..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-#pragma once
-
-#include <parlib/arch/vcore.h>
-#include <parlib/arch/atomic.h>
-#include <sys/param.h>
-#include <string.h>
-#include <parlib/timing.h>
-#include <parlib/common.h>
-
-__BEGIN_DECLS
-
-/*****************************************************************************/
-/* TODO: This is a complete hack, but necessary for vcore stuff to work for now
- * The issue is that exit sometimes calls sys_yield(), and we can't recover from
- * that properly under our vcore model (we shouldn't though).  We really need to
- * rethink what sys_yield 'should' do when in multicore mode, or else come up 
- * with a different syscall entirely. */
-#undef exit
-extern void _exit (int status);
-extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
-#define exit(status) _exit(status)
-/*****************************************************************************/
-
-#define LOG2_MAX_VCORES 6
-#define MAX_VCORES (1 << LOG2_MAX_VCORES)
-
-#define TRANSITION_STACK_PAGES 2
-#define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
-
-/* Defined in vcore.c */
-extern void vcore_entry();
-extern __thread bool __vcore_context;
-extern __thread int __vcoreid;
-extern __thread struct syscall __vcore_one_sysc;       /* see sys_change_vcore */
-
-/* Vcore API functions */
-static inline uint32_t max_vcores(void);
-static inline uint32_t num_vcores(void);
-static inline int vcore_id(void);
-static inline bool in_vcore_context(void);
-static inline bool in_multi_mode(void);
-static inline void __enable_notifs(uint32_t vcoreid);
-static inline void __disable_notifs(uint32_t vcoreid);
-static inline bool notif_is_enabled(uint32_t vcoreid);
-static inline bool vcore_is_mapped(uint32_t vcoreid);
-static inline bool vcore_is_preempted(uint32_t vcoreid);
-static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
-static inline bool preempt_is_pending(uint32_t vcoreid);
-static inline bool __preempt_is_pending(uint32_t vcoreid);
-static inline void *get_vcpd_tls_desc(uint32_t vcoreid);
-static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc);
-static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid);
-static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid);
-void vcore_lib_init(void);
-void vcore_change_to_m(void);
-int vcore_request(long nr_new_vcores);
-void vcore_yield(bool preempt_pending);
-void vcore_reenter(void (*entry_func)(void));
-void enable_notifs(uint32_t vcoreid);
-void disable_notifs(uint32_t vcoreid);
-void vcore_idle(void);
-void ensure_vcore_runs(uint32_t vcoreid);
-void cpu_relax_vc(uint32_t vcoreid);
-uint32_t get_vcoreid(void);
-bool check_vcoreid(const char *str, uint32_t vcoreid);
-void print_hw_tf(struct hw_trapframe *tf);
-void p