Removes c3po
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 6 Jun 2013 21:23:33 +0000 (14:23 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 6 Jun 2013 21:23:33 +0000 (14:23 -0700)
Anything c3po-specific (and not uthread-specific) can be reintroduced later as
a specific 2LS that inherits from uthreads, instead of being built on vcores.

68 files changed:
Makefile
tests/Makefile
tests/c3po/Makefrag [deleted file]
tests/c3po/c3po_test.c [deleted file]
user/c3po/Makefile [deleted file]
user/c3po/aio/Makefrag [deleted file]
user/c3po/aio/blocking_io.c [deleted file]
user/c3po/aio/blocking_io.h [deleted file]
user/c3po/aio/check_syscall [deleted file]
user/c3po/aio/diskio_aio.c [deleted file]
user/c3po/aio/diskio_blocking.c [deleted file]
user/c3po/aio/diskio_immediate.c [deleted file]
user/c3po/aio/diskio_kthread.c [deleted file]
user/c3po/aio/io_internal.h [deleted file]
user/c3po/aio/sockio_epoll.c [deleted file]
user/c3po/aio/sockio_poll.c [deleted file]
user/c3po/include/README [deleted file]
user/c3po/include/bits/pthreadtypes.h [deleted file]
user/c3po/include/capriccio.h [deleted file]
user/c3po/include/fptrcheck.h [deleted file]
user/c3po/include/pthread.h [deleted file]
user/c3po/include/semaphore.h [deleted file]
user/c3po/include/stackbounds.h [deleted file]
user/c3po/include/stacklink.h [deleted file]
user/c3po/stack/Makefrag [deleted file]
user/c3po/stack/fptr.c [deleted file]
user/c3po/stack/stack.c [deleted file]
user/c3po/threads/Makefrag [deleted file]
user/c3po/threads/blocking_graph.c [deleted file]
user/c3po/threads/blocking_graph.h [deleted file]
user/c3po/threads/mutex.c [deleted file]
user/c3po/threads/pthread.c [deleted file]
user/c3po/threads/pthreadtest.c [deleted file]
user/c3po/threads/readproc.c [deleted file]
user/c3po/threads/readproc.h [deleted file]
user/c3po/threads/resource_stats.c [deleted file]
user/c3po/threads/resource_stats.h [deleted file]
user/c3po/threads/sched_global_rr.c [deleted file]
user/c3po/threads/sched_graph_priority.c [deleted file]
user/c3po/threads/sched_graph_rr.c [deleted file]
user/c3po/threads/semaphore.h [deleted file]
user/c3po/threads/threadlib.c [deleted file]
user/c3po/threads/threadlib.h [deleted file]
user/c3po/threads/threadlib_internal.h [deleted file]
user/c3po/threads/ucontext.c [deleted file]
user/c3po/threads/ucontext.h [deleted file]
user/c3po/threads/vcore.c [deleted file]
user/c3po/util/Makefrag [deleted file]
user/c3po/util/atomic.h [deleted file]
user/c3po/util/clock.c [deleted file]
user/c3po/util/clock.h [deleted file]
user/c3po/util/config.c [deleted file]
user/c3po/util/config.h [deleted file]
user/c3po/util/debug.c [deleted file]
user/c3po/util/debug.h [deleted file]
user/c3po/util/libperfctr.h [deleted file]
user/c3po/util/linked_list.c [deleted file]
user/c3po/util/linked_list.h [deleted file]
user/c3po/util/object_pool.c [deleted file]
user/c3po/util/object_pool.h [deleted file]
user/c3po/util/occ_list.c [deleted file]
user/c3po/util/occ_list.h [deleted file]
user/c3po/util/plhash.c [deleted file]
user/c3po/util/plhash.h [deleted file]
user/c3po/util/timing.c [deleted file]
user/c3po/util/timing.h [deleted file]
user/c3po/util/util.h [deleted file]
user/c3po/util/utiltest.c [deleted file]

index 37707ce..1e8ed6f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -480,11 +480,6 @@ endif #ifeq ($(mixed-targets),1)
 user-dirs = parlib pthread benchutil
 pthread: parlib
 
-ifeq ($(ARCH),i686)
-user-dirs += c3po
-c3po: parlib
-endif
-
 PHONY += install-libs $(user-dirs)
 install-libs: $(user-dirs) symlinks
 
index e6ab685..a756db6 100644 (file)
@@ -24,7 +24,6 @@ TESTS_EXECS_CPP  = $(patsubst $(TESTS_DIR)/%.cc, \
                               $(OBJDIR)/$(TESTS_DIR)/%, \
                               $(TESTS_SRCS_CPP))
 
-include $(TESTS_DIR)/c3po/Makefrag
 include $(TESTS_DIR)/openmp/Makefrag
 
 STATIC := $(findstring static,$(CFLAGS_TESTS))
diff --git a/tests/c3po/Makefrag b/tests/c3po/Makefrag
deleted file mode 100644 (file)
index 1efd3b6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-C3PO_TESTS_DIR = $(TESTS_DIR)/c3po
-
-C3PO_TESTS_CFLAGS += $(CFLAGS_TESTS) \
-                     -I$(XCC_ROOT)/$(ARCH)-ros/sys-include/c3po
-
-ALL_C3PO_TEST_FILES = $(shell ls $(C3PO_TESTS_DIR)/*.c)
-
-C3PO_TESTS_LDLIBS := -lpthread -lm
-
-C3PO_TESTS_SRCS := $(ALL_C3PO_TEST_FILES)
-
-C3PO_TESTS_LDDEPENDS := $(C3PO_TESTS_DIR)/%.c 
-
-TESTS_EXECS_C  += $(patsubst $(C3PO_TESTS_DIR)/%.c, \
-                      $(OBJDIR)/$(C3PO_TESTS_DIR)/%, \
-                      $(C3PO_TESTS_SRCS))
-
-STATIC := $(findstring static,$(C3PO_TESTS_CFLAGS))
-$(OBJDIR)/$(C3PO_TESTS_DIR)/%: $(C3PO_TESTS_LDDEPENDS)
-       @echo + cc [C3PO_TESTS] $<
-       @mkdir -p $(@D)
-       $(Q)$(CC) $(C3PO_TESTS_CFLAGS) -o $@ $(C3PO_TESTS_LDFLAGS) \
-                 $(C3PO_TESTS_LDDIRS) $< $(C3PO_TESTS_LDLIBS)
-       @if [ "$(STATIC)" != "static" ]; then \
-               $(OBJDUMP) -S $@ > $@.asm; \
-               $(NM) -n $@ > $@.sym; \
-       fi
diff --git a/tests/c3po/c3po_test.c b/tests/c3po/c3po_test.c
deleted file mode 100644 (file)
index 4c3fa75..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <parlib.h>
-#include <unistd.h>
-#include <vcore.h>
-
-pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-#define printf_safe(...) {}
-//#define printf_safe(...) \
-       pthread_mutex_lock(&lock); \
-       printf(__VA_ARGS__); \
-       pthread_mutex_unlock(&lock);
-
-pthread_t t1;
-pthread_t t2;
-pthread_t t3;
-
-#define NUM_TEST_THREADS 100
-
-pthread_t my_threads[NUM_TEST_THREADS];
-void *my_retvals[NUM_TEST_THREADS];
-
-__thread int my_id;
-void *yield_thread(void* arg)
-{      
-       for (int i = 0; i < 100; i++) {
-               printf_safe("[A] pthread %p on vcore %d, itr: %d\n", pthread_self(), vcore_id(), i);
-               pthread_yield();
-               printf_safe("[A] pthread %p returned from yield on vcore %d, itr: %d\n",
-                           pthread_self(), vcore_id(), i);
-       }
-       return (void*)(pthread_self());
-}
-
-void *hello_thread(void* arg)
-{      
-       printf_safe("[A] pthread %p on vcore %d\n", pthread_self(), vcore_id());
-       return (void*)(pthread_self());
-}
-
-//int main(int argc, char** argv) 
-//{
-//     void *retval1 = 0;
-//     printf_safe("[A] About to create thread 1\n");
-//     pthread_create(&t1, NULL, &yield_thread, NULL);
-//     printf_safe("[A] About to join on thread 1\n");
-//     pthread_join(t1, &retval1);
-//}
-
-int main(int argc, char** argv) 
-{
-       void *retval1 = 0;
-       void *retval2 = 0;
-       void *retval3 = 0;
-
-       /* yield test */
-       printf_safe("[A] About to create thread 1\n");
-       pthread_create(&t1, NULL, &yield_thread, NULL);
-       printf_safe("[A] About to create thread 2\n");
-       pthread_create(&t2, NULL, &yield_thread, NULL);
-       printf_safe("[A] About to create thread 3\n");
-       pthread_create(&t3, NULL, &yield_thread, NULL);
-       /* join on them */
-       printf_safe("[A] About to join on thread 1\n");
-       pthread_join(t1, &retval1);
-       printf_safe("[A] Successfully joined on thread 1 (retval: %p)\n", retval1);
-       printf_safe("[A] About to join on thread 2\n");
-       pthread_join(t2, &retval2);
-       printf_safe("[A] Successfully joined on thread 2 (retval: %p)\n", retval2);
-       printf_safe("[A] About to join on thread 3\n");
-       pthread_join(t3, &retval3);
-       printf_safe("[A] Successfully joined on thread 3 (retval: %p)\n", retval3);
-
-       /* create and join on hellos */
-       for (int i = 0; i < NUM_TEST_THREADS; i++) {
-               printf_safe("[A] About to create thread %d\n", i);
-               pthread_create(&my_threads[i], NULL, &yield_thread, NULL);
-       }
-       for (int i = 0; i < NUM_TEST_THREADS; i++) {
-               printf_safe("[A] About to join on thread %d\n", i);
-               pthread_join(my_threads[i], &my_retvals[i]);
-               printf_safe("[A] Successfully joined on thread %d (retval: %p)\n", i,
-                           my_retvals[i]);
-       }
-       printf("Exiting cleanly!\n");
-} 
diff --git a/user/c3po/Makefile b/user/c3po/Makefile
deleted file mode 100644 (file)
index c868eb3..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-ARCH ?= none   # catch bugs
-CFLAGS_USER += -static -fomit-frame-pointer -DOPTIMIZE=2 -DNO_TIMING \
-               -Wno-deprecated-declarations
-LIBNAME = c3po
-SUBDIRS = util stack threads #aio 
-
-SRCDIR := 
-OBJDIR := $(SRCDIR)obj
-INCDIR = $(SRCDIR)include
-UTILDIR = $(SRCDIR)util
-STACKDIR = $(SRCDIR)stack
-THREADSDIR = $(SRCDIR)threads
-AIODIR = $(SRCDIR)aio
-
-INCS = -I$(INCDIR) -I$(UTILDIR) -I$(THREADSDIR) -I$(STACKDIR) -I.
-FINALLIB = $(OBJDIR)/lib$(LIBNAME).a
-
-uc = $(shell echo $(1) | tr a-z A-Z)
-lc = $(shell echo $(1) | tr A-Z a-z)
-libname = $(OBJDIR)/$(1)/lib$(1).a
-cleanname = $(1)-clean
-makefragname = $(1)/Makefrag
-filename = $(notdir $(1))
-dirname = $(dir $(1))
-
-CLEANS := $(foreach x, $(SUBDIRS), $(call cleanname,$(x)))
-MAKEFRAGS := $(foreach x, $(SUBDIRS), $(call makefragname,$(x)))
-LIBUCNAME := $(call uc, $(LIBNAME))
-
-all: $(FINALLIB)
-       @:
-
-include $(MAKEFRAGS)
-ALLOBJS = $(foreach x, $(SUBDIRS), $(wildcard $(OBJDIR)/$(x)/*.o))
-ALLLIBS = $(foreach x, $(SUBDIRS), $(call libname,$(x)))
-
-$(FINALLIB): $(ALLLIBS)
-       @echo + ar [$(LIBUCNAME)] $@
-       @mkdir -p $(@D)
-       $(Q)$(AR) rc $@ $(ALLOBJS)
-
-install: $(FINALLIB)
-       @cp $(FINALLIB) $(XCC_ROOT)/$(ARCH)-ros/lib/
-       @mkdir -p $(XCC_ROOT)/$(ARCH)-ros/include/$(LIBNAME)
-       @cp -R $(INCDIR)/* $(XCC_ROOT)/$(ARCH)-ros/include/$(LIBNAME)
-
-clean: $(CLEANS)
-       @echo + clean [$(LIBUCNAME)]
-       $(Q)rm -rf $(FINALLIB)
-       $(Q)rm -rf $(OBJDIR)
-       
diff --git a/user/c3po/aio/Makefrag b/user/c3po/aio/Makefrag
deleted file mode 100644 (file)
index 435347f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-AIO_NAME    := aio
-AIO_UCNAME  := $(call uc, $(AIO_NAME))
-AIO_CFLAGS  := $(CFLAGS)
-AIO_HEADERS := $(wildcard $(AIODIR)/*.h)
-AIO_CFILES  := $(wildcard $(AIODIR)/*.c)
-AIO_OBJDIR  := $(OBJDIR)/$(AIO_NAME)
-AIO_OBJS    := $(patsubst %.c, %.o, $(AIO_CFILES))
-AIO_OBJS    := $(foreach x, $(AIO_OBJS), $(AIO_OBJDIR)/$(call filename,$(x)))
-
-LIBAIO = $(AIO_OBJDIR)/lib$(AIO_NAME).a
-
-$(AIO_NAME)-clean:
-       @echo + clean [$(LIBUCNAME) $(AIO_UCNAME)]
-       $(V)rm -rf $(AIO_OBJS) $(LIBAIO)
-       $(V)rm -rf $(AIO_OBJDIR)
-
-$(LIBAIO): $(AIO_OBJS)
-       @echo + ar [$(LIBUCNAME) $(AIO_UCNAME)] $@
-       $(V)$(AR) rc $@ $^
-
-$(AIO_OBJDIR)/%.o: $(AIODIR)/%.c $(AIO_HEADERS)
-       @echo + cc [$(LIBUCNAME) $(AIO_UCNAME)] $<
-       @mkdir -p $(@D)
-       $(V)$(CC) $(AIO_CFLAGS) $(INCS) -o $@ -c $<
-
diff --git a/user/c3po/aio/blocking_io.c b/user/c3po/aio/blocking_io.c
deleted file mode 100644 (file)
index ae2bb69..0000000
+++ /dev/null
@@ -1,1582 +0,0 @@
-/**
- * blocking IO routines
- *
- * These routines make use of asynchronous IO and the signal/wait
- * calls of a threading package to provide a blocking IO abstraction
- * on top of underlying non-blocking IO calls.
- *
- * The semantics of these calls mirror those of the standard IO
- * libraries.
- **/
-
-#include "threadlib.h"
-#include "io_internal.h"
-#include "blocking_io.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <string.h>
-#include <malloc.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-// for socketcall stuff
-#include <linux/net.h>
-
-#define USE_NODELAY 0
-
-#ifndef DEBUG_blocking_io_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-#ifndef SYS_pread
-# ifdef __NR_pread
-#  define SYS_pread     __NR_pread
-#  define SYS_pwrite   __NR_pwrite
-# else
-#  define SYS_pread     180
-#  define SYS_pwrite   181
-# endif
-#endif
-
-// oontrol whether or not a user's nonblocking IO calls are actually nonblocking...
-#define ALLOW_USER_NONBLOCKING_IO 1
-
-#define DO_EXTRA_YIELDS 0
-
-
-// Timing counters
-static cap_timer_t poll_timer;
-static cap_timer_t extra_poll_timer;
-
-
-//////////////////////////////////////////////////////////////////////
-// Prototypes for internal functions
-//////////////////////////////////////////////////////////////////////
-
-// function pointers for IO routines
-
-void (*sockio_init)(void);
-int (*sockio_add_request)(iorequest_t* req);
-void (*sockio_poll)();
-
-void (*diskio_init)(void);
-int (*diskio_add_request)(iorequest_t* req);
-void (*diskio_poll)();
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// manage FD data structures
-//////////////////////////////////////////////////////////////////////
-
-// fdstructs are allocated in banks
-#define FD_BANK_SHIFT 15
-#define FDS_PER_BANK (1<<FD_BANK_SHIFT)  // 2^15
-#define FD_BANK_MASK (FDS_PER_BANK - 1)  // 2^15 - 1
-
-// allow up to 1 million  
-#define MAX_FD (1024*1024)
-#define MAX_BANK ((MAX_FD >> FD_BANK_SHIFT) + 1)
-fdstruct_t *fdstruct_list[MAX_BANK];
-
-int next_new_fd = 0;
-
-latch_t fdstruct_latch;
-
-fdstruct_t* get_fdstruct_no_dup_resolve(int fd);
-
-/**
- * find/allocate the fdstruct_t for the given fd
- * this will return the root fdstruct_t if the fd is a dup'ed one
- *
- * GAURANTEES: never return NULL
- **/
-fdstruct_t* get_fdstruct(int fd)
-{
-  fdstruct_t *res = get_fdstruct_no_dup_resolve(fd);
-  if (res->root_fds != NULL)
-    return res->root_fds;
-  return res;
-}
-
-/**
- * find/allocate a fdstruct_t, don't resolve to the root fd in a 
- * dup'ed list
- */
-fdstruct_t* get_fdstruct_no_dup_resolve(int fd)
-{
-  fdstruct_t *bank = fdstruct_list[fd >> FD_BANK_SHIFT];
-  fdstruct_t *fds;
-
-  // acquire lock
-  thread_latch( fdstruct_latch );
-
-  // allocate the bank, if necessary
-  if(bank == NULL) {
-    //bank = (fdstruct_t*) malloc(FDS_PER_BANK * sizeof(fdstruct_t));
-    bank = (fdstruct_t*) calloc(FDS_PER_BANK, sizeof(fdstruct_t));
-    assert(bank);
-    fdstruct_list[fd >> FD_BANK_SHIFT] = bank;
-  }
-
-  // do some lazy initialization of unused fdstruct_t's.  Lazy is MUCH
-  // better here, since we may never need to touch many of the pages,
-  // and hence don't need to take the unnecessary page faults.  Since
-  // fds are allocated sequentially, this should generally be quite
-  // fast.
-  //
-  // FIXME: the algorithm below is really bad if there is a big gap in
-  // FDs.
-  //
-  // FIXME: for now, assume that newly allocated memory is zeroed.
-  // This is not unreasonable, since newly mapped pages of VM are
-  // mapped copy-on-write to the zero page.  When we roll our own
-  // memory allocator, we'll need to be careful about this.
-  /*
-  if(fd >= next_new_fd) {
-    int firstbank = next_new_fd >> FD_BANK_SHIFT;
-    int lastbank = fd >> FD_BANK_SHIFT;
-    int i, first, last;
-
-    for(i=firstbank; i<=lastbank; i++) {
-      // allocate memory for the bank, if necessary
-      if( fdstruct_list[i] == NULL ) {
-        //fdstruct_list[i] = (fdstruct_t*) malloc(FDS_PER_BANK * sizeof(fdstruct_t));
-        fdstruct_list[i] = (fdstruct_t*) calloc(FDS_PER_BANK, sizeof(fdstruct_t));
-        assert( fdstruct_list[i] );
-      }
-
-      if(i==firstbank) first = next_new_fd & FD_BANK_MASK;
-      else first=0;
-
-      if(i==lastbank) last = fd & FD_BANK_MASK;
-      else last=FDS_PER_BANK-1;
-
-      // zero out all fdstructs up to the highest one.  NOTE that this
-      // also ensures that FD_UNUSED is set
-      bzero(&fdstruct_list[i][first], (last-first+1)*sizeof(fdstruct_t));
-    }
-
-    next_new_fd = fd+1;
-  }
-  */
-  thread_unlatch( fdstruct_latch );
-
-  fds = &(bank[fd & FD_BANK_MASK]);
-  if (fds->state == FD_UNUSED) {
-    fds->state = FD_CLOSED;
-    fds->fd = fd;
-  }
-
-  // NOTE: the init stuff below should now be unnecessary, since zero is the correct value for all defaults.
-    /*
-  if (fds->state == FD_UNUSED)
-    {
-      // We do not have record for this FD.
-      // It can be stdin/stdout or other FD not opened
-      // through our interface.
-      // Check whether this is a valid FD
-      off_t r;
-      r = syscall(SYS_lseek, fd, 0, SEEK_CUR);
-      if (r == -1 && errno == EBADF) {
-        thread_unlatch( fdstruct_latch );
-       assert (fds->fd == fd);
-       return fds;
-      }
-
-      // guess at the file type.  open(), accept(), etc. should re-set
-      // this, since they may know better.
-      //
-      // FIXME: this may not work for pipes, FIFOs, ttys, etc.
-      // FIXME: better solution is to override all functions that create new FDs
-      if (r == -1 && errno == ESPIPE)
-       fds->type = FD_SOCKET;
-      else
-       fds->type = FD_FILE;
-
-      fds->fd = fd;
-      fds->state = FD_UNKNOWN;
-      fds->off = (r>=0 ? r : 0);
-
-      debug("Added FD %d as %s\n", fd, (fds->type==FD_FILE ? "FD_FILE" : "FD_SOCKET"));
-    }
-    */
-
-  assert (fds->fd == fd);
-  return fds;
-}
-
-static inline void zero_fdstruct(fdstruct_t *fds)
-{
-  int fd = fds->fd;
-  bzero(fds, sizeof(fdstruct_t));
-  fds->fd = fd;
-  fds->state = FD_CLOSED;
-}
-
-// internal function to close a fd
-// this involves handling of dup'ed fds
-static void close_fd(int fd)
-{
-  fdstruct_t *fds = get_fdstruct_no_dup_resolve(fd);
-  debug("fd=%d\n", fd);
-  
-  if(fds->state != FD_CLOSED) {
-    cpu_tick_t lifetime;
-    GET_REAL_CPU_TICKS( lifetime );
-    lifetime -= fds->time_opened; 
-    if( fds->type == FD_SOCKET )
-      thread_stats_close_socket( lifetime );
-    else
-      thread_stats_close_file( lifetime );
-  }
-
-
-  // zero or one fds in the dup list
-  if (fds->next_fds == NULL  ||  fds->next_fds == fds)
-  {
-    zero_fdstruct( fds );
-  } 
-
-  // this is the messiest case
-  // we're closing the root fd, while there are dup'ed fds
-  // we migrate the file state to the next dup'ed fd and make that fd the root fd
-  //
-  // FIXME: this could be done cleaner if we maintain a separate struct for each open file besides
-  // each fd and put all info (e.g. offset) there
-  // - zf
-  else if (fds->root_fds == fds) {
-
-    fdstruct_t *new_root_fds = fds->next_fds;
-
-    assert (new_root_fds != fds);
-    debug("closing old root fd: %d, new root fd: %d\n", fds->fd, new_root_fds->fd);
-
-
-    // copy info to the new root
-    {
-      int saved_fd = new_root_fds->fd;
-      *new_root_fds = *fds;
-      new_root_fds->fd = saved_fd;
-      new_root_fds->root_fds = new_root_fds;
-    }
-
-    // close the old root fds
-    zero_fdstruct( fds );
-
-    // set new root fd in all dup'ed fd structs
-    {
-      fdstruct_t *next = new_root_fds->next_fds;
-      while (next != new_root_fds) {
-        next->root_fds = new_root_fds;
-        next = next->next_fds;
-      }
-    }
-
-  } 
-
-
-  // there are other dup'ed fds open for this file
-  // we should just close the current fd, not the root fd that holds info about this open file
-  else {
-    fdstruct_t *pre_fds = fds;
-    fdstruct_t *cur_fds = pre_fds->next_fds;
-    while (cur_fds != fds) {
-      pre_fds = cur_fds;
-      cur_fds = cur_fds->next_fds;
-    }
-
-    debug("closing dup'ed fd: %d, root fd: %d\n", fd, fds->fd);
-    
-    // delete cur_fds from the dup list
-    pre_fds->next_fds = cur_fds->next_fds;
-
-    // close cur_fds
-    zero_fdstruct( fds );
-  }
-}
-
-
-
-// internal function to dup a fd
-static void dup_fd(int oldfd, int newfd)
-{
-  fdstruct_t *oldfds, *newfds;
-  debug("oldfd=%d, newfd=%d\n", oldfd, newfd);
-
-  // Clear out the fdstruct_t.  newfd should have already been closed by dup or fcntl.
-  close_fd( newfd );
-
-  oldfds = get_fdstruct_no_dup_resolve(oldfd);
-  newfds = get_fdstruct_no_dup_resolve(newfd);
-
-
-  // the dup list is currently empty
-  if( oldfds->root_fds == NULL )
-    oldfds->root_fds = oldfds->next_fds = oldfds;
-
-  newfds->state = FD_OPEN;
-  GET_REAL_CPU_TICKS( newfds->time_opened );
-  if( oldfds->type == FD_SOCKET )
-    thread_stats_open_socket();
-  else
-    thread_stats_open_file();
-  
-  // add newfds to the linked list of all dup'ed fds
-  newfds->root_fds = oldfds->root_fds;
-  newfds->next_fds = oldfds->next_fds;
-  oldfds->next_fds = newfds;
-}
-
-
-/**
- * Add a request to the fd's wait list
- **/
-inline void add_waiter(iorequest_t *req)
-{
-  thread_latch( req->fds->reqlatch );
-  ll_add_existing_to_tail(&req->fds->reqlist, (linked_list_entry_t*)req);
-  thread_unlatch( req->fds->reqlatch );
-}
-
-/**
- * remove a specific waiter from the request list
- **/
-inline void remove_waiter(iorequest_t *req) 
-{
-  thread_latch( req->fds->reqlatch );
-  ll_remove_entry(&req->fds->reqlist, (linked_list_entry_t*)req);
-  thread_unlatch( req->fds->reqlatch );
-}
-
-/**
- * retrieve the head of the waiter list
- **/
-inline iorequest_t* remove_first_waiter(fdstruct_t *fds) 
-{
-  iorequest_t *req;
-  thread_latch( fds->reqlatch );
-  req = (iorequest_t*) ll_remove_head(&fds->reqlist);
-  thread_unlatch( fds->reqlatch );
-  return req;
-}
-
-/**
- * return the number of waiters
- **/
-inline iorequest_t* view_first_waiter(fdstruct_t *fds)
-{
-  iorequest_t *req;
-  thread_latch( fds->reqlatch );
-  req = (iorequest_t*) ll_view_head(&fds->reqlist);
-  thread_unlatch( fds->reqlatch );
-  return req;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// perform IO requests
-//////////////////////////////////////////////////////////////////////
-
-// internal stats provided by nio.c.  Replicated here to remove
-// compile errors in benchmarks when not using nio.
-int __cap_outstanding_disk_requests;
-int __epoll_wait_count, __epoll_wait_return_count;
-int __io_getevents_count, __io_getevents_return_count;
-
-static ssize_t do_rw(iotype type, int fd, void *buf, size_t count, off_t offset)
-{
-  iorequest_t req;
-  int res;
-  
-  tdebug("type=%d  fd=%d\n", type, fd);
-
-  if(fd < 0) { errno = EBADFD; return -1; }
-  
-  // get the fd structure
-  req.fds = get_fdstruct(fd);
-
-  if ( !cap_override_rw || (ALLOW_USER_NONBLOCKING_IO && req.fds->nonblocking)) {
-    // bypass all our wrapping when user wants true nonblocking i/o
-    tdebug("non-blocking i/o\n");
-    switch (type) {
-    case READ:   res = syscall(SYS_read, fd, buf, count); break;
-    case WRITE:  res = syscall(SYS_write, fd, buf, count); break;
-    case PREAD:  res = syscall(SYS_pread, fd, buf, count, offset); break;
-    case PWRITE: res = syscall(SYS_pwrite, fd, buf, count, offset); break;
-    default: res = -1; assert(0);
-    }
-    // weird hack - for some reason read() retuns -1, but sets errno=0 sometimes.  ;-/
-    if( res == -1 && errno == 0 )
-      errno = EAGAIN;
-#ifdef DO_EXTRA_YIELDS
-    if( cap_override_rw ) thread_yield();
-#endif
-    CAP_CLEAR_SYSCALL();
-    return res;
-  }
-  
-  req.type = type;
-  req.args.rw.buf = buf;
-  req.args.rw.count = count;
-  req.args.rw.off = offset;
-  req.thread = thread_self();
-
-  // add to the request list
-  add_waiter(&req);
-  
-  // do a request, based on fd type.  The add_request() call should
-  // suspend the thread.
-  if(req.fds->type == FD_SOCKET) {
-    IOSTAT_START(sockio);
-    res = sockio_add_request(&req);
-    IOSTAT_DONE(sockio, res<0);
-    if( res >= 0 ) {
-      if( type == READ || type == PREAD )    sockio_stats.bytes_read += res;
-      else                                   sockio_stats.bytes_written += res;
-    }
-  } else {
-    IOSTAT_START(diskio);
-    res = diskio_add_request(&req);
-    IOSTAT_DONE(diskio, res<0);
-    if( res >= 0) {
-      if( type == READ || type == PREAD )    diskio_stats.bytes_read += res;
-      else                                   diskio_stats.bytes_written += res;
-    }
-  }
-
-  // attempt to remove the request, just to be sure...
-  remove_waiter(&req);
-
-  tdebug("io done. rv=%d\n", res);
-  CAP_CLEAR_SYSCALL();
-  return res;
-}
-
-inline static int set_nonblocking(int fd)
-{
-  int flags = 1;
-  if (ioctl(fd, FIONBIO, &flags) &&
-      ((flags = syscall(SYS_fcntl, fd, F_GETFL, 0)) < 0 ||
-       syscall(SYS_fcntl, fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
-    int myerr = errno;
-    syscall(SYS_close, fd);
-    errno = myerr;
-    fatal("can't set fd %d to nonblocking IO!!\n", fd);
-    return -1;
-  }  
-  return 0;
-}
-
-inline static int set_blocking(int fd)
-{
-  int flags = 0;
-  if (ioctl(fd, FIONBIO, &flags) &&
-      ((flags = syscall(SYS_fcntl, fd, F_GETFL, 0)) < 0 ||
-       syscall(SYS_fcntl, fd, F_SETFL, flags & ~O_NONBLOCK) < 0)) {
-    int myerr = errno;
-    syscall(SYS_close, fd);
-    errno = myerr;
-    fatal("can't set fd %d to blocking IO!!\n", fd);
-    return -1;
-  }  
-  return 0;
-}
-
-#ifdef USE_NODELAY
-inline static int set_tcp_nodelay(int fd)
-{
-  int enable = 1;
-  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)) < 0) {
-    int myerr = errno;
-    syscall(SYS_close, fd);
-    errno = myerr;
-    if( errno != ENOTSUP && errno != ENOPROTOOPT ) {
-      perror("setsockopt(..., TCP_NODELAY, ...)");
-      //fatal("can't set fd %d to TCP_NODELAY!!\n", fd);
-      //return -1;
-    }
-  }
-  return 0;
-}
-#endif
-
-
-//////////////////////////////////////////////////////////////////////
-// support for making user-land poll requests async
-//
-// extra polling support
-// these entries are timed polls the user program calls
-//
-// See the definition of poll() below, for the other half of these routines
-//////////////////////////////////////////////////////////////////////
-
-typedef struct st_poll_entry {
-  thread_t *t;
-  struct pollfd *ufds;
-  int nfds;
-  int res;    // != 0 means the poll is finished
-  int pollcount;  // FIXME: this is for debug only
-  int *pos;       // points to a int that holds the position of this entry in the list
-                  // this is used to help the thread that creates this entry keep track of it
-                  // because the entry could be moved around but other threads
-} poll_entry_t;
-
-#define MAX_EXTRA_POLL_ENTRIES 1024
-static poll_entry_t extra_poll_entries[MAX_EXTRA_POLL_ENTRIES];
-int num_extra_polls = 0;
-
-extern unsigned long long start_usec;
-
-// process all poll requests in extra_poll_entries[]
-inline void extra_poll()
-{
-  int i;
-  for (i = 0; i < num_extra_polls; i++) {
-    poll_entry_t *e = &extra_poll_entries[i];
-    int rv = 0;
-    if (e->res)   // already finished
-      continue;
-//    debug("polling extra poll %d\n", i);
-    rv = syscall(SYS_poll, e->ufds, e->nfds, 0); 
-    e->pollcount++;
-    if (rv != 0)  // something happens
-      {
-       e->res = rv;
-       thread_resume(e->t);
-       tdebug("poll done after %d tries, rv=%d, ufds[0].revents=%x.\n", e->pollcount, rv, e->ufds[0].revents);
-       // we do not delete the entry now
-       // because the thread issueing the request
-       // needs to gather the return value
-       // however the entry will not be polled again
-       // because its res value is not 0 now
-      }
-  }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// External routines
-//////////////////////////////////////////////////////////////////////
-
-// from glibc source: include/libc-symbols.h
-# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
-# define _strong_alias(name, aliasname) \
-  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
-
-inline ssize_t read(int fd, void *buf, size_t count)
-{
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d  buf=%p  count=%d\n",fd, buf, count);
-  return do_rw(READ, fd, buf, count, (off_t)-1);
-}
-strong_alias (read, __read);
-
-inline ssize_t write(int fd, const void *buf, size_t count)
-{
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d  buf=%p  count=%d\n",fd, buf, count);
-  return do_rw(WRITE, fd, (void*) buf, count, (off_t)-1);
-}
-strong_alias (write, __write);
-
-inline ssize_t pread(int fd, void *buf, size_t count, off_t offset)
-{
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d  buf=%p  count=%d  off=%lud\n",fd, buf, count, offset);
-  return do_rw(PREAD, fd, buf, count, offset);
-}
-strong_alias (pread, __pread);
-
-inline ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
-{
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d  buf=%p  count=%d  off=%lud\n",fd, buf, count, offset);
-  return do_rw(PWRITE, fd, (void*) buf, count, offset);
-}
-strong_alias (pwrite, __pwrite);
-
-// bogus readv(), writev()
-inline ssize_t readv(int fd, const struct iovec *vector, int count)
-{
-  (void) fd,
-  (void) vector;
-  (void) count;
-  CAP_SET_SYSCALL();
-  tdebug(" \n");
-  errno = ENOSYS;
-  CAP_CLEAR_SYSCALL();
-  return -1;
-}
-strong_alias (readv, __readv);
-
-inline ssize_t writev(int fd, const struct iovec *vector, int count)
-{
-  // foolish implementation
-  int i, rv, total = 0;
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d, count=%d\n", fd, count);
-  for (i=0; i < count; i++) {
-    rv = write(fd, (vector+i)->iov_base, (vector+i)->iov_len);
-    if (rv == -1) {
-      CAP_CLEAR_SYSCALL();
-      return rv;
-    }
-    total += rv;
-  }
-  CAP_CLEAR_SYSCALL();
-  return total;
-}
-strong_alias (writev, __writev);
-
-
-/**
- * wrapper for open()
- **/
-int open(const char *pathname, int flags, ...)
-{
-  mode_t mode;
-  int fd;
-  fdstruct_t *fds;
-  va_list ap;
-  
-  if(flags & O_CREAT) {
-    va_start(ap, flags);
-    mode = va_arg(ap, mode_t);
-    va_end(ap);
-  } else {
-    mode = 0744; // this is ignored anyway
-  }
-
-  if( !cap_override_rw ) {
-    return syscall(SYS_open, pathname, flags, mode);
-  }
-
-  tdebug("path=%s\n",pathname);
-
-  flags |= O_NONBLOCK;
-  //flags &= ~O_NONBLOCK;
-
-  CAP_SET_SYSCALL();
-#ifdef DO_EXTRA_YIELDS
-  if( cap_override_rw ) thread_yield();
-#endif
-  fd = syscall(SYS_open,pathname, flags, mode);
-  CAP_CLEAR_SYSCALL();
-  tdebug("fd=%d\n", fd);
-  if(fd < 0) 
-    return fd;
-
-  // set the file back to blocking mode, so the IO routines will wait correctly for completions
-  // FIXME: 1. this should perhaps depend on what sort of disk IO is being used
-  // FIXME: 2. This may be problematic for things like pipes, special
-  // devices, etc. - those should perhaps go through the poll
-  // interface. (?)
-  //  if( set_blocking(fd) != 0 )
-  //  return -1;
-
-
-  fds = get_fdstruct_no_dup_resolve(fd);
-  zero_fdstruct( fds );
-  fds->state = FD_OPEN;
-  fds->type = FD_FILE;
-
-  // FIXME: there is an ugly initialization race here, if we don't do
-  // this check.  This is a pretty hacky solution, though - find a
-  // better one!!
-  if( cap_override_rw )
-    GET_REAL_CPU_TICKS( fds->time_opened );
-  thread_stats_open_file();
-  
-  return fd;
-}
-strong_alias (open, __open);
-
-
-/**
- * wrapper for creat()
- **/
-inline int creat(const char *pathname, mode_t mode)
-{
-  CAP_SET_SYSCALL();
-  tdebug("path=%s\n",pathname);
-  return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
-}
-strong_alias (creat, __creat);
-
-/**
- * wrapper for close()    
- **/
-int close(int fd)
-{
-  tdebug("fd=%d\n",fd);
-  if(fd < 0) { errno = EBADFD; return -1; }
-  
-  // FIXME: need to clean up outstanding requests, so we don't have
-  // confusion when the OS re-uses this FD.  For FDs accessed by a
-  // single thread, there will never be other outstanding requets.
-  // For FDs accessed by multiple threads, it probably makes sense to
-  // wait for the other IOs to complete before closing.  The best way
-  // to do this is to add a CLOSE request type, and just queue this
-  // along w/ everything else.
-  // 
-  // It might be good to track this anyway, to inform the programmer,
-  // since outstanding requests here means there is a race in the app
-  // anyway.  The only time this really makes sense is if multiple
-  // threads are accessing a particular file, and an IO error occurrs
-  // that should effect all of them.  In this case, the order doesn't
-  // matter, since all requests that are submitted to the kernel after
-  // the IO error occurs will simply return errors anyway.
-
-
-  close_fd(fd);
-
-  {
-    int ret;
-    CAP_SET_SYSCALL();
-#ifdef DO_EXTRA_YIELDS
-    thread_yield();
-#endif
-    //thread_usleep(100);
-    //markmark
-
-    ret = syscall(SYS_close,fd);
-    CAP_CLEAR_SYSCALL();
-    return ret;
-  }
-
-  
-
-  // FIXME: close always takes a long time - why??
-  //return syscall(SYS_close,fd);
-}
-strong_alias (close, __close);
-
-/**
- * wrapper for lseek.  Keep track of current file offset, for async disk routines.
- **/
-inline off_t lseek(int fd, off_t off, int whence) 
-{
-  int res;
-  fdstruct_t *fds;
-
-  tdebug("fd=%d, off=%ld, whence=%d\n",fd, off, whence);
-  if(fd < 0) { errno = EBADFD; return -1; }
-
-  fds = get_fdstruct(fd);
-
-  if (fds->state != FD_OPEN) {
-    errno = EBADF;
-    return -1;
-  }
-
-  if (fds->type != FD_FILE) {
-    errno = ESPIPE;
-    return -1;
-  }
-
-  // FIXME: we _could_ skip the seek if we are using linux aio.  This
-  // causes trouble with directory functions, however, since we do not
-  // catch readdir()/getdents(), and these make use of lseek.
-  res = syscall(SYS_lseek, fd, off, whence);
-  if (res != -1)
-    fds->off = res;
-
-  /*
-    // FIXME: we don't need this, since we actually just do the system call.
-  switch(whence) {
-  case SEEK_SET: fds->off = off; res = fds->off; break;
-  case SEEK_CUR: fds->off += off; res = fds->off; break;
-  case SEEK_END: assert(0); break;   // FIXME
-  default: res = (off_t)-1; errno = EINVAL;
-  }
-  */
-  
-  return res;
-}
-strong_alias (lseek, __lseek);
-
-
-/**
- * wrapper for fcntl.  we only need this for dup-ed fds. 
- **/
-int fcntl(int fd, int cmd, ...)
-{
-  int res;
-  va_list ap;
-  tdebug("fd=%d\n",fd);
-  if(fd < 0) { errno = EBADFD; return -1; }
-
-  va_start(ap, cmd);
-
-  switch( cmd ) {
-
-    // set up FD correctly for F_DUPFD
-  case F_DUPFD: {
-    long newfd = va_arg(ap, long);
-    // FIXME: this might block on closing newfd
-    CAP_SET_SYSCALL();
-#ifdef DO_EXTRA_YIELDS
-    thread_yield();
-#endif
-    res = syscall(SYS_fcntl, fd, cmd, newfd);
-    CAP_CLEAR_SYSCALL();
-    debug("F_DUPFD: fd=%d, newfd=%ld, res=%d\n", fd, newfd, res);
-    if(res < 0) return res;
-    dup_fd(fd, res);
-    break;
-  }
-    // struct flock* arg
-  case F_GETLK: case F_SETLK: case F_SETLKW: {
-    struct flock *arg = va_arg(ap, struct flock *);
-    // FIXME: this could block - don't allow them.
-    assert( cmd != F_SETLKW );
-    res = syscall(SYS_fcntl, fd, cmd, arg);
-    break;
-  }
-    // no arg cases, just to be clean
-  case F_GETFD: case F_GETOWN: 
-    //case F_GETSIG: // linux-specific.  should be OK w/ below, so leave it out
-    res = syscall(SYS_fcntl, fd, cmd);
-    break;
-
-  case F_GETFL: {
-    fdstruct_t *fds = get_fdstruct(fd);
-    res = syscall(SYS_fcntl, fd, cmd);
-    if( !fds->nonblocking ) // clear 
-      res &= ~O_NONBLOCK;
-    break;
-  }
-  case F_SETFL: {
-    long arg = va_arg(ap, long);
-    fdstruct_t *fds = get_fdstruct(fd);
-    if (arg & O_NONBLOCK)
-    {
-      fds->nonblocking = 1;
-      debug("setting fd=%d to non-blocking mode\n", fd);
-    } else {
-      fds->nonblocking = 0;
-      debug("setting fd=%d to blocking mode\n", fd);
-    }
-    // we should not let the user set the fd to blocking mode
-    arg |= O_NONBLOCK;  // FIXME: we need to coax the user with F_GETFL too
-    res = syscall(SYS_fcntl, fd, cmd, arg);
-    break;
-  }
-
-    // no arg and long arg can be treated the same, since fcntl() will
-    // ignore the spurious long() arg.
-  default: {
-    long arg = va_arg(ap, long);
-    res = syscall(SYS_fcntl, fd, cmd, arg);
-    break;
-    }
-  }
-  
-  va_end(ap);
-
-  return res;
-}
-strong_alias (fcntl, __fcntl);
-
-
-/**
- * wrapper for connect.  suspend the thread while the connection takes place.
- **/
-int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
-{
-  fdstruct_t *fds;
-  int res;
-  tdebug("fd=%d\n",sockfd);
-  if(sockfd < 0) { errno = EBADFD; return -1; }
-
-  // set nonblocking.  NOTE: we do this here rather than in socket(),
-  // on the off chance that someone passes us a valid socket not
-  // obtained via socket() (for example, something that was dup-ed.
-  if( set_nonblocking(sockfd) < 0 )  return -1;
-
-  // start the connect operation.  
-  //
-  // FIXME: the socketcall stuff here is both ugly and linux-specific.
-  // This should be abstracted for portability.
-  (void) serv_addr;
-  (void) addrlen;
-  res = syscall(SYS_socketcall, SYS_CONNECT, &sockfd);
-  if(res == -1 && errno != EINPROGRESS)
-    return res;
-
-  // initialize the fdstruct
-  fds = get_fdstruct(sockfd);
-  fds->type = FD_SOCKET;
-  fds->state = FD_CLOSED;
-
-  // connection is in progress, so block until done
-  if(res==-1) {
-    iorequest_t req;
-    int err;
-    socklen_t len = sizeof(err);
-
-    req.fds = fds;
-    req.type = CONNECT;
-    req.thread = thread_self();
-
-    // block
-    add_waiter(&req);
-    CAP_SET_SYSCALL();
-    IOSTAT_START(sockio);
-    res = sockio_add_request(&req);
-    IOSTAT_DONE(sockio,res<0);
-    CAP_CLEAR_SYSCALL();
-    remove_waiter(&req);
-
-    if( res < 0)
-      return -1; 
-
-    // call getsockopt() to see if the connect() succeeded
-    res = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len);
-    assert(res == 0);
-    if(err > 0) {
-      errno = err;
-      return -1;
-    }
-    assert(err == 0);
-  }
-
-#ifdef USE_NODELAY
-  if( set_tcp_nodelay(sockfd) < 0 )  return -1;
-#endif
-
-  // successfully created connection
-  fds->state = FD_OPEN;
-  thread_stats_open_socket();
-  GET_REAL_CPU_TICKS( fds->time_opened );
-  return 0;
-}
-strong_alias (connect, __connect);
-
-#define HP_TIMING_NOW(Var)      __asm__ __volatile__ ("rdtsc" : "=A" (Var))
-unsigned long rdtsc;
-
-/**
- * wrapper for accept.  
- **/
-int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
-{
-  fdstruct_t *fds;
-  int res;
-  unsigned long args[4];
-  tdebug("fd=%d\n",sockfd);
-
-  args[0] = (unsigned long)sockfd;
-  args[1] = (unsigned long)addr;
-  args[2] = (unsigned long)addrlen;
-  args[3] = (unsigned long)SOCK_NONBLOCK;
-
-  if(sockfd < 0) { errno = EBADFD; return -1; }
-  fds = get_fdstruct(sockfd);
-
-  // set nonblocking.  NOTE: we do this here rather than in socket(),
-  // on the off chance that someone passes us a valid socket not
-  // obtained via socket() (for example, something that was dup-ed.
-  if( fds->state != FD_LISTENING ) {
-    fds->state = FD_LISTENING;
-
-    if (set_nonblocking(sockfd) == -1) {
-      fatal("failed to set accept socket to nonblocking IO\n");
-      return -1;
-    }
-  }
-
-  // try the syscall first 
-  res = -1;
-  res = syscall(SYS_socketcall, SYS_ACCEPT4, args);
-
-  // do the accept request
-  if( res < 0  &&  (errno == EAGAIN || errno == EWOULDBLOCK) ){
-    iorequest_t req;
-
-    // set up a request
-    req.fds = fds;
-    req.type = ACCEPT;
-    req.args.scall.which = SYS_ACCEPT;
-    req.args.scall.argv = &sockfd;
-    req.thread = thread_self();
-
-    // block
-    add_waiter(&req);
-    CAP_SET_SYSCALL();
-    IOSTAT_START(sockio);
-    res = sockio_add_request(&req);
-    IOSTAT_DONE(sockio, res<0);
-    CAP_CLEAR_SYSCALL();
-    remove_waiter(&req);
-  }
-
-  // allocate the fdstruct_t
-  if(res >= 0) {
-    fdstruct_t *newfds = get_fdstruct(res);
-    zero_fdstruct( newfds );
-    newfds->type = FD_SOCKET;
-    newfds->state = FD_OPEN;
-    GET_REAL_CPU_TICKS( newfds->time_opened );
-
-    if (set_nonblocking(res) == -1) return -1;
-#ifdef USE_NODELAY
-    if (set_tcp_nodelay(res) == -1) return -1;
-#endif
-
-    thread_stats_open_socket();
-  } 
-
-  else {
-    perror("error response from accept()");
-  }
-
-  HP_TIMING_NOW(rdtsc);
-  tdebug("rv=%d, rdtsc=%lu\n", res, rdtsc);
-        
-  return res;
-}
-strong_alias (accept, __accept);
-
-/**
- * wrapper for poll.
- **/
-int poll(struct pollfd *ufds, nfds_t nfds, int timeout)
-{
-  int rv, sus_rv, i;
-  long utimeout;
-  tdebug("nfds=%d, timeout=%d, ufds[0].fd=%d\n", (int)nfds, timeout, ufds[0].fd);
-  CAP_SET_SYSCALL();
-
-  if (0 && timeout == 0) {
-    // no timeout required
-    // delegate to syscall directly
-    tdebug("poll delegated to syscall.\n"); 
-    return syscall(SYS_poll, ufds, nfds, 0);
-  }
-
-  // FIXME: turn this into a blocking call w/ no timeout, if there is only one fd
-
-#if 1
-  if( nfds == 1 ) {
-    iorequest_t req;
-    int res;
-
-    // set up a request
-    req.fds = get_fdstruct( ufds[0].fd );
-    req.type = POLL1;
-    req.args.poll1.ufds = ufds;
-    req.thread = thread_self();
-
-    // block
-    add_waiter(&req);
-    CAP_SET_SYSCALL();
-    IOSTAT_START(sockio);
-    res = sockio_add_request(&req);
-    IOSTAT_DONE(sockio, res<0);
-    CAP_CLEAR_SYSCALL();
-    remove_waiter(&req);
-    
-    return res;
-  }
-
-  assert( 0 ); // works for apache...  ;-)
-#endif
-
-  utimeout = timeout * 1000;
-
-  assert (num_extra_polls < MAX_EXTRA_POLL_ENTRIES);
-
-  i = num_extra_polls;
-  extra_poll_entries[i].t = thread_self();
-  extra_poll_entries[i].ufds = ufds;
-  extra_poll_entries[i].nfds = nfds;
-  extra_poll_entries[i].res = 0;
-  extra_poll_entries[i].pollcount = 0;
-  extra_poll_entries[i].pos = &i;     // i will be updated if this entry is moved by other threads
-  
-  num_extra_polls++;
-
-  tdebug("poll count=%d, timeout=%ld\n", num_extra_polls, utimeout);
-  
-  sus_rv = thread_suspend_self(utimeout);
-
-  assert(extra_poll_entries[i].ufds == ufds);   // make sure we have the same entry
-
-  // this result is correct no matter whether timeout happens
-  // RACE: sus_rv == TIMEDOUT doesn't mean the poll is not successful
-  // the sequence can be: timeout -> poll gets events -> this thread is scheduled
-  rv = extra_poll_entries[i].res;
-
-  // delete the entry
-  assert(num_extra_polls > 0);   // contains at least our entry
-  memcpy(&extra_poll_entries[i], 
-        &extra_poll_entries[num_extra_polls - 1],
-        sizeof(poll_entry_t)); // copy the last entry over
-  *extra_poll_entries[i].pos = i;   // update its position pointer
-  num_extra_polls--;
-  
-  tdebug("poll finished, count=%d\n", num_extra_polls);
-
-  return rv;
-}
-strong_alias (poll, __poll);
-
-/**
- * wrapper for select
- * this is not fully implemented (no blocking select supported
- */
-int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
-{
-  int ret;
-  CAP_SET_SYSCALL();
-  tdebug("count=%d\n", n);
-                
-  if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
-    // nonblocking polling
-#ifdef DO_EXTRA_YIELDS
-    thread_yield();
-#endif
-    ret = syscall(SYS_select, n, readfds, writefds, exceptfds, timeout);
-  } else if (readfds == NULL && writefds == NULL && exceptfds == NULL) {
-    // barf if the timeout would wrap around.  4294 = 2^32 / 10^6
-    assert( timeout->tv_sec < 4294 );  
-    thread_usleep((unsigned) timeout->tv_sec * 1000000 + (unsigned)timeout->tv_usec);
-    ret = 0;
-  } else {
-    output("blocking select() not implemented!\n");
-    ret = -1;
-    assert(0);
-  }
-  
-
-  CAP_CLEAR_SYSCALL();
-  return ret;
-}
-strong_alias(select, __select);
-
-// FIXME: do the same thing for pselect()
-
-
-/**
- * wrapper for dup
- **/
-int dup(int oldfd)
-{
-  int newfd;
-  CAP_SET_SYSCALL();
-  tdebug("fd=%d\n",oldfd);
-  if(oldfd < 0) { errno = EBADFD; return -1; }
-
-#ifdef DO_EXTRA_YIELDS
-  thread_yield();
-#endif
-  newfd = syscall(SYS_dup,oldfd);
-  if(newfd != -1) {
-    dup_fd(oldfd, newfd);
-  }
-  CAP_CLEAR_SYSCALL();
-  return newfd;
-}
-strong_alias (dup, __dup);
-
-
-/**
- * wrapper for dup2
- **/
-int dup2(int oldfd, int newfd)
-{
-  int ret;
-  tdebug("oldfd=%d newfd=%d\n",oldfd,newfd);
-
-  if(oldfd < 0) { errno = EBADFD; return -1; }
-  
-  CAP_SET_SYSCALL();
-#ifdef DO_EXTRA_YIELDS
-  thread_yield();
-#endif
-  ret = syscall(SYS_dup2, oldfd, newfd);
-  //res = __dup2(oldfd, newfd);  // alternative?
-  CAP_CLEAR_SYSCALL();
-
-  dup_fd(oldfd, newfd);
-
-  return ret;
-}
-strong_alias (dup2, __dup2);
-
-/**
- * Sleep
- **/
-// FIXME: what about signals?
-unsigned int sleep(unsigned int sec) {
-  CAP_SET_SYSCALL();
-  thread_usleep((unsigned long long) sec * 1000000);
-  CAP_CLEAR_SYSCALL();
-  return 0;
-}
-strong_alias (sleep, __sleep);
-
-
-/**
- * usleep
- **/
-// FIXME: what about signals?
-int usleep(__useconds_t usec) {
-  tdebug("usec=%ld\n", (long)usec);
-  CAP_SET_SYSCALL();
-  thread_usleep(usec);
-  CAP_CLEAR_SYSCALL();
-  return 0;
-}
-strong_alias (usleep, __usleep);
-
-
-
-/**
- * wrapper for pipe.
- **/
-int pipe(int filedes[2])
-{
-  int ret = syscall(SYS_pipe, filedes);
-  if( ret == 0 ) {
-    fdstruct_t *fds;
-    fds = get_fdstruct(filedes[0]);  fds->state = FD_OPEN;    GET_REAL_CPU_TICKS( fds->time_opened );
-    fds = get_fdstruct(filedes[1]);  fds->state = FD_OPEN;    GET_REAL_CPU_TICKS( fds->time_opened );
-    thread_stats_open_socket();
-    thread_stats_open_socket();
-  }
-  return ret;
-}
-strong_alias (pipe, __pipe);
-
-
-int socketpair(int d, int type, int protocol, int sv[2])
-{
-  int ret;
-  (void) type; (void) protocol;
-
-  ret = syscall(SYS_socketcall, SYS_SOCKETPAIR, &d);
-  if( ret == 0 ) {
-    fdstruct_t *fds;
-    fds = get_fdstruct(sv[0]);  fds->state = FD_OPEN;    GET_REAL_CPU_TICKS( fds->time_opened );
-    fds = get_fdstruct(sv[1]);  fds->state = FD_OPEN;    GET_REAL_CPU_TICKS( fds->time_opened );
-    thread_stats_open_socket();
-    thread_stats_open_socket();
-  }
-  return ret;
-}
-strong_alias(socketpair, __socketpair);
-
-
-/*
-// FIXME: do some cleanup of thread lib state?
-int fork()
-{
-  assert(0);
-  return -1;
-}
-strong_alias (fork,__fork);
-*/
-
-// FIXME: do this
-
-
-
-// apache's DNS lookups have problems w/ this, so disable for now
-#if 0
-/**
- * This is the same for all of the send / recv functions
- **/
-static inline int sendrecv_aux(int type, int which, int fd, void *args)
-{
-  iorequest_t req;
-  int res;
-  (void) type;
-
-  // set up a request
-  req.fds = get_fdstruct(fd);
-  req.type = type;
-  req.args.scall.which = which;
-  req.args.scall.argv = args;
-  req.thread = thread_self();
-  
-  // block
-  add_waiter(&req);
-  IOSTAT_START(sockio);
-  res = sockio_add_request(&req);
-  IOSTAT_DONE(sockio, res<0);
-  CAP_CLEAR_SYSCALL();
-  remove_waiter(&req);
-  
-  return res;
-}
-
-/**
- * wrapper for send
- **/
-int send(int s, const void *msg, size_t len, int flags)
-{
-  (void) msg; (void) len;
-
-  if(flags & MSG_DONTWAIT)
-    return syscall(SYS_socketcall, SYS_SEND, &s);
-
-  flags |= MSG_DONTWAIT; // switch to nonblocking
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(SEND, SYS_SEND, s, &s);
-}
-strong_alias (send,__send);
-
-
-/**
- * wrapper for sendto
- **/
-int sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
-{
-  (void) msg; (void) len; (void) to; (void) tolen;
-
-  if(flags & MSG_DONTWAIT)
-    return syscall(SYS_socketcall, SYS_SENDTO, &s);
-
-  flags |= MSG_DONTWAIT; // switch to nonblocking
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(SEND, SYS_SENDTO, s, &s);
-}
-strong_alias (sendto,__sendto);
-
-/**
- * wrapper for sendmsg
- **/
-int sendmsg(int s, const struct msghdr *msg, int flags) 
-{
-  (void) msg;
-
-  if(flags & MSG_DONTWAIT)
-    return syscall(SYS_socketcall, SYS_SENDMSG, &s);
-
-  flags |= MSG_DONTWAIT; // switch to nonblocking
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(SEND, SYS_SENDMSG, s, &s);
-}
-strong_alias (sendmsg,__sendmsg);
-
-
-// FIXME: the recv functions don't properly handle the MSG_WAITALL
-// flag - this needs to be fixed in the IO polling functions!!
-
-/**
- * wrapper for recv()
- **/
-int recv(int s, void *buf, size_t len, int flags)
-{
-  (void) buf; (void) len; (void)flags;
-
-  assert( (flags & MSG_WAITALL) == 0 );
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(RECV, SYS_RECV, s, &s);
-}
-strong_alias (recv,__recv);
-
-  
-/**
- * wrapper for recvfrom()
- **/
-int recvfrom(int  s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
-{
-  (void) buf; (void) len; (void) from; (void) fromlen; (void) flags;
-
-  assert( (flags & MSG_WAITALL) == 0 );
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(RECV, SYS_RECVFROM, s, &s);
-}
-strong_alias (recvfrom,__recvfrom);
-
-
-/**
- * wrapper for recvmsg()
- **/
-int recvmsg(int s, struct msghdr *msg, int flags)
-{
-  (void) msg; (void) flags;
-
-  assert( (flags & MSG_WAITALL) == 0 );
-  CAP_SET_SYSCALL();
-  return sendrecv_aux(RECV, SYS_RECVMSG, s, &s);
-}
-strong_alias (recvmsg,__recvmsg);
-
-
-// FIXME: need a real implimentation of this
-int shutdown(int s, int how) {
-  (void) how;
-  close(s);
-  return 0;
-}
-strong_alias (shutdown,__shutdown);
-#endif
-
-
-// FIXME: wrappers still needed:
-//     stat, fstat
-//     readdir (both a system call and a lib func --- ugly)
-//     getdents
-
-//     shutdown ??
-//   
-//
-// look at pth_syscal.c and pth_high.c for others (sigprocmask, fork, etc.)
-
-
-// FIXME.  BUGS:
-//     check pipes, FIFOs, ttys, etc.  Need to use the right lib.
-
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// Initialization and polling wrapper functions
-//////////////////////////////////////////////////////////////////////
-
-
-extern int num_runnable_threads;
-
-/**
- * perform a poll
- **/
-// FIXME: have this return a number, to indicate how many things were found (?)
-static void blocking_io_poll(long long usecs)
-{
-  if( usecs > 1e7) {
-    output("blocking_io_poll: %lld  %lld\n", usecs, (long long)1e7);
-    //abort();
-    usecs = 0;
-  }
-    
-  start_timer(&poll_timer);
-  {
-    if( sockio_stats.active >  0  &&  diskio_stats.active == 0 ) 
-      sockio_poll( usecs );
-    else if ( sockio_stats.active == 0  &&  diskio_stats.active > 0)
-      diskio_poll( usecs );
-    else {
-      // don't allow either to block
-      if( diskio_stats.active > 0 )
-        diskio_poll( (long long) 0 );
-        //diskio_poll( usecs );
-      if( sockio_stats.active > 0 )
-        sockio_poll( usecs );
-    }
-  }
-  stop_timer(&poll_timer);
-
-  // extra poll never blocks anyway...
-  start_timer(&extra_poll_timer);
-  extra_poll();
-  //tdebug("num=%d\n", num_runnable_threads);
-  stop_timer(&extra_poll_timer);
-}
-
-
-#define SET_IO(type,name) \
-do {\
-  if( !type##_##name##_is_available ) {\
-    warning("%s '%s' is not available on this system\n",__STRING(type),__STRING(name)); \
-    exit(1); \
-  } \
-  type##_init = type##_##name##_init; \
-  type##_poll = type##_##name##_poll; \
-  type##_add_request = type##_##name##_add_request; \
-  output("CAPRICCIO_%s=%s\n", \
-         (strcmp(__STRING(type),"sockio") == 0 ? "SOCKIO" : "DISKIO"), \
-         __STRING(name)); \
-} while( 0 )
-
-static void pick_io_scheme()
-{
-  char *env;
-
-  // sockio
-  env = getenv("CAPRICCIO_SOCKIO");
-  if( env == NULL )// default
-    if( sockio_epoll_is_available )
-      SET_IO(sockio, epoll ); 
-    else
-      SET_IO(sockio, poll ); 
-  else if( !strcasecmp(env,"poll") )
-    SET_IO(sockio, poll );
-  else if( !strcasecmp(env,"epoll") )
-    SET_IO(sockio, epoll );
-  else 
-    fatal("Invalid value for CAPRICCIO_SOCKIO: '%s'\n",env);
-
-  // diskio
-  env = getenv("CAPRICCIO_DISKIO");
-  if( env == NULL ) // default
-    if( diskio_aio_is_available )
-      SET_IO(diskio, aio ); 
-    else
-      SET_IO(diskio, blocking ); // default
-  else if( !strcasecmp(env,"immediate") )
-    SET_IO(diskio, immediate );
-  else if( !strcasecmp(env,"blocking") )
-    SET_IO(diskio, blocking );
-  else if( !strcasecmp(env,"kthread") )
-    SET_IO(diskio, kthread );
-  else if( !strcasecmp(env,"aio") )
-    SET_IO(diskio, aio );
-  else 
-    fatal("Invalid value for CAPRICCIO_DISKIO: '%s'\n",env);
-
-}
-
-
-
-/**
- * init the IO routines
- **/
-static void blocking_io_init() __attribute__((constructor));
-static void blocking_io_init() 
-{
-  static int init_done = 0;
-  if( init_done ) return;
-  init_done = 1;
-
-  thread_latch_init( fdstruct_latch );
-
-  // pick the version of the disk and socket IO libs
-  pick_io_scheme();
-
-  sockio_init();
-  diskio_init();
-
-  set_io_polling_func( blocking_io_poll );
-
-  init_timer(&poll_timer);
-  register_timer("poll", &poll_timer);
-  init_timer(&extra_poll_timer);
-  register_timer("extra_poll", &extra_poll_timer);
-
-}
-// This is implemented in NIO now.
-int __cap_outstanding_disk_requests = 0;
diff --git a/user/c3po/aio/blocking_io.h b/user/c3po/aio/blocking_io.h
deleted file mode 100644 (file)
index 20b35c8..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-#ifndef BLOCKING_IO_H
-#define BLOCKING_IO_H
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <sys/syscall.h>
-//#ifdef HAVE_SYS_SOCKETCALL_H
-//#include <sys/socketcall.h>
-//#endif
-
-
-// replacements for standard system calls
-extern int open(const char *pathname, int flags, ...);
-extern int creat(const char *pathname, mode_t mode);
-extern int close(int fd);
-
-extern ssize_t read(int fd, void *buf, size_t count);
-extern ssize_t write(int fd, const void *buf, size_t count);
-extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
-extern ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-
-extern off_t lseek(int fd, off_t off, int whence);
-extern int fcntl(int fd, int cmd, ...);
-extern int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
-extern int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-extern int dup(int oldfd);
-extern int dup2(int oldfd, int newfd);
-
-
-// FIXME: should add disk r/w calls that specify the offset
-
-
-
-#endif // BLOCKING_IO_H
diff --git a/user/c3po/aio/check_syscall b/user/c3po/aio/check_syscall
deleted file mode 100755 (executable)
index d5640bc..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/perl
-######################################################################
-#
-#  Do a sanity check on a source code file, to make sure it makes
-#  system calls via syscall(), rather directly.  This prevents stupid
-#  mistakes due to looping in the io routines
-#
-#  USAGE: check_syscall FILENAME
-#
-#  add special cases that are _not_ bugs to the @special_cases array
-#
-######################################################################
-use strict;
-
-
-# NOTE: keep this in sync w/ blocking_io.h
-my @syscalls = qw(open creat close read write
-                  lseek fcntl connect accept dup dup2);
-
-# files to skip entirely
-my @skipfiles = qw(aiotest.c pthread_diskio.c);
-
-# special cases, for various files
-my %special_cases =
-(
- 'blocking_io.c' => 
- [
-  ' SYSCALL\(.*\)\s*$',          # the definition of our version of the system call
-  'open\(pathname, O_CREAT',   # creat() calls open()
- ],
-);
-
-
-my $syscall_re = "\\b\(" . join("|", @syscalls) . "\)\\b";
-my $skipfiles_re = "\(" . join("|", @skipfiles) . "\)\$";
-my $exitcode = 0;
-
-foreach my $file (@ARGV) {
-    next if($file =~ m!$skipfiles_re!);
-
-    #open(FILE,"<$file") || die "can't read from file '$file'";
-
-    my $syscall;
-    my $lineno=0;
- LINE: while (my $line=<FILE>) {
-        $lineno++;
-
-        # strip comments
-        $line =~ s!//.*$!!;
-        next if $line =~ /^ \* /;
-
-        # strip strings
-        $line =~ s!\\"!!g;
-        $line =~ s!\\'!!g;
-        $line =~ s!".*?"!!g;
-        $line =~ s!'.*?'!!g;
-
-        # check for syscalls
-        ($syscall) = ($line =~ m!$syscall_re!);
-        next if $syscall eq "";
-        
-        # special cases
-        foreach my $f (keys %special_cases) {
-            my $l = $special_cases{$f};
-            if ($file =~ /$f$/) {
-                foreach my $re (@$l) {
-                    my $temp = $re;
-                    $temp =~ s!SYSCALL!$syscall!g;
-                    next LINE if($line =~ m!$temp!);
-                }
-            }
-        }
-
-        # warn
-        print STDERR "$file:$lineno  BAD SYSCALL: $syscall() - Line follows:\n";
-        chomp($line); 
-        print $line, "\n";
-        $exitcode = 1;
-    }
-
-}
-
-
-exit $exitcode;
-
diff --git a/user/c3po/aio/diskio_aio.c b/user/c3po/aio/diskio_aio.c
deleted file mode 100644 (file)
index 43c248b..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/**
- * blocking IO routines
- *
- * These routines make use of asynchronous IO and the signal/wait
- * calls of a threading package to provide a blocking IO abstraction
- * on top of underlying non-blocking IO calls.
- *
- * The semantics of these calls mirror those of the standard IO
- * libraries.
- **/
-
-#include "threadlib.h"
-#include "io_internal.h"
-#include "util.h"
-
-
-#ifndef DEBUG_diskio_aio_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-#ifndef HAVE_AIO
-
-// dummy functions to allow correct linking
-int diskio_aio_is_available = 0;
-void diskio_aio_init() {};
-void diskio_aio_poll(long long usecs) { (void)usecs; }
-int diskio_aio_add_request(iorequest_t* req) { (void)req; return -1; }
-
-#else // HAVE_AIO
-
-
-#include <unistd.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <libaio.h>
-#include <time.h>
-
-
-#define AIO_QUEUE_SIZE 10000
-
-int diskio_aio_is_available = 1;
-static void reinit();
-
-//////////////////////////////////////////////////////////////////////
-// Internal data
-//////////////////////////////////////////////////////////////////////
-
-
-// ioctx
-static io_context_t ioctx;
-
-static int num_outstanding = 0;
-
-int diskio_aio_add_request(iorequest_t* req)
-{
-  int ret;
-  struct iocb cb;
-  struct iocb *cbs[1];
-  debug_print_request("new request",req);
-
-  //diocb.req = req;
-  switch( req->type ) {
-  case READ:   
-  case PREAD:   
-    io_prep_pread(&cb, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->fds->off);  
-    break;
-  case WRITE:  
-  case PWRITE:  
-    io_prep_pwrite(&cb, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->fds->off); 
-    break;
-  default: assert(0);
-  }  
-
-  // set the data, for later
-  cb.data = req;
-
-  // Submit the request
-  cbs[0] = &cb;
-
-  ret = io_submit(ioctx, 1, cbs);
-  if( ret < 0 ) {
-    warning("reinitializing AIO!!  io_submit returned %d: %s\n", ret, strerror(0-ret));
-    reinit();
-    ret = io_submit(ioctx, 1, cbs);
-  }
-  if (ret < 0) {
-    errno = 0 - ret;
-    warning("reinit didn't help!!  io_submit returned %d: %s\n", ret, strerror(0-ret));
-    return -1;
-  } else if(ret != 1) {
-    warning("io_submit returned wrong number of requests!!\n");
-    errno = EINVAL;
-    return -1;
-  }
-
-#if 0
-  // debug code.  This forces an immediate reply, to avoid any
-  // scheduling / polling overhead in the threading layer.
-  // 
-  // For a single-threaded looping read() test, scheduling seems to
-  // add about 16% additional overhead.
-  if( 0 ) {
-    int res;
-    struct io_event myevents[1];    
-    struct timespec t;
-    t.tv_sec = 0;
-    t.tv_nsec = 0;
-
-    while ( (res = io_getevents(ioctx, 0, 1, myevents, NULL)) <= 0) {
-      ; 
-    }
-
-    {
-      struct iocb *cb = (struct iocb *)myevents[0].obj;
-      iorequest_t *rreq = (iorequest_t *)cb->data;
-
-      int len = myevents[0].res;
-
-      (void) rreq;
-      rreq = req;
-      assert( rreq );
-
-      // set return values
-      req->ret = len;
-      req->err = myevents[0].res2;   // FIXME: Is this correct? 
-    }
-
-    return req->ret;
-  }
-#endif
-
-  debug("%s: submit a request(type=%d).\n", thread_name(thread_self()), req->type);
-
-  // suspend the current thread
-  num_outstanding++;
-  req->ret = 5551212;
-  req->err = 5551212;
-  thread_suspend_self(0);
-
-  debug_print_request("request done",req);
-
-  // set errno, and return
-  errno = req->err;
-  return req->ret;
-}
-
-
-// Process at most how many events at a time
-#define EVENT_BATCH_FACTOR 10
-static struct io_event events[EVENT_BATCH_FACTOR];
-
-// Read completion event from Linux-aio and resume corresponding 
-// threads.
-//
-// NOTE: this routine is NOT thread-safe!! 
-void diskio_aio_poll(long long usecs)
-{
-  int i, complete;
-  struct timespec t;
-
-  if( usecs > 1e7) {
-    output("diskio_aio_poll: %lld  %lld\n", usecs, (long long)1e7);
-    //abort();
-    usecs = 0;
-  }
-
-  // FIXME: not sure how AIO handles -1 timeout, so just give a big one
-  t.tv_sec = 0;
-  if( usecs < 0 ) {
-    t.tv_nsec = 1e8; // max of 100 ms
-  } else { 
-    t.tv_nsec = usecs*1000;
-  }
-
-  // just to be safe
-  if( t.tv_nsec > 1e8 ) t.tv_nsec = 1e8;
-
-
-  // short-circuit, if there are no outstanding requests
-  if( num_outstanding <= 0 )
-    return;
-
-  if ( (complete = io_getevents(ioctx, 0, EVENT_BATCH_FACTOR, events, &t)) <= 0) {
-    // No event for now, just return
-    return;
-  }
-
-  num_outstanding -= complete;
-  debug("%d disk events ready, %d still left\n", complete, num_outstanding); 
-
-  for (i = 0; i < complete; i++ )
-    {
-      struct iocb *cb = (struct iocb *)events[i].obj;
-      iorequest_t *req = (iorequest_t *) cb->data;
-
-      debug("events[%d]:\n", i);
-      debug("   req         %p\n", req);
-      debug("   data        %p\n", (void*) events[i].data);
-      debug("   obj         %p\n", (void*) events[i].obj);
-      debug("   res         %ld\n", events[i].res);
-      debug("   obj         %ld\n", events[i].res2);
-      debug("\n");
-      debug("iocb:\n");
-      debug("   data        %p\n", cb->data);
-      debug("   opcode      %d\n", cb->aio_lio_opcode);
-      debug("   filedes     %d\n", cb->aio_fildes);
-      debug("\n");
-      
-
-      // set return values
-      if( (long)events[i].res >= 0 ) {
-        req->ret = events[i].res;
-        req->err = 0;
-      } else {
-        req->ret = -1;
-        req->err = -1 * events[i].res;
-      }
-      debug("request: ret=%d err=%d\n", req->ret, req->err);
-      
-      // update file position, if necessary
-      if((req->type==READ || req->type==WRITE) && req->ret > 0) {
-        req->fds->off += req->ret;
-      }
-
-      thread_resume(req->thread);
-    }
-
-  // FIXME: adding io_destroy(ioctx) here prevents the SIGSEGV
-
-  debug("processed %d completion events.\n", complete);
-}
-
-/**
- * Initailize the aio layer, possibly for a second time.  This is
- * useful b/c there seem to be cases in which the AIO layer gets
- * hosed, for no good reason.
- **/
-static void reinit()
-{
-  static int init_done = 0;
-  int ret;
-
-  // if the IO layer was previously initialized, clean up
-  if( init_done ) {
-    // FIXME: we should kill off any pending requests here, too!!
-    if( num_outstanding > 0 )
-      warning("Reinitializing AIO with %d requests still outstanding!!\n",num_outstanding);
-    num_outstanding = 0;
-
-    ret = io_destroy(ioctx);
-    output("io_destroy() = %d\n", ret);
-  }
-
-  // Init Linux-AIO
-  ioctx = NULL;
-  if (io_setup(AIO_QUEUE_SIZE, &ioctx) != 0)
-    fatal("Failed to initialize Linux-AIO.  Do you have the right kernel?\n");
-
-  init_done = 1;
-}
-
-void diskio_aio_init() 
-{
-  static int init_done = 0;
-
-  if(init_done) return;
-  init_done = 1;
-
-  // Init Linux-AIO
-  reinit();
-
-  // FIXME: adding io_destroy(ioctx) here prevents the SIGSEGV
-
-  // FIXME: doing an atexit() func to call io_destroy() doesn't help.
-}
-
-#endif // HAVE_AIO
-
-
-
-
-
-
-
-
-
diff --git a/user/c3po/aio/diskio_blocking.c b/user/c3po/aio/diskio_blocking.c
deleted file mode 100644 (file)
index 78231d7..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-
-/**
- * Kernel threads version of async disk IO.  This is intended for use
- * on development machines that don't have an aio patched kernel
- * installed.
- **/
-
-#include "io_internal.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <syscall.h>
-#include <sys/syscall.h>
-
-#ifndef DEBUG_diskio_blocking_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-#ifndef SYS_pread
-# ifdef __NR_pread
-#  define SYS_pread     __NR_pread
-#  define SYS_pwrite   __NR_pwrite
-# else
-#  define SYS_pread     180
-#  define SYS_pwrite   181
-# endif
-#endif
-
-int diskio_blocking_is_available = 1;
-
-
-typedef struct {
-  linked_list_entry_t e;
-  iorequest_t *req;
-} rlist_entry_t;
-
-linked_list_t reqlist;
-
-latch_t diskio_latch;
-
-int diskio_blocking_add_request(iorequest_t* req)
-{
-  rlist_entry_t e;
-  debug_print_request("",req);
-
-  e.req = req;
-
-  thread_latch( diskio_latch );
-  ll_add_existing_to_tail(&reqlist, &e.e);
-  thread_unlatch( diskio_latch );
-
-  // suspend the current thread
-  thread_suspend_self(0);
-
-  // set errno, and return
-  errno = req->err;
-  return req->ret;
-}
-
-
-void diskio_blocking_poll(long long usecs)
-{
-  rlist_entry_t *e;
-  iorequest_t *req;
-  (void) usecs;  // we always block
-
-  while( 1 ) {
-    thread_latch( diskio_latch );
-    e = (rlist_entry_t*) ll_remove_head( &reqlist );
-    thread_unlatch( diskio_latch );
-
-    if(e == NULL) 
-      break;
-    req = e->req;
-
-    switch( req->type ) {
-    case READ:
-      debug("doing read(%d,%p,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      req->ret = syscall(SYS_read, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      debug("read done.\n");
-      break;
-    case WRITE:
-      debug("doing write(%d,%p,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      req->ret = syscall(SYS_write, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      debug("write done.\n");
-      break;
-    case PREAD:
-      debug("doing pread(%d,%p,%d,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count, (int)req->args.rw.off);
-      req->ret = syscall(SYS_pread, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-      debug("pread done.\n");
-      break;
-    case PWRITE:
-      debug("doing pwrite(%d,%p,%d,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count, (int)req->args.rw.off);
-      req->ret = syscall(SYS_pwrite, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-      debug("pwrite done.\n");
-      break;
-    default:
-      assert(0);
-    }
-
-    
-    
-    debug("resuming thread: %s\n", thread_name(req->thread));
-    thread_resume(req->thread);
-  }
-}
-
-
-void diskio_blocking_init() 
-{
-  ll_init(&reqlist, "diskio_kthread_reqlist", NULL);
-  thread_latch_init( diskio_latch );
-
-  
-}
-
diff --git a/user/c3po/aio/diskio_immediate.c b/user/c3po/aio/diskio_immediate.c
deleted file mode 100644 (file)
index ab2247d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-
-/**
- * Kernel threads version of async disk IO.  This is intended for use
- * on development machines that don't have an aio patched kernel
- * installed.
- **/
-
-#include "io_internal.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <sys/syscall.h>
-
-#ifndef DEBUG_diskio_immediate_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-#ifndef SYS_pread
-# ifdef __NR_pread
-#  define SYS_pread     __NR_pread
-#  define SYS_pwrite   __NR_pwrite
-# else
-#  define SYS_pread     180
-#  define SYS_pwrite   181
-# endif
-#endif
-
-int diskio_immediate_is_available = 1;
-
-
-int diskio_immediate_add_request(iorequest_t* req)
-{
-  debug_print_request("",req);
-
-  switch( req->type ) {
-  case READ:
-    debug("doing read(%d,%p,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count);
-    req->ret = syscall(SYS_read, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-    debug("read done.\n");
-    break;
-  case WRITE:
-    debug("doing write(%d,%p,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count);
-    req->ret = syscall(SYS_write, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-    debug("write done.\n");
-    break;
-  case PREAD:
-    debug("doing pread(%d,%p,%d,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count, (int)req->args.rw.off);
-    req->ret = syscall(SYS_pread, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-    debug("pread done.\n");
-    break;
-  case PWRITE:
-    debug("doing pwrite(%d,%p,%d,%d)\n", req->fds->fd, req->args.rw.buf, req->args.rw.count, (int)req->args.rw.off);
-    req->ret = syscall(SYS_pwrite, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-    debug("pwrite done.\n");
-    break;
-  default:
-    assert(0);
-  }
-
-  req->err = errno;
-  return req->ret;
-}
-
-
-void diskio_immediate_poll(long long usecs)
-{
-  (void) usecs;
-}
-
-
-void diskio_immediate_init() 
-{
-}
-
diff --git a/user/c3po/aio/diskio_kthread.c b/user/c3po/aio/diskio_kthread.c
deleted file mode 100644 (file)
index bf5bd19..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-
-/**
- * Kernel threads version of async disk IO.  This is intended for use
- * on development machines that don't have an aio patched kernel
- * installed.
- **/
-
-#include "io_internal.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <syscall.h>
-#include <sys/syscall.h>
-#include <sched.h>
-
-#ifndef DEBUG_diskio_kthread_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-#ifndef SYS_pread
-# ifdef __NR_pread
-#  define SYS_pread     __NR_pread
-#  define SYS_pwrite   __NR_pwrite
-# else
-#  define SYS_pread     180
-#  define SYS_pwrite   181
-# endif
-#endif
-
-
-// FIXME: need more flexibility here.  These both behave very badly, in terms of latency.  ;-(
-
-#define NUM_WORKERS 30
-#define WORKER_SLEEP_MICROSECONDS 100
-//#define NUM_WORKERS 1
-//#define WORKER_SLEEP_MICROSECONDS 1
-
-occ_list_t *requests, *main_rspare;
-occ_list_t *finished, *main_fspare;
-static occ_list_t mainstructs[4];
-
-int diskio_kthread_is_available = 1;
-
-// in the main capriccio kernel thread
-int diskio_kthread_add_request(iorequest_t* req)
-{
-  occ_list_entry_t e;
-  debug_print_request("",req);
-
-  e.data = req;
-
-  // NOTE: we only use one spare for the main thread, since it is still running single-threaded.
-  occ_enqueue(&requests, &main_rspare, &e);
-
-  // suspend the current thread
-  thread_suspend_self(0);
-
-  // set errno, and return
-  errno = req->err;
-  return req->ret;
-}
-
-// in the main capriccio kernel thread
-void diskio_kthread_poll(long long usecs)
-{
-  occ_list_entry_t *e;
-  iorequest_t *req;
-  (void) usecs; // we never block here
-
-  while( 1 ) {
-    debug("main: about to dequeue\n");
-    e = occ_dequeue(&finished, &main_fspare);
-    debug("main: dequeued e=%p\n",e);
-
-    // the IO is now done, so just wake the thread
-    if(e == NULL) 
-      break;
-    req = (iorequest_t*) e->data;
-
-    debug_print_request("removed from finished queue",req);
-    tdebug("resuming thread: %s\n", thread_name(req->thread));
-    thread_resume(req->thread);
-  }
-}
-
-typedef struct {
-  occ_list_t *fspare;
-  occ_list_t *rspare;
-  long long wake_time;
-  int id;
-} worker_args_t;
-
-// do the actual IO - in seperate kernel threads
-static int diskio_worker_thread(void *clone_args)
-{
-  worker_args_t *args = (worker_args_t*) clone_args;
-  occ_list_entry_t *e;
-  iorequest_t *req;
-
-  while( 1 ) {
-
-    // get a pending request
-    debug("%d: about to dequeue\n", args->id);
-    e = occ_dequeue(&requests, &args->rspare);
-    debug("%d: got e=%p\n",args->id,e);
-
-    // no requests, sleep a bit
-    if(e == NULL) {
-      // FIXME: better to use signals?
-      struct timespec ts;
-      long long now = (current_usecs() % WORKER_SLEEP_MICROSECONDS);
-      
-      if( args->wake_time > now )
-        ts.tv_nsec = (args->wake_time - now);
-      else 
-        ts.tv_nsec = WORKER_SLEEP_MICROSECONDS - (args->wake_time - now);
-      ts.tv_sec = 0;
-      ts.tv_nsec = 1;
-
-      //syscall(SYS_nanosleep, &ts, NULL);
-      syscall(SYS_sched_yield);
-
-      continue;
-    }
-
-    req = (iorequest_t*) e->data;
-
-    debug_print_request("removed from request queue", req);
-
-    switch( req->type ) {
-    case READ:
-      req->ret = syscall(SYS_read, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      break;
-    case WRITE:
-      req->ret = syscall(SYS_write, req->fds->fd, req->args.rw.buf, req->args.rw.count);
-      break;
-    case PREAD:
-      req->ret = syscall(SYS_pread, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-      break;
-    case PWRITE:
-      req->ret = syscall(SYS_pwrite, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off);
-      break;
-    default:
-      assert(0);
-    }
-
-    // put the request on the finished list
-    debug_print_request("adding to the finished queue", req);
-    occ_enqueue(&finished, &args->fspare, e);
-  }
-
-  return 0;
-}
-
-
-static worker_args_t arglist[NUM_WORKERS];
-static occ_list_t rsparelist[NUM_WORKERS];
-static occ_list_t fsparelist[NUM_WORKERS];
-
-// NOTE: 1024 causes corruption.
-//#define STACKSIZE 4096  // seems to be OK
-#define STACKSIZE 4096*4
-static char stacklist[NUM_WORKERS][STACKSIZE];
-
-// FIXME: remove CLONE_SIGHAND & possibly CLONE_THREAD once we use signal handling to rendesvous
-#ifndef CLONE_THREAD
-#define CLONE_THREAD 0
-#endif
-#ifndef CLONE_PARENT
-#define CLONE_PARENT 0
-#endif
-#define CLONE_THREAD_OPTS (\
-   CLONE_FS | \
-   CLONE_FILES | \
-   CLONE_PTRACE | \
-   CLONE_VM | \
-   CLONE_THREAD | \
-   CLONE_PARENT | \
-   CLONE_SIGHAND | \
-   0)
-
-//   CLONE_SIGHAND | 
-
-
-void diskio_kthread_init() 
-{
-  int i, ret;
-
-  // create request lists
-  debug("initializing\n");
-  requests = &mainstructs[0];  init_occ_list(requests);
-  finished = &mainstructs[1];  init_occ_list(finished);
-  debug("  done w/ lists\n");
-  main_rspare = &mainstructs[2];  // no init needed - just a copy to swap in & out
-  main_fspare = &mainstructs[3];  
-  
-  // create worker threads
-  // FIXME: kind of lame to have a fixed number
-  for( i=0; i<NUM_WORKERS; i++ ) {
-    arglist[i].rspare = &rsparelist[ i ];  // no init needed - just a copy to swap in & out
-    arglist[i].fspare = &fsparelist[ i ];
-    arglist[i].id = i;
-    arglist[i].wake_time = (WORKER_SLEEP_MICROSECONDS/NUM_WORKERS)*i;
-
-    ret = clone(diskio_worker_thread, stacklist[i]+STACKSIZE-4, CLONE_THREAD_OPTS, &arglist[i]);
-
-    if(ret == -1) {
-      perror("clone"); 
-      exit(1);
-    }
-  }
-  debug("  done w/ workers\n");
-
-}
-
diff --git a/user/c3po/aio/io_internal.h b/user/c3po/aio/io_internal.h
deleted file mode 100644 (file)
index 9696f28..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-
-#ifndef IO_INTERNAL_H
-#define IO_INTERNAL_H
-
-#include "threadlib.h"
-#include "util.h"
-#include <sys/types.h>
-
-
-
-// types of FDs
-
-
-
-// track information about a file descriptor
-typedef struct fdstruct_st {
-  int fd;          // file descriptor number
-
-  // next 2 fields are for dup() handling
-  struct fdstruct_st *root_fds;   // "master" fd that contains all other info if this fd is a dup()'ed one
-                                  // if this is different from fd, then all other fields in the struct are irrelavant
-  struct fdstruct_st *next_fds;   // all dup'ed fd's form a circular linked list, this is the next one. 
-                                  // should be == NULL if not dup'ed
-  // group bitfields together
-  enum { // type of fd
-    FD_SOCKET=0,      // default 
-    FD_FILE           // regular disk file - use aio
-  } type:1;
-
-  enum { // valid states of an FD
-    FD_UNUSED=0,   // FD has not been seen before
-    FD_UNKNOWN,    // don't know the state of this FD yet
-    FD_CLOSED,     
-    FD_OPEN, 
-    FD_LISTENING,  // a non-blocking server socket, ready for accept()
-  } state:3;
-
-  unsigned int nonblocking:1;   // is the underlying file set to O_NONBLOCK?
-
-  cpu_tick_t time_opened;       // The time the fd was opened.  used internally for stats gathering
-    
-  off_t off;       // file offset
-
-  union {  // for use by underlying IO routines.
-    struct {                      // for sockio_epoll
-      __uint32_t events;
-    } epoll;
-  } u;
-
-  latch_t reqlatch;
-  linked_list_t reqlist;
-} fdstruct_t;
-
-// types of IO requests
-typedef enum {
-  READ, 
-  WRITE, 
-  PREAD,   // only for files.
-  PWRITE,  // only for files.
-  CONNECT, // only for sockets.  underlying socket IO should just check for writability
-  ACCEPT,  // only for sockets.  underlying socket IO should just check for readability
-  POLL1,   // only for sockets.  only support single fds
-  SEND,    // only for sockets.  for UDP sending operations
-  RECV,    // only for sockets.  for UDP receiving operations
-} iotype;
-
-// an outstanding IO request
-typedef struct iorequest_st {
-  // "inherit" from linked_list_entry_t
-  linked_list_entry_t lle;
-
-  // request info
-  fdstruct_t *fds;
-  iotype type;
-  thread_t *thread;
-
-  // IO-specific request info
-  union {
-    struct {
-      __uint32_t events;
-    } epoll;
-  } u;
-
-  // args
-  union {
-
-    // for read, write, pread, pwrite
-    struct {
-      void *buf;
-      size_t count;
-      off_t off;
-    } rw;
-
-    // for poll
-    struct {
-      struct pollfd *ufds;
-    } poll1;
-
-    // for things that use SYS_socketcall
-    struct {
-      int which;      // which socket call?
-      void *argv;
-    } scall;
-
-  } args;
-
-  // return vals
-  ssize_t ret;
-  int err;
-} iorequest_t;
-
-#define debug_print_request(msg,req) \
-do {\
-  switch(req->type) { \
-  case READ: \
-    tdebug("%s:  read(%d,%p,%d) = %d (errno=%d)\n", \
-           msg, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->ret, req->err); \
-    break; \
-  case WRITE: \
-    tdebug("%s:  write(%d,%p,%d) = %d (errno=%d)\n", \
-           msg, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->ret, req->err); \
-    break; \
-  case PREAD: \
-    tdebug("%s:  pread(%d,%p,%d,%lud) = %d (errno=%d)\n", \
-           msg, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off, req->ret, req->err); \
-    break; \
-  case PWRITE: \
-    tdebug("%s:  pwrite(%d,%p,%d,%lud) = %d (errno=%d)\n", \
-           msg, req->fds->fd, req->args.rw.buf, req->args.rw.count, req->args.rw.off, req->ret, req->err); \
-    break; \
-  case CONNECT: \
-    tdebug("%s:  connect(%d, ...) = %d (errno=%d)\n", msg, req->fds->fd, req->ret, req->err); \
-    break; \
-  case ACCEPT:  \
-    tdebug("%s:  accept(%d, ...) = %d (errno=%d)\n", msg, req->fds->fd, req->ret, req->err); \
-    break; \
-  case POLL1:  \
-    tdebug("%s:  poll(%d, ...) = %d (errno=%d)\n", msg, req->fds->fd, req->ret, req->err); \
-    break; \
-  default: \
-    tdebug("%s:  unknown request type: %d\n", msg, req->type); \
-  } \
-} while( 0 )
-
-
-// internal utility functions
-fdstruct_t* get_fdstruct(int fd);
-inline void add_waiter(iorequest_t *req);
-inline void remove_waiter(iorequest_t *req);
-inline iorequest_t* remove_first_waiter(fdstruct_t *fds);
-inline iorequest_t* view_first_waiter(fdstruct_t *fds);
-
-
-// 
-// scheduler functions
-#define DECLARE_IO(type,name) \
-  extern int  type##_##name##_is_available; \
-  extern void type##_##name##_init(void); \
-  extern int  type##_##name##_add_request(iorequest_t *req); \
-  extern void type##_##name##_poll(long long timeout); 
-
-DECLARE_IO(sockio,poll);
-DECLARE_IO(sockio,epoll);
-
-DECLARE_IO(diskio,immediate);
-DECLARE_IO(diskio,blocking);
-DECLARE_IO(diskio,kthread);
-DECLARE_IO(diskio,aio);
-
-
-#endif //IO_INTERNAL_H
-
diff --git a/user/c3po/aio/sockio_epoll.c b/user/c3po/aio/sockio_epoll.c
deleted file mode 100644 (file)
index a6977c5..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/**
- * blocking IO routines
- *
- * These routines make use of asynchronous IO and the signal/wait
- * calls of a threading package to provide a blocking IO abstraction
- * on top of underlying non-blocking IO calls.
- *
- * The semantics of these calls mirror those of the standard IO
- * libraries.
- **/
-
-#include "threadlib.h"
-#include "io_internal.h"
-#include "util.h"
-#include <sys/poll.h>
-
-#ifndef DEBUG_sockio_epoll_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-
-#ifndef HAVE_SYS_EPOLL
-
-// epoll isn't available, so just make dummy functions for linking
-int sockio_epoll_is_available = 0;
-int sockio_epoll_add_request(iorequest_t *req) { (void) req; return -1; }
-void sockio_epoll_init() {}
-void sockio_epoll_poll(long long usec) {(void) usec;}
-
-#else // HAVE_SYS_EPOLL
-
-
-#include <unistd.h>
-#include <syscall.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
-
-// for socketcall stuff
-#include <linux/net.h>
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// Internal data
-//////////////////////////////////////////////////////////////////////
-
-
-latch_t sockio_epoll_latch;
-
-//#define EPOLL_INITIAL_FDS 10000
-#define EPOLL_INITIAL_FDS 100
-static int epollfd = -1;
-
-//////////////////////////////////////////////////////////////////////
-// IO management routines
-//////////////////////////////////////////////////////////////////////
-
-int sockio_epoll_is_available = 1;
-
-// cheesy hack, to keep an extra flag in w/ the epoll events
-#define SEP_REGISTERED_FD 0x8000
-#if (SEP_REGISTERED_FD & (EPOLLIN|EPOLLOUT|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET))
-#error conflict with SEP_REGISTERED_FD - redefine!!
-#endif
-
-
-/**
- * Process the list of requests.  This correctly handles the case
- * where new items are added to the list durring processing.  
- **/
-void process_request_list(fdstruct_t *fds) 
-{
-  iorequest_t *req, *head;
-  int res;
-
-  thread_latch( sockio_epoll_latch );
-  head = req = view_first_waiter(fds);
-  thread_unlatch( sockio_epoll_latch );
-
-  while( req != NULL ) {
-      
-    // this request isn't satisfiable w/ the current flags, so quit
-    if( (req->u.epoll.events & fds->u.epoll.events) == 0 )
-      break;
-    
-    // do the IO
-    do {
-      switch( req->type ) {
-      case READ:    res = syscall(SYS_read,  fds->fd, req->args.rw.buf, req->args.rw.count); break;
-      case WRITE:   res = syscall(SYS_write, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-      case CONNECT: res = 0; break; // system call already done in blocking_io.c
-      case POLL1:   res = 1; req->args.poll1.ufds[0].revents = fds->u.epoll.events; break;
-      case ACCEPT: case SEND: case RECV:
-        res = syscall(SYS_socketcall, req->args.scall.which, req->args.scall.argv); break;
-      default: assert(0); res=-1;
-      }
-    } while(res==-1 && errno==EINTR);
-    
-    // if the op would have blocked, clear the saved epoll flags, and try wait again
-    if(res==-1 && errno==EAGAIN) {
-      fds->u.epoll.events = (fds->u.epoll.events & ~req->u.epoll.events);
-      break;
-    }
-    
-    // we got an error completion.  Set the error flags for this FD, and wake all waiters
-    if(res == -1) {
-      thread_latch( sockio_epoll_latch );
-      while( (req=remove_first_waiter(fds)) != NULL ) {
-        req->ret = -1;
-        req->err = errno;
-        if( req->thread != thread_self() )
-          thread_resume( req->thread );
-      }
-      thread_unlatch( sockio_epoll_latch );
-      break;
-    }
-    
-    // The IO completed successfully. save results, and fetch the next request
-    req->ret = res;
-    req->err = 0;
-    thread_latch( sockio_epoll_latch );
-    remove_first_waiter(fds);
-    if( req->thread != thread_self() )
-      thread_resume( req->thread );
-    req = view_first_waiter(fds);
-    thread_unlatch( sockio_epoll_latch );
-  }
-
-
-}
-
-
-int sockio_epoll_add_request(iorequest_t *req) 
-{
-  fdstruct_t *fds = req->fds;
-
-  debug_print_request("",req);
-
-
-  // set the events for this request
-  switch( req->type ) {
-  case READ:    case RECV:  case ACCEPT:  req->u.epoll.events = EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP; break;
-  case WRITE:   case SEND:  case CONNECT: req->u.epoll.events = EPOLLOUT|EPOLLERR|EPOLLHUP; break;
-  case POLL1: req->u.epoll.events = req->args.poll1.ufds[0].events; break;
-  default: assert(0);
-  }
-  
-  // FIXME: races!!  need to avoid race b/w user-side and poll-side updates of flags 
-  thread_latch( sockio_epoll_latch );
-
-  // return w/ an IO error if we have EVER seen an error on this socket.
-  // FIXME: this might be the wrong thing to do?
-  if(fds->u.epoll.events & (EPOLLERR|EPOLLHUP)) {
-    errno = EIO;
-    // FIXME: remove from the epoll set?
-
-    thread_unlatch( sockio_epoll_latch );
-    return -1;
-  }
-
-  // add the fd to the epoll set, if necessary
-  if( !(fds->u.epoll.events & SEP_REGISTERED_FD) ) {
-    struct epoll_event ev;
-    int res;
-    errno = 0;
-    ev.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLET;
-    ev.data.ptr = fds;
-    res = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds->fd, &ev);
-    if( res != 0 ) {
-      output("attempted to register fd=%d  res=%d   errno=%d\n",fds->fd, res, errno);
-      // registration really failed, so just use blocking IO 
-      if(  errno != EEXIST && errno != 0 ) {
-        int res;
-        fdstruct_t* fds = req->fds;
-
-        // FIXME: this is an ugly hack, and shouldn't be necessary if
-        // the system call overriding works, and we've tracked the FDs
-        // correctly.  Having the assertion allows this to work, but
-        // only when optimizations are turned off.
-        assert( 0 );
-
-        switch( req->type ) {
-        case READ:    res = syscall(SYS_read,  fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case WRITE:   res = syscall(SYS_write, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case CONNECT: res = 0; break; // system call already done in blocking_io.c
-        case POLL1:   res = 1; req->args.poll1.ufds[0].revents = fds->u.epoll.events; break;
-        case ACCEPT: case SEND: case RECV:
-          res = syscall(SYS_socketcall, req->args.scall.which, req->args.scall.argv); break;
-        default: assert(0); res=-1;
-        }
-        thread_unlatch( sockio_epoll_latch );
-        return res;
-      }
-    }
-    assert( res == 0 || errno == EEXIST || errno == 0 );
-    fds->u.epoll.events = SEP_REGISTERED_FD|EPOLLOUT|EPOLLPRI|EPOLLIN;
-
-    /*
-    if( 0 ) 
-    { 
-      int ret;
-      struct pollfd ufds[1];
-
-      ufds[0].events = POLLIN | POLLOUT | POLLPRI | POLLERR | POLLHUP;
-      ret = syscall(SYS_poll, ufds, 1, 0);
-      fds->u.epoll.events = ufds[0].revents | SEP_REGISTERED_FD;
-    }
-    */
-  }
-
-  // some special hackery, to find out the exact state of the FD in
-  // the case of POLL1 and nonblocking sockets.  The problem is that
-  // w/ edge-triggered epoll semantics, a high bit doesn't mean the FD
-  // is really ready for IO - it just means that it it WAS ready.  We
-  // don't know for certain until the next actual read or write.  This
-  // means that we might give bad responses back to poll() requests. 
-  //
-  // FIXME: the current solution to this is to use a seperate epoll fd
-  // that is level-triggered, and use extra system calls to fetch the
-  // precice current status of the FD before we sleep.
-  if( req->type == POLL1 ) {
-    int ret;
-    ret = syscall(SYS_poll, req->args.poll1.ufds, 1, 0);
-    if( ret == 1 ) {
-      thread_unlatch( sockio_epoll_latch );
-      return 1;
-    } else {
-      fds->u.epoll.events &= ~(req->args.poll1.ufds[0].events);
-    }
-  }
-
-  thread_unlatch( sockio_epoll_latch );
-
-
-
-  // if this is the first request, just try the IO
-  // FIXME: race w/ view_first_waiter....  fix by latching fdstruct.
-  if( view_first_waiter(fds) == req ) {
-    process_request_list(fds);
-    if( view_first_waiter(fds) == req )
-      thread_suspend_self(0);
-  } else {
-    thread_suspend_self(0);
-  }
-
-  // remove ourselves from the list of waiters, and unlock
-  thread_latch( sockio_epoll_latch );
-  remove_waiter( req );
-  thread_unlatch( sockio_epoll_latch );
-
-  // set errno, and return
-  errno = req->err;
-  return req->ret;
-}
-
-
-
-#define EPOLL_BATCH_SIZE 1000
-static struct epoll_event evlist[EPOLL_BATCH_SIZE];
-
-void sockio_epoll_poll(long long usecs) 
-{
-  int nfds, i;
-  struct epoll_event *ev;
-  fdstruct_t *fds;
-  int timeout;
-  tdebug("start\n");
-
-  if( 1 || usecs > 1e7) {
-    //output("sockio_epoll_poll: %lld\n", usecs);
-    //abort();
-    usecs = 0;
-  }
-
-  // translate from microseconds to milliseconds
-  if( usecs < 0 )
-    //timeout = -1;
-    timeout = 100;  // max is 100 ms
-  else 
-    timeout = usecs/1000;
-  
-  // just to be safe
-  if( timeout > 100 ) timeout = 100;
-
-
-  do { 
-    nfds=epoll_wait(epollfd, evlist, EPOLL_BATCH_SIZE, timeout);
-  } while( nfds < 0  &&  (errno == EAGAIN || errno == ESPIPE || errno == EINPROGRESS || errno==EINTR) );
-  if(nfds < 0) 
-    fatal("epoll_wait() failed - %s\n", strerror(errno));
-
-
-  for (i=0, ev=evlist; i<nfds; i++, ev++) {
-    // save new events
-    fds = (fdstruct_t*) ev->data.ptr;
-    
-    thread_latch( sockio_epoll_latch );
-    fds->u.epoll.events |= ev->events;
-    thread_unlatch( sockio_epoll_latch );
-
-    process_request_list( fds );
-  }
-}
-
-
-void sockio_epoll_init() 
-{
-  // init the lock
-  thread_latch_init( sockio_epoll_latch );
-
-  // init the epoll infrastructure
-  epollfd = epoll_create(EPOLL_INITIAL_FDS);
-  if(epollfd < 0) {
-    fatal("epoll initialization failed - %s\n", strerror(errno));
-  }
-}
-
-
-
-#endif // HAVE_SYS_EPOLL
diff --git a/user/c3po/aio/sockio_poll.c b/user/c3po/aio/sockio_poll.c
deleted file mode 100644 (file)
index ad1a1fe..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/**
- * blocking IO routines
- *
- * These routines make use of asynchronous IO and the signal/wait
- * calls of a threading package to provide a blocking IO abstraction
- * on top of underlying non-blocking IO calls.
- *
- * The semantics of these calls mirror those of the standard IO
- * libraries.
- **/
-
-#include "threadlib.h"
-#include "io_internal.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <syscall.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/poll.h>
-#include <sys/syscall.h>
-
-// for socketcall stuff
-#include <linux/net.h>
-
-
-#ifndef DEBUG_sockio_poll_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-//////////////////////////////////////////////////////////////////////
-// Internal data
-//////////////////////////////////////////////////////////////////////
-
-#define MAX_OUTSTANDING_REQUESTS 20000
-static struct pollfd ufds[ MAX_OUTSTANDING_REQUESTS ];
-static int num_outstanding = 0;
-
-latch_t sockio_poll_latch = LATCH_INITIALIZER_UNLOCKED;
-
-
-int sockio_poll_is_available = 1;
-
-//////////////////////////////////////////////////////////////////////
-// IO management routines
-//////////////////////////////////////////////////////////////////////
-
-int sockio_poll_add_request(iorequest_t *req) 
-{
-  fdstruct_t *fds = req->fds;
-  debug_print_request("",req);
-
-  // get lock
-  thread_latch( sockio_poll_latch );
-
-  // the request was already processed by the polling thread, between
-  // the call and when we got the latch
-  // 
-  // FIXME: handle this!!
-  
-  if( view_first_waiter(fds) != req ) {
-    // this is an additional request, so return an error if it isn't accept();
-    debug("additional request for fd=%d\n",fds->fd);
-  } else {
-    // add the first reqeuest
-
-    // check that we don't have too many outstanding requests
-    if(num_outstanding >= MAX_OUTSTANDING_REQUESTS) {
-      errno = ENOMEM;
-      thread_unlatch( sockio_poll_latch );
-      return -1;
-    }
-
-    // try the IO first
-#if 1
-    { 
-      int ret;
-      do {
-        switch (req->type) {
-        case READ:    ret = syscall(SYS_read, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case WRITE:   ret = syscall(SYS_write, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case POLL1:   ret = syscall(SYS_poll, req->args.poll1.ufds, 1, 0); break;
-        case CONNECT: ret=0; break;  // system call already done in blocking_io.c 
-        case ACCEPT: case SEND: case RECV:
-          ret = syscall(SYS_socketcall, req->args.scall.which, req->args.scall.argv); break;
-        default: assert(0); ret=0;
-        }
-      } while(ret==-1 && errno==EINTR);
-      
-      // the request completed - just return to the user
-      if( req->type == POLL1  &&  ret == 0 )
-        ; // make sure we don't return too soon
-      else if( ret >= 0 || (errno!=EAGAIN && errno!=EWOULDBLOCK)) {
-        thread_unlatch( sockio_poll_latch );
-        return ret;
-      }
-    }
-#endif
-
-    // this is the first request for this FD
-    debug("adding first request for fd=%d\n",fds->fd);
-    ufds[num_outstanding].fd     = fds->fd;
-    switch( req->type ) {
-    case READ: case RECV: case ACCEPT:     ufds[num_outstanding].events = POLLIN|POLLPRI; break;
-    case WRITE: case SEND: case CONNECT:   ufds[num_outstanding].events = POLLOUT; break;
-    case POLL1:  ufds[num_outstanding].events = req->args.poll1.ufds[0].events; break;
-    default: assert(0);
-    }
-    num_outstanding++;
-  }
-
-  // release lock
-  thread_unlatch( sockio_poll_latch );
-
-  // suspend the current thread
-  thread_suspend_self(0);
-
-  // set errno and return 
-  errno = req->err;
-  return req->ret;
-}
-
-
-
-void sockio_poll_poll(long long usecs) 
-{
-  int ret, i;
-  fdstruct_t *fds;
-  iorequest_t *req;
-  int timeout = (usecs == -1 ? -1 : usecs / 1000);  // translate from microseconds to milliseconds
-
-  // get the lock
-  thread_latch( sockio_poll_latch );
-
-  assert(num_outstanding >= 0);
-  if( num_outstanding == 0 ) {
-    thread_unlatch( sockio_poll_latch );
-    return;
-  }
-
-  // NOTE: why a 100us timeout here?  this is preventing all runnable threads from proceeding - zf
-  // removing it
-  
-  //while( (ret=syscall(SYS_poll, ufds, num_outstanding, timeout)) < 0  &&  errno == EINTR ) ;
-  (void) timeout;
-  while( (ret=syscall(SYS_poll, ufds, num_outstanding, 0)) < 0  &&  errno == EINTR ) ;
-  if(ret < 0) {
-    perror("FATAL ERROR.  poll() failed. ");
-    exit(1);
-  }
-  
-  if(ret == 0) {
-    // release the lock
-    thread_unlatch( sockio_poll_latch );
-    return;
-  }
-
-  tdebug("%d fds are ready for IO\n", ret);
-
-  // process the returned events
-  for(i=num_outstanding-1; i>=0; i--) {
-
-    // skip past fds w/ no events
-    if( ufds[i].revents == 0 )
-      continue;
-
-    // find the fdstruct & get the first request
-    fds = get_fdstruct(ufds[i].fd);
-    req = view_first_waiter(fds);
-
-    // do the IO for as many waiters as possible
-    //
-    // FIXME: do this with just one syscall by using readv/writev!!!
-    // FIXME: it's VERY VERY BAD to hold sockio_poll_latch across these
-    // syscalls.  To fix, sockio_poll_add_request needs to drop waiting
-    // requests into a list somewhere, so only the list needs to be locked
-    while( req != NULL ) {
-      do {
-        switch (req->type) {
-        case READ:    ret = syscall(SYS_read, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case WRITE:   ret = syscall(SYS_write, fds->fd, req->args.rw.buf, req->args.rw.count); break;
-        case POLL1:   ret = 1; req->args.poll1.ufds[0].revents = ufds[i].revents; break;
-        case CONNECT: ret=0; break;  // system call already done in blocking_io.c 
-        case ACCEPT: case SEND: case RECV:
-          ret = syscall(SYS_socketcall, req->args.scall.which, req->args.scall.argv); break;
-        default: assert(0);
-        }
-      } while(ret==-1 && errno==EINTR);
-
-      // the request would have blocked.  Keep the fd in the poll set, and try again later
-      if( ret == -1  &&  (errno==EAGAIN || errno==EWOULDBLOCK)) 
-        req = NULL;
-
-      // there was some other error - return this error to all waiters
-      else if( ret == -1 ) {
-        while( (req=remove_first_waiter(fds)) != NULL ) {
-          req->ret = -1;
-          req->err = errno;
-          thread_resume( req->thread );
-        }
-      }
-
-      // the call succeeded
-      else {
-        remove_first_waiter(fds);
-        req->ret = ret;
-        req->err = 0;
-        thread_resume( req->thread );
-
-        // a read or write succeeded, but we didn't get the full count.
-        if( (req->type == READ || req->type == WRITE) && (size_t) ret < req->args.rw.count )
-          req = NULL;
-
-        // for everything else, we get the next request
-        else 
-          req = view_first_waiter(fds);
-      }
-    }
-
-    // update the poll flags for the fd
-    req = view_first_waiter(fds);
-    if( req != NULL ) {
-      // add flags for the next poll() call
-      debug("more waiters for %d - will poll again", fds->fd);
-      switch( req->type ) {
-      case READ: case RECV: case ACCEPT:     ufds[i].events = POLLIN|POLLPRI; break;
-      case WRITE: case SEND: case CONNECT:   ufds[i].events = POLLOUT; break;
-      case POLL1:  ufds[i].events = req->args.poll1.ufds[0].events; break;
-      default: assert(0);
-      }
-    } else {
-      // plug the hole in the request list
-      num_outstanding--;
-      ufds[i] = ufds[num_outstanding];
-    }
-  }
-
-  // release the lock
-  thread_unlatch( sockio_poll_latch );
-}
-
-
-
-void sockio_poll_init() 
-{
-}
-
diff --git a/user/c3po/include/README b/user/c3po/include/README
deleted file mode 100644 (file)
index 75683e1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-include files for use by applications.  These override standard system headers when necessary, to ensure that our threads lib is used correctly.
-
diff --git a/user/c3po/include/bits/pthreadtypes.h b/user/c3po/include/bits/pthreadtypes.h
deleted file mode 100644 (file)
index 21bc82c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-
-#include <pthread.h>
diff --git a/user/c3po/include/capriccio.h b/user/c3po/include/capriccio.h
deleted file mode 100644 (file)
index 3ca3ce4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _CAPRICCIO_H
-#define _CAPRICCIO_H
-
-/* various capriccio utility for user program */
-
-#ifndef cpu_tick_t
-typedef unsigned long long cpu_tick_t;
-#endif
-
-extern void *current_thread;
-extern unsigned long long start_usec;
-extern cpu_tick_t ticks_per_microsecond;
-
-void output(char *fmt, ...) __attribute__ ((format (printf,1,2)));
-unsigned thread_tid(void *t);
-
-#ifndef GET_CPU_TICKS
-#define GET_CPU_TICKS(Var)      __asm__ __volatile__ ("rdtsc" : "=A" (Var))
-#endif
-
-static inline long long current_usecs(void)
-{
-  register cpu_tick_t ret;
-  GET_CPU_TICKS( ret );
-  return (ret / ticks_per_microsecond);
-}
-
-#define cap_output(args...) \
-do {\
-  output("%3d %9lld : %s() - ", (int)thread_tid(current_thread), (long long)(current_usecs() - start_usec), __FUNCTION__  ); \
-  output(args); \
-} while( 0 )
-
-
-#endif
diff --git a/user/c3po/include/fptrcheck.h b/user/c3po/include/fptrcheck.h
deleted file mode 100644 (file)
index 02993de..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef FPTR_CHECK_H
-#define FPTR_CHECK_H
-
-// -----------------------------------------------------------------------
-
-// fptrcheck.h
-//
-// This module implements a sanity check for the graph analysis used by
-// the stack module.  It provides instrumentation for function pointer
-// call sites and function entry points in order to determine whether
-// our graph was missing edges.
-//
-// These checks are enabled or disabled by the analyzegraph program.
-
-// -----------------------------------------------------------------------
-
-extern int fptr_caller;
-
-#define FPTR_CALL(cur) \
-    do { \
-        if (fptr_caller != -1) { \
-            fptr_report_unvalidated_overwrite(cur); \
-        } \
-        fptr_caller = (cur); \
-    } while (0)
-
-#define FPTR_CHECK(cur, a) \
-    do { \
-        if (fptr_caller != -1) { \
-            int *p = (a); \
-            while (*p != 0) { \
-                if (*p == fptr_caller) { \
-                    fptr_caller = -1; \
-                    break; \
-                } \
-                p++; \
-            } \
-            if (fptr_caller != -1) { \
-                fptr_report_unexpected_call(cur); \
-                fptr_caller = -1; \
-            } \
-        } \
-    } while (0)
-
-#define FPTR_DONE(cur) \
-    do { \
-        if (fptr_caller != -1) { \
-            fptr_report_unvalidated_return(cur); \
-            fptr_caller = -1; \
-        } \
-    } while (0)
-
-#endif // FPTR_CHECK_H
diff --git a/user/c3po/include/pthread.h b/user/c3po/include/pthread.h
deleted file mode 100644 (file)
index e82ada5..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-#ifndef _CAPRICCIO_PTHREAD_H_
-#define _CAPRICCIO_PTHREAD_H_
-
-/*
-**
-** BOOTSTRAPPING
-**
-*/
-
-/*
- * Prevent system includes from implicitly including
- * possibly existing vendor Pthread headers
- */
-#define PTHREAD
-#define PTHREAD_H
-#define _PTHREAD_H
-#define _PTHREAD_H_
-#define PTHREAD_INCLUDED
-#define _PTHREAD_INCLUDED
-#define SYS_PTHREAD_H
-#define _SYS_PTHREAD_H
-#define _SYS_PTHREAD_H_
-#define SYS_PTHREAD_INCLUDED
-#define _SYS_PTHREAD_INCLUDED
-#define BITS_PTHREADTYPES_H
-#define _BITS_PTHREADTYPES_H
-#define _BITS_PTHREADTYPES_H_
-#define _BITS_SIGTHREAD_H
-
-
-/*
- * Protect namespace, because possibly existing vendor Pthread stuff
- * would certainly conflict with our defintions of pthread*_t.
- */
-#define pthread_t              __vendor_pthread_t
-#define pthread_attr_t         __vendor_pthread_attr_t
-#define pthread_key_t          __vendor_pthread_key_t
-#define pthread_once_t         __vendor_pthread_once_t
-#define pthread_mutex_t        __vendor_pthread_mutex_t
-#define pthread_mutexattr_t    __vendor_pthread_mutexattr_t
-#define pthread_cond_t         __vendor_pthread_cond_t
-#define pthread_condattr_t     __vendor_pthread_condattr_t
-#define pthread_rwlock_t       __vendor_pthread_rwlock_t
-#define pthread_rwlockattr_t   __vendor_pthread_rwlockattr_t
-#define sched_param            __vendor_sched_param
-
-/*
- * Allow structs containing pthread*_t in vendor headers
- * to have some type definitions
- */
-#if 0
-typedef int __vendor_pthread_t;
-typedef int __vendor_pthread_attr_t;
-typedef int __vendor_pthread_key_t;
-typedef int __vendor_pthread_once_t;
-typedef int __vendor_pthread_mutex_t;
-typedef int __vendor_pthread_mutexattr_t;
-typedef int __vendor_pthread_cond_t;
-typedef int __vendor_pthread_condattr_t;
-typedef int __vendor_pthread_rwlock_t;
-typedef int __vendor_pthread_rwlockattr_t;
-typedef int __vendor_sched_param;
-#endif
-
-/*
- * Include essential vendor headers
- */
-
-#include <limits.h>
-
-//#include <features.h>
-
-//#include <sched.h>
-//#include <time.h>
-
-#include <bits/posix_opt.h>
-
-// has a number of things that we need to undef, and redef.
-
-
-#define __need_sigset_t
-#include <signal.h>
-//#include <bits/pthreadtypes.h>
-//#include <bits/initspin.h>
-
-#include <sys/types.h>     /* for ssize_t         */
-//#include <sys/time.h>      /* for struct timeval  */
-//#include <sys/socket.h>    /* for sockaddr        */
-//#include <sys/signal.h>    /* for sigset_t        */
-//#include <time.h>          /* for struct timespec */
-//#include <unistd.h>        /* for off_t           */
-
-/*
- * Unprotect namespace, so we can define our own variants now
- */
-#undef pthread_t
-#undef pthread_attr_t
-#undef pthread_key_t
-#undef pthread_once_t
-#undef pthread_mutex_t
-#undef pthread_mutexattr_t
-#undef pthread_cond_t
-#undef pthread_condattr_t
-#undef pthread_rwlock_t
-#undef pthread_rwlockattr_t
-#undef sched_param
-
-/*
- * Cleanup more Pthread namespace from vendor values
- */
-#undef  _POSIX_THREADS
-#undef  _POSIX_THREAD_ATTR_STACKADDR
-#undef  _POSIX_THREAD_ATTR_STACKSIZE
-#undef  _POSIX_THREAD_PRIORITY_SCHEDULING
-#undef  _POSIX_THREAD_PRIO_INHERIT
-#undef  _POSIX_THREAD_PRIO_PROTECT
-#undef  _POSIX_THREAD_PROCESS_SHARED
-#undef  _POSIX_THREAD_SAFE_FUNCTIONS
-#undef  PTHREAD_DESTRUCTOR_ITERATIONS
-#undef  PTHREAD_KEYS_MAX
-#undef  PTHREAD_STACK_MIN
-#undef  PTHREAD_THREADS_MAX
-#undef  PTHREAD_CREATE_DETACHED
-#undef  PTHREAD_CREATE_JOINABLE
-#undef  PTHREAD_SCOPE_SYSTEM
-#undef  PTHREAD_SCOPE_PROCESS
-#undef  PTHREAD_INHERIT_SCHED
-#undef  PTHREAD_EXPLICIT_SCHED
-#undef  PTHREAD_CANCEL_ENABLE
-#undef  PTHREAD_CANCEL_DISABLE
-#undef  PTHREAD_CANCEL_ASYNCHRONOUS
-#undef  PTHREAD_CANCEL_DEFERRED
-#undef  PTHREAD_CANCELED
-#undef  PTHREAD_PROCESS_PRIVATE
-#undef  PTHREAD_PROCESS_SHARED
-#undef  PTHREAD_ONCE_INIT
-#undef  PTHREAD_MUTEX_DEFAULT
-#undef  PTHREAD_MUTEX_RECURSIVE
-#undef  PTHREAD_MUTEX_NORMAL
-#undef  PTHREAD_MUTEX_ERRORCHECK
-#undef  PTHREAD_MUTEX_INITIALIZER
-#undef  PTHREAD_COND_INITIALIZER
-#undef  PTHREAD_RWLOCK_INITIALIZER
-
-/*
-**
-** API DEFINITION
-**
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Extra structure definitions
- */
-struct timeval;
-struct timespec;
-
-/*
- * GNU Pth indentification
- */
-#define _POSIX_THREAD_IS_CAPRICCIO 0x100
-
-/*
- * Compile time symbolic feature macros for portability
- * specification to applications using pthreads
- */
-#define _POSIX_THREADS
-#define _POSIX_THREAD_ATTR_STACKADDR
-#define _POSIX_THREAD_ATTR_STACKSIZE
-#undef  _POSIX_THREAD_PRIORITY_SCHEDULING
-#undef  _POSIX_THREAD_PRIO_INHERIT
-#undef  _POSIX_THREAD_PRIO_PROTECT
-#undef  _POSIX_THREAD_PROCESS_SHARED
-#undef  _POSIX_THREAD_SAFE_FUNCTIONS
-
-/*
- * System call mapping support type
- * (soft variant can be overridden)
- */
-//#define _POSIX_THREAD_SYSCALL_HARD @PTH_SYSCALL_HARD@
-//#ifndef _POSIX_THREAD_SYSCALL_SOFT
-//#define _POSIX_THREAD_SYSCALL_SOFT @PTH_SYSCALL_SOFT@
-//#endif
-
-/*
- * Run-time invariant values
- */
-#define PTHREAD_DESTRUCTOR_ITERATIONS  4
-#define PTHREAD_KEYS_MAX               256
-#define PTHREAD_STACK_MIN              8192
-#define PTHREAD_THREADS_MAX            10000 /* actually yet no restriction */
-
-/*
- * Flags for threads and thread attributes.
- */
-// People are using 0 for JOINABLE!
-#define PTHREAD_CREATE_DETACHED     0x01
-#define PTHREAD_CREATE_JOINABLE     0x0
-//#define PTHREAD_CREATE_DETACHED     0x01
-//#define PTHREAD_CREATE_JOINABLE     0x02
-#define PTHREAD_SCOPE_SYSTEM        0x03
-#define PTHREAD_SCOPE_PROCESS       0x04
-#define PTHREAD_INHERIT_SCHED       0x05
-#define PTHREAD_EXPLICIT_SCHED      0x06
-
-/*
- * Values for cancellation
- */
-#define PTHREAD_CANCEL_ENABLE        0x01
-#define PTHREAD_CANCEL_DISABLE       0x02
-#define PTHREAD_CANCEL_ASYNCHRONOUS  0x01
-#define PTHREAD_CANCEL_DEFERRED      0x02
-#define PTHREAD_CANCELED             ((void *)-1)
-
-/*
- * Flags for mutex priority attributes
- */
-#define PTHREAD_PRIO_INHERIT        0x00
-#define PTHREAD_PRIO_NONE           0x01
-#define PTHREAD_PRIO_PROTECT        0x02
-
-/*
- * Flags for read/write lock attributes
- */
-#define PTHREAD_PROCESS_PRIVATE     0x00
-#define PTHREAD_PROCESS_SHARED      0x01
-
-/*
- * Forward structure definitions.
- * These are mostly opaque to the application.
- */
-struct pthread_st;
-struct pthread_attr_st;
-struct pthread_cond_st;
-struct pthread_mutex_st;
-struct pthread_rwlock_st;
-struct sched_param;
-
-/*
- * Primitive system data type definitions required by P1003.1c
- */
-typedef struct  pthread_st              *pthread_t;
-typedef struct  pthread_attr_st         *pthread_attr_t;
-typedef int                              pthread_key_t;
-typedef int                              pthread_once_t;
-typedef int                              pthread_mutexattr_t;
-typedef struct  pthread_mutex_st        *pthread_mutex_t;
-typedef int                              pthread_condattr_t;
-typedef struct  pthread_cond_st         *pthread_cond_t;
-typedef int                              pthread_rwlockattr_t;
-typedef struct  pthread_rwlock_st       *pthread_rwlock_t;
-
-/*
- * Once support.
- */
-#define PTHREAD_ONCE_INIT 0
-
-/*
- * Mutex static initialization values.
- */
-enum pthread_mutextype {
-    PTHREAD_MUTEX_DEFAULT = 1,
-    PTHREAD_MUTEX_RECURSIVE,
-    PTHREAD_MUTEX_NORMAL,
-    PTHREAD_MUTEX_ERRORCHECK
-};
-
-enum pthread_sched {
-       SCHED_OTHER = 0,
-       SCHED_FIFO = 1,
-       SCHED_RR = 2
-};
-
-/*
- * Mutex/CondVar/RWLock static initialization values.
- */
-#define __PTHREAD_UNINITIALIZED 23
-
-#define PTHREAD_MUTEX_INITIALIZER   (pthread_mutex_t)(__PTHREAD_UNINITIALIZED)
-#define PTHREAD_COND_INITIALIZER    (pthread_cond_t)(__PTHREAD_UNINITIALIZED)
-#define PTHREAD_RWLOCK_INITIALIZER  (pthread_rwlock_t)(__PTHREAD_UNINITIALIZED)
-
-/*
- * IEEE (``POSIX'') Std 1003.1 Second Edition 1996-07-12
- */
-
-/* thread attribute routines */
-extern int       pthread_attr_init(pthread_attr_t *);
-extern int       pthread_attr_destroy(pthread_attr_t *);
-extern int       pthread_attr_setinheritsched(pthread_attr_t *, int);
-extern int       pthread_attr_getinheritsched(const pthread_attr_t *, int *);
-extern int       pthread_attr_setschedparam(pthread_attr_t *, struct sched_param *);
-extern int       pthread_attr_getschedparam(const pthread_attr_t *, struct sched_param *);
-extern int       pthread_attr_setschedpolicy(pthread_attr_t *, int);
-extern int       pthread_attr_getschedpolicy(const pthread_attr_t *, int *);
-extern int       pthread_attr_setscope(pthread_attr_t *, int);
-extern int       pthread_attr_getscope(const pthread_attr_t *, int *);
-extern int       pthread_attr_setstacksize(pthread_attr_t *, size_t);
-extern int       pthread_attr_getstacksize(const pthread_attr_t *, size_t *);
-extern int       pthread_attr_setstackaddr(pthread_attr_t *, void *);
-extern int       pthread_attr_getstackaddr(const pthread_attr_t *, void **);
-extern int       pthread_attr_setdetachstate(pthread_attr_t *, int);
-extern int       pthread_attr_getdetachstate(const pthread_attr_t *, int *);
-extern int       pthread_attr_setguardsize(pthread_attr_t *, int);
-extern int       pthread_attr_getguardsize(const pthread_attr_t *, int *);
-extern int       pthread_attr_setname_np(pthread_attr_t *, char *);
-extern int       pthread_attr_getname_np(const pthread_attr_t *, char **);
-extern int       pthread_attr_setprio_np(pthread_attr_t *, int);
-extern int       pthread_attr_getprio_np(const pthread_attr_t *, int *);
-
-/* thread routines */
-extern int       pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
-extern int       __pthread_detach(pthread_t);
-extern int       pthread_detach(pthread_t);
-/* #define          pthread_detach(t) __pthread_detach(t) */
-extern pthread_t pthread_self(void);
-extern int       pthread_equal(pthread_t, pthread_t);
-extern int       pthread_yield_np(void);
-extern int       pthread_yield(void);
-extern void      pthread_exit(void *);
-extern int       pthread_join(pthread_t, void **);
-extern int       pthread_once(pthread_once_t *, void (*)(void));
-extern int       pthread_sigmask(int, const sigset_t *, sigset_t *);
-extern int       pthread_kill(pthread_t, int);
-
-/* concurrency routines */
-extern int       pthread_getconcurrency(void);
-extern int       pthread_setconcurrency(int);
-
-/* context routines */
-extern int       pthread_key_create(pthread_key_t *, void (*)(void *));
-extern int       pthread_key_delete(pthread_key_t);
-extern int       pthread_setspecific(pthread_key_t, const void *);
-extern void     *pthread_getspecific(pthread_key_t);
-
-/* cancel routines */
-extern int       pthread_cancel(pthread_t);
-extern void      pthread_testcancel(void);
-extern int       pthread_setcancelstate(int, int *);
-extern int       pthread_setcanceltype(int, int *);
-
-/* scheduler routines */
-extern int       pthread_setschedparam(pthread_t, int, const struct sched_param *);
-extern int       pthread_getschedparam(pthread_t, int *, struct sched_param *);
-
-/* cleanup routines */
-extern void      pthread_cleanup_push(void (*)(void *), void *);
-extern void      pthread_cleanup_pop(int);
-extern int       pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
-
-/* mutex attribute routines */
-extern int       pthread_mutexattr_init(pthread_mutexattr_t *);
-extern int       pthread_mutexattr_destroy(pthread_mutexattr_t *);
-extern int       pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int);
-extern int       pthread_mutexattr_getprioceiling(pthread_mutexattr_t *, int *);
-extern int       pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
-extern int       pthread_mutexattr_getprotocol(pthread_mutexattr_t *, int *);
-extern int       pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
-extern int       pthread_mutexattr_getpshared(pthread_mutexattr_t *, int *);
-extern int       pthread_mutexattr_settype(pthread_mutexattr_t *, int);
-extern int       pthread_mutexattr_gettype(pthread_mutexattr_t *, int *);
-
-/* mutex routines */
-extern int       pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
-extern int       pthread_mutex_destroy(pthread_mutex_t *);
-extern int       pthread_mutex_setprioceiling(pthread_mutex_t *, int, int *);
-extern int       pthread_mutex_getprioceiling(pthread_mutex_t *, int *);
-extern int       pthread_mutex_lock(pthread_mutex_t *);
-extern int       pthread_mutex_trylock(pthread_mutex_t *);
-extern int       pthread_mutex_unlock(pthread_mutex_t *);
-
-/* rwlock attribute routines */
-extern int       pthread_rwlockattr_init(pthread_rwlockattr_t *);
-extern int       pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
-extern int       pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
-extern int       pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *, int *);
-
-/* rwlock routines */
-extern int       pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
-extern int       pthread_rwlock_destroy(pthread_rwlock_t *);
-extern int       pthread_rwlock_rdlock(pthread_rwlock_t *);
-extern int       pthread_rwlock_tryrdlock(pthread_rwlock_t *);
-extern int       pthread_rwlock_wrlock(pthread_rwlock_t *);
-extern int       pthread_rwlock_trywrlock(pthread_rwlock_t *);
-extern int       pthread_rwlock_unlock(pthread_rwlock_t *);
-
-/* condition attribute routines */
-extern int       pthread_condattr_init(pthread_condattr_t *);
-extern int       pthread_condattr_destroy(pthread_condattr_t *);
-extern int       pthread_condattr_setpshared(pthread_condattr_t *, int);
-extern int       pthread_condattr_getpshared(pthread_condattr_t *, int *);
-
-/* condition routines */
-extern int       pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
-extern int       pthread_cond_destroy(pthread_cond_t *);
-extern int       pthread_cond_broadcast(pthread_cond_t *);
-extern int       pthread_cond_signal(pthread_cond_t *);
-extern int       pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
-extern int       pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
-
-/*
- * Extensions created by POSIX 1003.1j
- */
-extern int       pthread_abort(pthread_t);
-
-/*
- * Replacement Functions (threading aware)
- */
-
-/*
-  zf: this is a good list of replacements we need to implement
-
-extern pid_t              __pthread_fork(void);
-extern unsigned int       __pthread_sleep(unsigned int);
-extern int                __pthread_sigwait(const sigset_t *, int *);
-extern pid_t              __pthread_waitpid(pid_t, int *, int);
-extern int                __pthread_connect(int, struct sockaddr *, socklen_t);
-extern int                __pthread_accept(int, struct sockaddr *, socklen_t *);
-extern int                __pthread_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-extern int                __pthread_poll(struct pollfd *, nfds_t, int);
-extern ssize_t            __pthread_read(int, void *, size_t);
-extern ssize_t            __pthread_write(int, const void *, size_t);
-extern ssize_t            __pthread_readv(int, const struct iovec *, int);
-extern ssize_t            __pthread_writev(int, const struct iovec *, int);
-extern ssize_t            __pthread_recv(int, void *, size_t, int);
-extern ssize_t            __pthread_send(int, const void *, size_t, int);
-extern ssize_t            __pthread_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
-extern ssize_t            __pthread_sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
-extern ssize_t            __pthread_pread(int, void *, size_t, off_t);
-extern ssize_t            __pthread_pwrite(int, const void *, size_t, off_t);
-
-*/
-
-/*
- * More "special" POSIX stuff
- */
-
-  //#define sched_yield  pthread_yield_np
-
-#endif
diff --git a/user/c3po/include/semaphore.h b/user/c3po/include/semaphore.h
deleted file mode 100644 (file)
index bbdd951..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#ifndef _SEMAPHORE_H
-#define _SEMAPHORE_H    1
-
-// apache needs this to compile
-# error semaphores are not supported
-
-#endif  /* semaphore.h */
diff --git a/user/c3po/include/stackbounds.h b/user/c3po/include/stackbounds.h
deleted file mode 100644 (file)
index 642a41e..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef STACKBOUNDS_H
-#define STACKBOUNDS_H
-
-#pragma stacksize("strlen", 128)
-#pragma stacksize("strcpy", 128)
-#pragma stacksize("strcmp", 128)
-#pragma stacksize("strcasecmp", 128)
-#pragma stacksize("strchr", 128)
-#pragma stacksize("strrchr", 128)
-
-#pragma stacksize("tolower", 128)
-
-#pragma stacksize("memset", 128)
-#pragma stacksize("memcpy", 128)
-#pragma stacksize("memcmp", 128)
-#pragma stacksize("memchr", 128)
-
-#pragma stacksize("__errno_location", 128)
-
-#pragma stacksize("__ctype_b_loc", 128)
-#pragma stacksize("__xstat", 128)
-
-#pragma stacksize("read", 256)
-#pragma stacksize("write", 256)
-#pragma stacksize("readv", 256)
-#pragma stacksize("writev", 256)
-#pragma stacksize("open", 256)
-#pragma stacksize("close", 256)
-#pragma stacksize("accept", 256)
-#pragma stacksize("poll", 256)
-#pragma stacksize("fcntl", 256)
-
-#pragma stacksize("pthread_mutex_lock", 128)
-#pragma stacksize("pthread_mutex_unlock", 128)
-#pragma stacksize("pthread_cond_wait", 128)
-#pragma stacksize("pthread_cond_signal", 128)
-
-#pragma stacksize("pthread_yield", 128)
-
-#endif // STACKBOUNDS_H
diff --git a/user/c3po/include/stacklink.h b/user/c3po/include/stacklink.h
deleted file mode 100644 (file)
index aba1cf4..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#ifndef STACKLINK_H
-#define STACKLINK_H
-
-// -----------------------------------------------------------------------
-
-// stacklink.h
-//
-// This module defines the primary interface for stack chunk allocation
-// and linking.  It is used by capriccio's thread system to allocate
-// initial stack chunks, and it is used by the build system to link and
-// unlink stack chunks where appropriate.
-
-// -----------------------------------------------------------------------
-
-// Compile-time settings: comment or uncomment as you please.
-
-// Collect statistics at each call site.
-//#define STACK_CALL_STATS
-
-// Collect statistics about stack depth.
-//#define STATS_USAGE_STATS
-
-// Check for stack overflow when checking for free space on a chunk.
-//#define STACK_PARANOID
-
-// Print statistics and debug info.
-//#define STACK_VERBOSE
-
-// -----------------------------------------------------------------------
-
-// Global variables.
-
-// Current stack fingerprint.
-extern int stack_fingerprint;
-
-// Counters for tracking how often checks are executed.
-extern int stack_extern;
-extern int stack_check_link;
-extern int stack_check_nolink;
-extern int stack_nocheck;
-
-// Counters for tracking stack use.
-extern int stack_waste_ext;
-extern int stack_waste_int;
-extern int stack_allocchunks[];
-
-// The current state of the stack and the free lists for various chunk sizes.
-// Indices to the free list array indicate sizes (kb log2 scale).
-extern void *stack_bottom;
-extern void *stack_freechunks[];
-
-// -----------------------------------------------------------------------
-
-// Function prototypes.  The macros below should only call these functions.
-
-// Ensure that stack_freechunks[bucket] in non-null.
-extern void stack_alloc_chunk(int bucket);
-
-// Get a chunk from the specified bucket or return a chunk when finished.
-extern void *stack_get_chunk(int bucket);
-extern void stack_return_chunk(int bucket, void *chunk);
-
-// Error and stats reporting.
-extern void stack_report_call_stats(void);
-extern void stack_report_usage_stats(void);
-extern void stack_report_link(void *chunk, int used, int node, int succ);
-extern void stack_report_unlink(void *chunk);
-extern void stack_report_overflow(void);
-extern void stack_report_unreachable(int id, char *name);
-
-// -----------------------------------------------------------------------
-
-// Implement settings.
-
-#ifdef STACK_CALL_STATS
-# define STATS_CALL_INC(stat) { stat++; }
-#else // ndef STACK_CALL_STATS
-# define STATS_CALL_INC(stat)
-#endif // STACK_CALL_STATS
-
-#ifdef STATS_USAGE_STATS
-# define STATS_USAGE_INC(stat, amt) { (stat) += (amt); }
-# define STATS_USAGE_DEC(stat, amt) { (stat) -= (amt); }
-#else // ndef STATS_USAGE_STATS
-# define STATS_USAGE_INC(stat, amt)
-# define STATS_USAGE_DEC(stat, amt)
-#endif // STATS_USAGE_STATS
-
-#ifdef STACK_PARANOID
-# define CHECK_OVERFLOW() \
-    { if (savesp < stack_bottom) stack_report_overflow(); }
-#else // ndef STACK_PARANOID
-# define CHECK_OVERFLOW()
-#endif // STACK_PARANOID
-
-#ifdef STACK_VERBOSE
-# define REPORT_LINK(chunk, used, node, succ) \
-    stack_report_link(chunk, used, node, succ)
-# define REPORT_UNLINK(chunk) stack_report_unlink(chunk)
-#else // ndef STACK_VERBOSE
-# define REPORT_LINK(chunk, used, node, succ)
-# define REPORT_UNLINK(chunk)
-#endif // STACK_VERBOSE
-
-// -----------------------------------------------------------------------
-
-// Magic macro code follows.  Note that I got rid of the do { ... } while (0)
-// construct because we may not be turning on optimizations that would
-// eliminate the corresponding conditionals.  We don't need to use these
-// macros in any scenarios where do/while would prevent a syntax error.
-
-// -----------------------------------------------------------------------
-
-// Private macros: don't call these directly outside of this file or stack.c.
-
-// Get a chunk from the specified free list (bucket).
-#define GET_CHUNK(bucket, chunk) \
-{ \
-    if (stack_freechunks[bucket] == 0) { \
-        stack_alloc_chunk(bucket); \
-    } \
-    (chunk) = stack_freechunks[bucket]; \
-    stack_freechunks[bucket] = *(((void**) (chunk)) - 1); \
-    STATS_USAGE_INC(stack_allocchunks[bucket], 1); \
-}
-
-// Return a chunk to the free list.
-#define RETURN_CHUNK(bucket, chunk) \
-{ \
-    STATS_USAGE_DEC(stack_allocchunks[bucket], 1); \
-    *(((void**) (chunk)) - 1) = stack_freechunks[bucket]; \
-    stack_freechunks[bucket] = (chunk); \
-}
-
-// Unconditionally link a stack chunk of the specified size.
-// Note that stack_size == (1 << (bucket + 10)).  I specify them
-// separately to reduce overhead when optimizations are disabled.
-#define STACK_LINK_NOSTATS(stack_size, bucket) \
-{ \
-    GET_CHUNK(bucket, savechunk); \
-    savebottom = stack_bottom; \
-    stack_bottom = savechunk - (stack_size); \
-    asm volatile("movl %%esp,%0" : "=g" (savesp) :); \
-    savesp = (void*) ((unsigned long) savechunk - (unsigned long) savesp); \
-    asm volatile("addl %0,%%esp" : : "g" (savesp) : "esp"); \
-}
-
-// Unconditionally unlink a stack chunk.
-#define STACK_UNLINK_NOSTATS(bucket) \
-{ \
-    asm volatile("subl %0,%%esp" : : "g" (savesp) : "esp"); \
-    stack_bottom = savebottom; \
-    RETURN_CHUNK(bucket, savechunk); \
-}
-
-// Unconditionally link a stack chunk of the specified size, as above.
-// Record some stats using the new stack chunk while we're at it.
-#define STACK_LINK(stack_size, bucket, node, succ) \
-{ \
-    STACK_LINK_NOSTATS(stack_size, bucket); \
-    STATS_USAGE_INC(stack_waste_int, ((void*) &savebottom) - stack_bottom); \
-    REPORT_LINK(savechunk, \
-                (((unsigned long) savechunk) - \
-                 ((unsigned long) savesp) - \
-                 ((unsigned long) savebottom)), \
-                (node), (succ)); \
-}
-
-// Unconditionally unlink a stack chunk, with stats.
-#define STACK_UNLINK(bucket) \
-{ \
-    REPORT_UNLINK(savechunk); \
-    STATS_USAGE_DEC(stack_waste_int, ((void*) &savebottom) - stack_bottom); \
-    STACK_UNLINK_NOSTATS(bucket); \
-}
-
-// -----------------------------------------------------------------------
-
-// Public macros: this is your interface.
-
-// Unconditionally link a stack chunk, presumably for external function stacks.
-#define STACK_EXTERN_LINK(stack_size, bucket, node, succ) \
-{ \
-    STATS_CALL_INC(stack_extern); \
-    STACK_LINK(stack_size, bucket, node, succ); \
-}
-
-// Unconditionally unlink an external function stack chunk.
-#define STACK_EXTERN_UNLINK(bucket) \
-{ \
-    STACK_UNLINK(bucket); \
-}
-
-// Link a new stack chunk if necessary.
-#define STACK_CHECK_LINK(max_path, stack_size, bucket, node, succ) \
-{ \
-    asm volatile("movl %%esp,%0" : "=g" (savesp) :); \
-    CHECK_OVERFLOW(); \
-    if ((unsigned long) (savesp - stack_bottom) <= (unsigned long) (max_path)){\
-        STATS_CALL_INC(stack_check_link); \
-        STACK_LINK(stack_size, bucket, node, succ); \
-    } else { \
-        STATS_CALL_INC(stack_check_nolink); \
-        savesp = 0; \
-    } \
-}
-
-// Unlink a stack chunk if the above macro linked one.
-#define STACK_CHECK_UNLINK(bucket) \
-{ \
-    if (savesp != 0) { \
-        STACK_UNLINK(bucket); \
-    } \
-}
-
-// Increment counters for call sites with no stack linking.
-#define STACK_NOCHECK(node, succ) \
-{ \
-    STATS_CALL_INC(stack_nocheck); \
-}
-
-// Report an error for a function presumed to be unreachable.
-#define STACK_UNREACHABLE(id, name) \
-{ \
-    stack_report_unreachable(id, name); \
-}
-
-#endif // STACKLINK_H
diff --git a/user/c3po/stack/Makefrag b/user/c3po/stack/Makefrag
deleted file mode 100644 (file)
index 040a53d..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-STACK_NAME    := stack
-STACK_UCNAME  := $(call uc, $(STACK_NAME))
-STACK_CFLAGS  := $(CFLAGS_USER)
-STACK_HEADERS := $(wildcard $(STACKDIR)/*.h)
-STACK_CFILES  := $(wildcard $(STACKDIR)/*.c)
-STACK_OBJDIR  := $(OBJDIR)/$(STACK_NAME)
-STACK_OBJS    := $(patsubst %.c, %.o, $(STACK_CFILES))
-STACK_OBJS    := $(foreach x, $(STACK_OBJS), $(STACK_OBJDIR)/$(call filename,$(x)))
-
-LIBSTACK = $(STACK_OBJDIR)/lib$(STACK_NAME).a
-
-$(STACK_NAME)-clean:
-       @echo + clean [$(LIBUCNAME) $(STACK_UCNAME)]
-       $(Q)rm -rf $(STACK_OBJS) $(LIBSTACK)
-       $(Q)rm -rf $(STACK_OBJDIR)
-
-$(LIBSTACK): $(STACK_OBJS)
-       @echo + ar [$(LIBUCNAME) $(STACK_UCNAME)] $@
-       $(Q)$(AR) rc $@ $^
-
-$(STACK_OBJDIR)/%.o: $(STACKDIR)/%.c $(STACK_HEADERS)
-       @echo + cc [$(LIBUCNAME) $(STACK_UCNAME)] $<
-       @mkdir -p $(@D)
-       $(Q)$(CC) $(STACK_CFLAGS) $(INCS) -o $@ -c $<
-
diff --git a/user/c3po/stack/fptr.c b/user/c3po/stack/fptr.c
deleted file mode 100644 (file)
index d037058..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "util.h"
-
-int fptr_caller = -1;
-
-void
-fptr_report_unexpected_call(int cur)
-{
-  output("unexpected call %d -> %d\n", fptr_caller, cur);
-}
-
-void
-fptr_report_unvalidated_return(int cur)
-{
-  output("unvalidated fptr_caller %d (return to %d)\n", fptr_caller, cur);
-}
-
-void
-fptr_report_unvalidated_overwrite(int cur)
-{
-  output("unvalidated fptr_caller %d (overwrite in %d)\n", fptr_caller, cur);
-}
diff --git a/user/c3po/stack/stack.c b/user/c3po/stack/stack.c
deleted file mode 100644 (file)
index f8671a3..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "stacklink.h"
-#include "util.h"
-
-#ifndef DEBUG_stack_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-#define MAX_BUCKETS 32
-
-int stack_fingerprint = 0;
-
-int stack_extern = 0;
-int stack_check_link = 0;
-int stack_check_nolink = 0;
-int stack_nocheck = 0;
-
-int stack_waste_ext = 0;
-int stack_waste_int = 0;
-int stack_allocchunks[MAX_BUCKETS] =
-{
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-// disable stack checking for initial thread
-void *stack_bottom = NULL;
-void *stack_freechunks[MAX_BUCKETS] =
-{
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-void stack_alloc_many_chunks(int bucket)
-{
-  int bytes = 1 << 16; // 64 KB
-  char *p = (char*) malloc(bytes);
-
-  if (p != NULL) {
-    int chunkbytes = 1 << (bucket + 10);
-    char *base = p;
-
-    // get pointer to end of memory area and align
-    p += bytes;
-    p = (char*) (((int) p) & ~(chunkbytes - 1));
-
-    // we should get at least one chunk
-    assert((p - base) >= chunkbytes);
-
-    while ((p - base) >= chunkbytes) {
-      *(((void**) p) - 1) = stack_freechunks[bucket];
-      stack_freechunks[bucket] = p;
-
-      debug("allocated %p\n", p);
-
-      p -= chunkbytes;
-    }
-  } else {
-    output("malloc error\n");
-    abort();
-  }
-}
-
-void stack_alloc_one_chunk(int bucket)
-{
-  int bytes = 1 << (bucket + 10);
-  char *p = (char*) malloc(bytes);
-
-  if (p != NULL) {
-    p += bytes;
-
-    *(((void**) p) - 1) = stack_freechunks[bucket];
-    stack_freechunks[bucket] = p;
-
-    debug("allocated %p\n", p);
-  } else {
-    output("malloc error\n");
-    abort();
-  }
-}
-
-void stack_alloc_chunk(int bucket)
-{
-  assert(bucket >= 0);
-  if (bucket < 5) {
-    stack_alloc_many_chunks(bucket);
-  } else {
-    stack_alloc_one_chunk(bucket);
-  }
-}
-
-void *stack_get_chunk(int bucket)
-{
-  void *chunk;
-  GET_CHUNK(bucket, chunk);
-  return chunk;
-}
-
-void stack_return_chunk(int bucket, void *chunk)
-{
-  // FIXME: this needs to follow any chained pages that still remain, in the case of pthread_exit()
-
-  RETURN_CHUNK(bucket, chunk);
-}
-
-void stack_report_call_stats(void)
-{
-  output("links:      %d check/links    %d check/nolinks\n"
-         "            %d externals    %d nochecks\n",
-         stack_check_link, stack_check_nolink,
-         stack_extern, stack_nocheck);
-}
-
-void stack_report_usage_stats(void)
-{
-  int total = 0;
-  int size;
-  int i;
-
-  for (i = 0, size = 1; i < MAX_BUCKETS; i++, size <<= 1) {
-    total += (stack_allocchunks[i] * size);
-  }
-
-  output("stack:      %d KB allocated    %d KB internal waste\n",
-         total, stack_waste_int / 1024);
-}
-
-void stack_report_link(void *chunk, int used, int node, int succ)
-{
-  output("linking stack %p (used %d node %d succ %d )\n",
-         chunk, used, node, succ);
-}
-
-void stack_report_unlink(void *chunk)
-{
-  output("unlinking stack %p\n", chunk);
-}
-
-void stack_report_overflow(void)
-{
-  abort();
-}
-
-void stack_report_unreachable(int id, char *name)
-{
-  output("error: reached unreachable node (%d, %s)\n", id, name);
-  abort();
-}
diff --git a/user/c3po/threads/Makefrag b/user/c3po/threads/Makefrag
deleted file mode 100644 (file)
index f801db4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-THREADS_NAME    := threads
-THREADS_UCNAME  := $(call uc, $(THREADS_NAME))
-THREADS_CFLAGS  := $(CFLAGS_USER)
-THREADS_HEADERS := $(wildcard $(THREADSDIR)/*.h)
-THREADS_CFILES  := $(wildcard $(THREADSDIR)/*.c)
-THREADS_OBJDIR  := $(OBJDIR)/$(THREADS_NAME)
-THREADS_OBJS    := $(patsubst %.c, %.o, $(THREADS_CFILES))
-THREADS_OBJS    := $(foreach x, $(THREADS_OBJS), $(THREADS_OBJDIR)/$(call filename,$(x)))
-
-LIBTHREADS = $(THREADS_OBJDIR)/lib$(THREADS_NAME).a
-
-$(THREADS_NAME)-clean:
-       @echo + clean [$(LIBUCNAME) $(THREADS_UCNAME)]
-       $(Q)rm -rf $(THREADS_OBJS) $(LIBTHREADS)
-       $(Q)rm -rf $(THREADS_OBJDIR)
-
-$(LIBTHREADS): $(THREADS_OBJS)
-       @echo + ar [$(LIBUCNAME) $(THREADS_UCNAME)] $@
-       $(Q)$(AR) rc $@ $^
-
-$(THREADS_OBJDIR)/%.o: $(THREADSDIR)/%.c $(THREADS_HEADERS)
-       @echo + cc [$(LIBUCNAME) $(THREADS_UCNAME)] $<
-       @mkdir -p $(@D)
-       $(Q)$(CC) $(THREADS_CFLAGS) $(INCS) -o $@ -c $<
-
diff --git a/user/c3po/threads/blocking_graph.c b/user/c3po/threads/blocking_graph.c
deleted file mode 100644 (file)
index 7d29451..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/**
- *
- *  Fucntions to gather/manage statistics about nodes in the call graph
- *
- **/
-
-#include "threadlib.h"
-#include "threadlib_internal.h"
-#include "blocking_graph.h"
-#include "util.h"
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <execinfo.h>
-
-
-#ifndef DEBUG_blocking_graph_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// Set this to 1 to print thread stats
-#define PRINT_STAT 0
-
-
-// external flags, to turn off stats gathering
-int bg_save_stats = 1;
-int bg_stats_epoch = 0;
-
-
-// track the nodes - used for dynamic graph building 
-// (BG_NODE_TYPE_YIELD and BG_NODE_TYPE_NAMED)
-static PLHashTable *nodehash = NULL;
-
-
-// function prototypes
-PLHashNumber HashPtr(const void *key);
-
-
-// used to inform the BG routines how they got there...  Set by the IO routines
-const char *cap_current_syscall;  
-
-//////////////////////////////////////////////////////////////////////
-// node list handling
-//////////////////////////////////////////////////////////////////////
-
-// dummy node, for threads that don't have a real node yet
-bg_node_t *bg_dummy_node=NULL;
-bg_node_t *bg_exit_node=NULL;
-
-// FIXME: this stuff is horribly non-thread safe!!  There are races
-// both on bg_maxnode, and (due to realloc) bg_nodelist!!.  Changes to
-// both should be infrequent, so optomistic concurrency control is
-// ultimately the way to go.
-
-// list of nodes
-int bg_num_nodes = 0;
-static int bg_nodelist_size = 0;
-bg_node_t **bg_nodelist = NULL;
-
-#define BG_NODELIST_INC 100
-
-
-static inline bg_node_t* bg_newnode(bg_node_type_t type)
-{
-  bg_node_t* node;
-
-  // allocate the node
-  node = malloc( sizeof(bg_node_t) );
-  assert(node);
-  bzero(node, sizeof(bg_node_t));
-
-  node->type = type;
-  node->node_num = bg_num_nodes++;
-  node->latch = (latch_t)LATCH_INITIALIZER_UNLOCKED;
-
-  // set the system call
-  node->system_call = (cap_current_syscall ? cap_current_syscall : "unknown");
-
-  node->edgehash = PL_NewHashTable(20, HashPtr, PL_CompareValues, PL_CompareValues, NULL, NULL);
-  assert(node->edgehash);
-
-  // allocate list space if necessary
-  if(node->node_num >= bg_nodelist_size) {
-    bg_nodelist = realloc(bg_nodelist, (bg_nodelist_size+BG_NODELIST_INC)*sizeof(bg_node_t*));
-    assert(bg_nodelist);
-    bzero(&bg_nodelist[bg_nodelist_size], BG_NODELIST_INC*sizeof(bg_node_t*));
-    bg_nodelist_size += BG_NODELIST_INC;
-  }
-
-  bg_nodelist[ node->node_num ] = node;
-
-  return node;
-}
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// blocking graph node management
-//////////////////////////////////////////////////////////////////////
-
-static latch_t nodehash_latch = LATCH_INITIALIZER_UNLOCKED;
-
-/**
- * add a named node
- **/
-void bg_named_set_node(char *file, char *func, int line)
-{
-  bg_node_t *this_node;
-  static bg_node_t key_node;
-
-  // we skipped a blocking point without actually yielding.  Insert a
-  // yield now.  This both changes how the edges in the graph look,
-  // and ensures that we have enough yields.
-  // 
-  // FIXME: not sure if this is really a good idea!!
-  if( current_thread->curr_stats.node != NULL )
-    thread_yield();
-
-
-  // lock the node hash
-  thread_latch( nodehash_latch );
-
-  key_node.type = BG_NODE_TYPE_NAMED;
-  key_node.u.named.file = file;
-  key_node.u.named.func = func;
-  key_node.u.named.line = line;
-
-  // get the node structure for the current node
-  this_node = PL_HashTableLookup(nodehash, &key_node);
-  if( this_node == NULL ) {
-    this_node = bg_newnode(BG_NODE_TYPE_NAMED);
-
-    this_node->u.named.file = file;
-    this_node->u.named.func = func;
-    this_node->u.named.line = line;
-
-    PL_HashTableAdd(nodehash, this_node, this_node);
-  }
-
-  // unlock the node hash
-  thread_unlatch( nodehash_latch );
-
-  current_thread->curr_stats.node = this_node;
-}
-
-
-/**
- * Add a cil-specified node
- **/
-// FIXME: implement this in earnest
-void bg_cil_set_node(int num)
-{
-  // we skipped a blocking point without actually yielding.  Insert a
-  // yield now.  This both changes how the edges in the graph look,
-  // and ensures that we have enough yields.
-  // 
-  // FIXME: not sure if this is really a good idea!!
-  if( current_thread->curr_stats.node != NULL )
-    thread_yield();
-
-  // this should have already been initialized
-  current_thread->curr_stats.node = bg_nodelist[ num ];
-}
-
-
-
-/**
- * add a yield point node
- **/
-#define MAX_STACK_FRAMES 200
-void bg_backtrace_set_node()
-{
-  bg_node_t *this_node;
-  static void* stack[MAX_STACK_FRAMES];
-  static bg_node_t key_node;
-
-  // lock
-  thread_latch( nodehash_latch );
-  
-  // fill in the key node
-  key_node.type = BG_NODE_TYPE_YIELD;
-  key_node.u.yield.stack = stack;
-  key_node.u.yield.numframes = backtrace(stack, MAX_STACK_FRAMES);
-  
-  // look up this stack trace
-  this_node = (bg_node_t*) PL_HashTableLookup(nodehash, &key_node);
-  if(this_node == NULL) {
-    this_node = bg_newnode(BG_NODE_TYPE_YIELD);
-
-    assert( cap_current_syscall ); // so we can find the places that don't set this...
-    
-    this_node->u.yield.numframes = key_node.u.yield.numframes;
-    this_node->u.yield.stack = malloc(sizeof(void*) * key_node.u.yield.numframes); 
-    assert(this_node->u.yield.stack);
-    memcpy(this_node->u.yield.stack, stack, sizeof(void*) * key_node.u.yield.numframes);
-    
-    PL_HashTableAdd(nodehash, this_node, this_node);
-  }
-  
-  // unlock
-  thread_unlatch( nodehash_latch );
-
-  current_thread->curr_stats.node = this_node;
-}
-
-
-/**
- * update the blocking graph node for the current thread.  This also
- * updates the stats for the node, and the edge just taken.
- **/
-
-// keep totals and show averages
-//#define ADD_STATS(sum,new) (sum += new)
-//#define AVG_STATS(sum,count) (count > 0 ? (sum/count) : 0)
-
-// keep a decaying history
-// FIXME: cheesy hack here to do fixed-point arithmatic.  needs to be un-done on output!!
-#define ADD_STATS(avg,new) ( avg = (avg==0) ? ((new)<<2) : ((avg*7 + ((new)<<2)) >> 3) )
-#define AVG_STATS(avg,count) (avg>>2)
-
-
-void bg_update_stats()
-{
-  bg_node_t *this_node = current_thread->curr_stats.node;
-  bg_node_t *prev_node = current_thread->prev_stats.node;
-  thread_stats_t *prev_stats = &current_thread->prev_stats;
-  thread_stats_t *curr_stats = &current_thread->curr_stats;
-  bg_edge_t *edge;
-
-  // short circuit, if there's nothing to do.  
-  //
-  // FIXME: need to do epochs or something, so the first set of stats
-  // aren't bogus when we turn things on again.
-
-  // update stats for the current thread
-  bg_set_current_stats( curr_stats );
-
-  // if the prev stats are not from the current epoch, don't add the
-  // info in, as it isn't valid
-  if( prev_stats->epoch != bg_stats_epoch )
-    return;
-  
-
-  // update aggregate stats for the previous node
-  {
-    // NOTE: don't bother latching since the numbers are only updated
-    // here, and it's not that big of a deal if others see slightly
-    // inconsistent data
-
-    prev_node->stats.count++;
-
-    // update the stack usage.  NOTE: the stack grows down, so we subtract the new from the old
-    ADD_STATS(prev_node->stats.stack, prev_stats->stack - curr_stats->stack);
-    
-    // update the total stack numbers as well
-    ADD_STATS(total_stack_in_use, prev_stats->stack - curr_stats->stack);
-    
-    // update the cpu ticks, memory, etc.
-    ADD_STATS(prev_node->stats.cpu_ticks, curr_stats->cpu_ticks - prev_stats->cpu_ticks);
-#ifdef USE_PERFCTR
-    ADD_STATS(prev_node->stats.real_ticks, curr_stats->real_ticks - prev_stats->real_ticks);
-#endif // USE_PERFCTR
-    ADD_STATS(prev_node->stats.files, curr_stats->files - prev_stats->files);
-    ADD_STATS(prev_node->stats.sockets, curr_stats->sockets - prev_stats->sockets);
-    ADD_STATS(prev_node->stats.heap, curr_stats->heap - prev_stats->heap);
-  }
-
-  // get the edge structure from prev_node -> this_node
-  {
-    // get or add the edge structure
-    thread_latch( prev_node->latch );
-    edge = PL_HashTableLookup(prev_node->edgehash, this_node);
-    if( edge == NULL ) {
-      edge = malloc( sizeof(bg_edge_t) );
-      assert(edge);
-      bzero(edge, sizeof(bg_edge_t));
-      edge->src  = prev_node;
-      edge->dest = this_node;
-      edge->latch = (latch_t)LATCH_INITIALIZER_UNLOCKED;
-      PL_HashTableAdd(prev_node->edgehash, this_node, edge);
-    }
-    thread_unlatch( prev_node->latch );
-    // update the edge stats.  NOTE: as above, no latch needed
-    {
-      edge->stats.count++;
-      assert( edge->stats.count > 0 );
-      
-      // update the stack usage.  NOTE: the stack grows down, so we subtract the new from the old
-      ADD_STATS(edge->stats.stack, prev_stats->stack - curr_stats->stack);
-      
-      // update the total stack numbers as well
-      ADD_STATS(total_stack_in_use, prev_stats->stack - curr_stats->stack);
-      
-      // update the cpu ticks, memory, etc.
-      ADD_STATS(edge->stats.cpu_ticks, curr_stats->cpu_ticks - prev_stats->cpu_ticks);
-#ifdef USE_PERFCTR
-      ADD_STATS(edge->stats.real_ticks, curr_stats->real_ticks - prev_stats->real_ticks);
-#endif
-      ADD_STATS(edge->stats.files, curr_stats->files - prev_stats->files);
-      ADD_STATS(edge->stats.sockets, curr_stats->sockets - prev_stats->sockets);
-      ADD_STATS(edge->stats.heap, curr_stats->heap - prev_stats->heap);
-    }
-  }
-
-
-  // update some global stats
-  update_edge_totals( curr_stats->cpu_ticks - prev_stats->cpu_ticks );
-
-}
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// printing functions
-//////////////////////////////////////////////////////////////////////
-
-
-PRIntn edge_enumerator(PLHashEntry *e, PRIntn i, void *arg)
-{
-  bg_edge_t *edge = (bg_edge_t*) e->value;
-  bg_node_t *s = edge->src;
-  bg_node_t *d = edge->dest;
-  (void) arg, (void) i;
-
-  // header for this edge
-  switch( edge->src->type ) {
-  case BG_NODE_TYPE_NAMED:
-    output("  %s:%s():%d -> %s:%s():%d", 
-           s->u.named.file, s->u.named.func, s->u.named.line, 
-           d->u.named.file, d->u.named.func, d->u.named.line);
-    break;
-  default: 
-    output("  %3d -> %3d", s->node_num, d->node_num);
-  }
-
-  output("     [ label = \"");
-  output(" num %6d  \\l", edge->stats.count);
-  output(" cpu  %6lld   \\l",  AVG_STATS(edge->stats.cpu_ticks,   edge->stats.count));
-#ifdef USE_PERFCTR
-  output(" rcpu %6lld   \\l",  AVG_STATS(edge->stats.real_ticks,  edge->stats.count));
-#endif
-  output(" stak %ld     \\l",  AVG_STATS(edge->stats.stack,       edge->stats.count));
-  output(" heap %ld     \\l",  AVG_STATS(edge->stats.heap,        edge->stats.count)); 
-  output(" sock %d     \\l",   AVG_STATS(edge->stats.sockets,     edge->stats.count)); 
-  output(" file %d     \\l",   AVG_STATS(edge->stats.files,       edge->stats.count)); 
-  //output("       // mutexes/run  %d\n", edge->stats.mutexes / edge->stats.count); 
-  output("\" ");
-  if( edge->stats.stack < 0 )   // FIXME: better heuristic here
-    output(" color=green");
-  output(" ]\n");
-  
-  return 0;
-}
-
-
-void dump_blocking_graph(void)
-{
-  int i;
-
-  output("// blocking graph dump - create graph with dot -Tgif -oOUTFILE INFILE\n");
-  output("digraph foo {\n");
-  output("  ratio=compress\n");
-  output("  margin=\"0,0\"\n");
-  output("  nodesep=0.1\n");
-  output("  ranksep=0.001\n");
-  output("  rankdir=LR\n");
-  output("  ordering=out\n");
-  output("  node [shape=ellipse style=filled fillcolor=\"#e0e0e0\" color=black]\n");
-  output("  node [label=\"\\N\" fontsize=10 height=.1 width=.1]\n");
-  output("  edge [fontsize=7 arrowsize=.8]\n");
-  output("  \n");
-
-  // output the nodes in order, so the graph will be reasonable looking
-  output("  // NODES\n");
-  for(i=0; i<bg_num_nodes; i++) {
-    bg_node_t *node = bg_nodelist[i];
-    if(node->num_here)
-      output("  %3d     [ label=\"\\N:%s - %d\" fontcolor=\"red\" ]\n", 
-             node->node_num, node->system_call, node->num_here);
-    else
-      output("  %3d     [ label=\"\\N:%s\" ]\n", 
-             node->node_num, node->system_call);
-  }
-  output("  \n");
-
-  // now output the edge info
-  output("  // EDGES\n");
-  for(i=0; i<bg_num_nodes; i++) {
-    PL_HashTableEnumerateEntries( bg_nodelist[i]->edgehash, edge_enumerator, NULL);
-  }
-
-  output("}\n\n");
-}
-
-
-
-//////////////////////////////////////////////////////////////////////
-// Utilities for node hash
-//////////////////////////////////////////////////////////////////////
-
-PLHashNumber HashPtr(const void *key)
-{
-  return (((unsigned long) key)>>2) ^ 0x57954317;
-}
-
-
-PLHashNumber HashNode(const void *key)
-{
-  bg_node_t *node = (bg_node_t*) key;
-  switch( node->type ) {
-  case BG_NODE_TYPE_NAMED: 
-    return (((unsigned long) node->u.named.file)>>2) ^ 
-      //(((unsigned long) node->u.named.func)>>2) ^ 
-      (((unsigned long) node->u.named.line)>>2) ^ 
-      0x57954317;
-  case BG_NODE_TYPE_YIELD: {
-    unsigned long ret = 0x57954317;
-    void **s = node->u.yield.stack;
-    int numframes = node->u.yield.numframes;
-    
-    while(numframes > 1) {
-      ret ^= (unsigned long) *s;
-      s++;
-      numframes--;
-    }
-    
-    return ret;
-  }
-
-  case BG_NODE_TYPE_CIL:
-    return node->node_num;
-  default:
-    assert(0);
-  }
-  
-  assert(0);
-  return 0; // never reached
-}
-
-PRIntn CompareKeyNodes(const void *v1, const void *v2)
-{
-  bg_node_t *n1 = (bg_node_t*) v1;
-  bg_node_t *n2 = (bg_node_t*) v2;
-  assert(n1->type == n2->type);
-
-  switch( n1->type ) {
-  case BG_NODE_TYPE_NAMED: 
-    if( n1->u.named.line != n2->u.named.line ) return 0;
-    //if( n1->u.named.func != n2->u.named.func ) return 0;
-    if( n1->u.named.file != n2->u.named.file ) return 0;
-    return 1;
-  case BG_NODE_TYPE_YIELD: {
-    void **s1, **s2;
-    int numframes;
-    
-    // check numframes
-    if( n1->u.yield.numframes != n2->u.yield.numframes ) return 0;
-
-    for(numframes = n1->u.yield.numframes, s1 = n1->u.yield.stack, s2 = n2->u.yield.stack;
-        numframes > 1;
-        s1++, s2++, numframes--) 
-      if(*s1 != *s2) return 0;
-
-    return 1;
-  }
-  case BG_NODE_TYPE_CIL: 
-    return n1->node_num == n2->node_num;
-  default:
-    assert(0);
-  }
-
-  // never reached
-  assert(0);
-  return 0;
-}
-
-PRIntn CompareValueNodes(const void *v1, const void *v2)
-{
-  bg_node_t *n1 = (bg_node_t*) v1;
-  bg_node_t *n2 = (bg_node_t*) v2;
-
-  assert(n1->type == n2->type);
-  return n1->node_num == n2->node_num;
-}
-
-
-
-//////////////////////////////////////////////////////////////////////
-// Initialization
-//////////////////////////////////////////////////////////////////////
-
-void init_blocking_graph(void)
-{
-
-  // allocate the node hash
-  nodehash  = PL_NewHashTable(100, HashNode, CompareKeyNodes, CompareValueNodes, NULL, NULL);
-  assert(nodehash);
-
-  // add the dummy node to the list
-  cap_current_syscall = "thread_create";
-  bg_dummy_node = bg_newnode( BG_NODE_TYPE_DUMMY );
-
-  cap_current_syscall = "thread_exit";
-  bg_exit_node = bg_newnode( BG_NODE_TYPE_DUMMY );
-}
-
diff --git a/user/c3po/threads/blocking_graph.h b/user/c3po/threads/blocking_graph.h
deleted file mode 100644 (file)
index 9d07e9c..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-
-#ifndef BLOCKING_GRAPH_H
-#define BLOCKING_GRAPH_H
-
-#include "util.h"
-#include "threadlib.h"
-
-typedef enum {
-  BG_NODE_TYPE_DUMMY = 0,
-  BG_NODE_TYPE_NAMED = 1, 
-  BG_NODE_TYPE_YIELD = 2,
-  BG_NODE_TYPE_CIL   = 3,
-} bg_node_type_t;
-
-
-// nodes in the blocking graph
-// FIXME: use ifdefs to trim the size down?
-typedef struct bg_node_st {
-  int node_num;            // unique ID for this node
-  const char *system_call;       // system call from which the blocking point was reached
-  int num_here;            // number of threads currently in this node
-  latch_t latch;           // latch for this node's data
-  PLHashTable *edgehash;   // list of outgoing edges
-
-
-  // different info for different types of nodes
-  bg_node_type_t type;
-  union {
-    struct {
-      char *file;
-      char *func;
-      int line;
-    } named;
-    struct {
-      int numframes;
-      void *stack;
-    } yield;
-  } u;
-
-  // info used by the various schedulers
-  union {
-    // nothing for global_rr.
-
-    struct { // sched_graph_rr
-      pointer_list_t *runlist;
-    } g_rr;
-
-    struct { // sched_graph_priority
-      pointer_list_t *runlist;
-      long long score;
-      int listpos;
-    } g_pri;
-
-  } sched;
-
-  // aggregate stats for this node, across recently visited edges
-  thread_stats_t stats;
-
-} bg_node_t;
-
-
-// edges in the blocking graph
-typedef struct bg_edge_st {
-  bg_node_t *src;
-  bg_node_t *dest;
-  latch_t latch;
-
-  // the stats
-  thread_stats_t stats;          // cumulative stats for the edge.  These must
-                                 // be divided by count, to get the per-iteration number.
-
-} bg_edge_t;
-
-
-// vars to access the blocking graph node list.  
-// FIXME: these should be wrapped w/ accessor functions
-extern bg_node_t *bg_dummy_node;
-extern bg_node_t *bg_exit_node;
-extern int bg_num_nodes;
-extern bg_node_t **bg_nodelist;
-
-// flags to control stats gathering
-extern int bg_save_stats;
-extern int bg_stats_epoch;
-
-
-
-// stats routines - for testing
-void init_blocking_graph(void);
-void dump_blocking_graph(void);
-
-
-
-#define bg_auto_set_node() bg_named_set_node(__FILE__, __FUNCTION__, __LINE__)
-void bg_named_set_node(char *file, char *function, int line);
-
-void bg_backtrace_set_node();
-
-void bg_cil_set_node(int num);
-
-void bg_update_stats();
-
-
-static inline void bg_set_current_stats(thread_stats_t *stats) 
-{
-  char foo;
-
-  stats->stack = (long) &foo;  // we're just interested in relative values, so this is fine 
-  GET_CPU_TICKS( stats->cpu_ticks );  
-  stats->cpu_ticks -= ticks_diff;  // FIXME: subtract out time to do debug output
-#ifdef USE_PERFCTR
-  GET_REAL_CPU_TICKS( stats->real_ticks );
-  stats->real_ticks -= ticks_rdiff;  // FIXME: subtract out time to do debug output
-#endif
-  stats->epoch = bg_stats_epoch;
-  
-}
-
-
-#endif // BLOCKING_GRAPH_H
-
diff --git a/user/c3po/threads/mutex.c b/user/c3po/threads/mutex.c
deleted file mode 100644 (file)
index 068e6c1..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-
-/**
- * Simple mutexes, rwlocks and condition variables
- **/
-
-#include "threadlib_internal.h"
-#include "threadlib.h"
-
-#include "util.h"
-#include <assert.h>
-#include <error.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#ifndef DEBUG_mutex_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-static void queue_init(queue_t *q, int n);
-static void queue_free(queue_t *q) __attribute__ ((unused));
-static void enqueue(queue_t *q, void *v);
-static void *dequeue(queue_t *q);
-static int queue_isempty(queue_t *q);
-static int queue_remove(queue_t *q, void *v);
-
-inline int thread_mutex_init(mutex_t *m, char *name) 
-{
-  m->state = UNLOCKED;
-  m->name = name;
-  m->count = 0;
-  m->owner = NULL;
-  queue_init(&m->wait_queue, 0);   // This will be allocated when a thread actually waits on the mutex
-  thread_latch_init( m->latch );
-  return TRUE;
-}
-
-
-static inline int _thread_mutex_lock(mutex_t *m, int istry)
-{
-  if (m == NULL)
-    return_errno(FALSE, EINVAL);
-
-  thread_latch( m->latch );
-
-  // If unlocked, just lock it
-  if (m->state == UNLOCKED)
-    {
-      // Need to have a spin lock on the mutex if we have multiple kernel threads
-      debug("thread_mutex_lock: locking mutex directly\n");
-      m->state = LOCKED;
-      m->owner = current_thread;
-      m->count = 1;
-      thread_unlatch( m->latch );
-      return TRUE;
-    }
-    
-  assert(m->count >= 1);
-
-  // already locked by caller
-  if (m->owner == current_thread)
-    {
-      // recursive lock
-      m->count++;
-      debug("thread_mutex_lock: recursive locking\n");
-      thread_unlatch( m->latch );
-      return TRUE;
-    }
-
-  // Locked by someone else.  
-  if (istry)
-    return_errno_unlatch(FALSE, EBUSY, m->latch);
-
-  // add current thread to waiting queue
-  assert(current_thread);
-  enqueue(&m->wait_queue, current_thread);
-
-  // suspend the current thread
-  thread_unlatch( m->latch );
-  CAP_SET_SYSCALL();
-  thread_suspend_self(0);
-  CAP_CLEAR_SYSCALL();
-
-  // wake up.  Verify that we now own the lock
-  thread_latch( m->latch );
-  assert(m->state == LOCKED);
-  assert(m->owner == current_thread);
-  assert(m->count == 1);
-  thread_unlatch( m->latch );
-
-  return TRUE;
-}
-
-inline int thread_mutex_lock(mutex_t *m)
-{
-  return _thread_mutex_lock(m, FALSE);
-}
-
-inline int thread_mutex_trylock(mutex_t *m)
-{
-  return _thread_mutex_lock(m, TRUE);
-}
-
-inline int thread_mutex_unlock(mutex_t *m)
-{
-  thread_t *t;
-
-  if (m == NULL)
-    return_errno(FALSE, EINVAL);
-
-  thread_latch(m->latch);
-  if (m->state != LOCKED) 
-    return_errno_unlatch(FALSE, EDEADLK, m->latch);
-  if (m->owner != current_thread)
-    return_errno_unlatch(FALSE, EPERM, m->latch);
-
-  m->count--;
-
-  // still locked by the current thread
-  if (m->count > 0)
-    return_errno_unlatch(TRUE, 0, m->latch);
-
-  // get the first waiter
-  t = (thread_t *)dequeue(&m->wait_queue);
-
-  // no threads waiting
-  if(t == NULL) {
-    m->state = UNLOCKED;
-    m->count = 0;
-    m->owner = NULL;
-  }
-
-  // resume the waiter
-  else {
-    m->owner = t;
-    m->count = 1;
-    thread_resume(t);
-  }
-
-  thread_unlatch(m->latch);
-  return TRUE;
-}
-
-
-/*
-**  Read-Write Locks
-*/
-
-int thread_rwlock_init(rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(FALSE, EINVAL);
-    rwlock->rw_state = THREAD_RWLOCK_INITIALIZED;
-    rwlock->rw_readers = 0;
-    thread_mutex_init(&rwlock->rw_mutex_rd, NULL);
-    thread_mutex_init(&rwlock->rw_mutex_rw, NULL);
-    return TRUE;
-}
-
-static int _thread_rwlock_lock(rwlock_t *rwlock, int op, int tryonly)
-{
-    /* consistency checks */
-    if (rwlock == NULL)
-        return_errno(FALSE, EINVAL);
-    if (!(rwlock->rw_state & THREAD_RWLOCK_INITIALIZED))
-        return_errno(FALSE, EDEADLK);
-
-    /* lock lock */
-    if (op == RWLOCK_RW) {
-        /* read-write lock is simple */
-      if (!_thread_mutex_lock(&(rwlock->rw_mutex_rw), tryonly))
-       return FALSE;
-      rwlock->rw_mode = RWLOCK_RW;
-    }
-    else {
-        /* read-only lock is more complicated to get right */
-        if (!_thread_mutex_lock(&(rwlock->rw_mutex_rd), tryonly))
-            return FALSE;
-        rwlock->rw_readers++;
-        if (rwlock->rw_readers == 1) {
-            if (!_thread_mutex_lock(&(rwlock->rw_mutex_rw), tryonly)) {
-                rwlock->rw_readers--;
-                thread_mutex_unlock(&(rwlock->rw_mutex_rd));
-                return FALSE;
-            }
-        }
-        rwlock->rw_mode = RWLOCK_RD;
-        thread_mutex_unlock(&(rwlock->rw_mutex_rd));
-    }
-    return TRUE;
-}
-
-int thread_rwlock_lock(rwlock_t *l, int op)
-{
-  return _thread_rwlock_lock(l, op, FALSE);
-}
-
-int thread_rwlock_trylock(rwlock_t *l, int op)
-{
-  return _thread_rwlock_lock(l, op, TRUE);
-}
-
-int thread_rwlock_unlock(rwlock_t *rwlock)
-{
-    /* consistency checks */
-    if (rwlock == NULL)
-        return_errno(FALSE, EINVAL);
-    if (!(rwlock->rw_state & THREAD_RWLOCK_INITIALIZED))
-        return_errno(FALSE, EDEADLK);
-
-    /* unlock lock */
-    if (rwlock->rw_mode == RWLOCK_RW) {
-        /* read-write unlock is simple */
-        if (!thread_mutex_unlock(&(rwlock->rw_mutex_rw)))
-            return FALSE;
-    }
-    else {
-        /* read-only unlock is more complicated to get right */
-        if (!_thread_mutex_lock(&(rwlock->rw_mutex_rd), FALSE))
-            return FALSE;
-        rwlock->rw_readers--;
-        if (rwlock->rw_readers == 0) {
-            if (!thread_mutex_unlock(&(rwlock->rw_mutex_rw))) {
-                rwlock->rw_readers++;
-                thread_mutex_unlock(&(rwlock->rw_mutex_rd));
-                return FALSE;
-            }
-        }
-        rwlock->rw_mode = RWLOCK_RD;
-        thread_mutex_unlock(&(rwlock->rw_mutex_rd));
-    }
-    return TRUE;
-}
-
-/*
-**  Condition Variables
-*/
-
-int thread_cond_init(cond_t *cond)
-{
-    if (cond == NULL)
-        return_errno(FALSE, EINVAL);
-    cond->cn_state   = THREAD_COND_INITIALIZED;
-    cond->cn_waiters = 0;
-    queue_init(&cond->wait_queue, 0);
-    return TRUE;
-}
-
-int thread_cond_timedwait(cond_t *cond, mutex_t *mutex, const struct timespec *abstime)
-{
-  unsigned long timeout = 0;
-  int sus_rv = 0;
-    /* consistency checks */
-    if (cond == NULL || mutex == NULL)
-        return_errno(FALSE, EINVAL);
-    if (!(cond->cn_state & THREAD_COND_INITIALIZED))
-        return_errno(FALSE, EDEADLK);
-
-    /* add us to the number of waiters */
-    cond->cn_waiters++;
-
-    /* unlock mutex (caller had to lock it first) */
-    thread_mutex_unlock(mutex);
-
-    /* wait until the condition is signaled */
-    assert (current_thread);
-    enqueue(&cond->wait_queue, current_thread);
-
-    if (abstime) {
-      struct timeval tv;
-      gettimeofday(&tv, NULL);
-      timeout = (abstime->tv_sec - tv.tv_sec) * 1000000 +
-       (abstime->tv_nsec / 1000 - tv.tv_usec);
-    }
-
-    CAP_SET_SYSCALL();
-    sus_rv = thread_suspend_self(timeout);
-    CAP_CLEAR_SYSCALL();
-    
-    /* relock mutex */
-    thread_mutex_lock(mutex);
-
-       // FIXME: this is wrong, we should retry after INTERRUPTED
-    if (sus_rv == TIMEDOUT || sus_rv == INTERRUPTED) {
-      /* we timed out */
-      /* remove us from the number of waiters */
-      /* our thread could possibly be already removed by thread_cond_signal() */
-      if (queue_remove(&cond->wait_queue, current_thread))
-       cond->cn_waiters--;
-
-      return_errno(FALSE, ETIMEDOUT);
-    } else
-      return TRUE;
-}
-
-int thread_cond_wait(cond_t *cond, mutex_t *mutex)
-{
-  return thread_cond_timedwait(cond, mutex, NULL);
-}
-
-
-static int _thread_cond_signal(cond_t *cond, int broadcast)
-{
-    /* consistency checks */
-    if (cond == NULL)
-        return_errno(FALSE, EINVAL);
-    if (!(cond->cn_state & THREAD_COND_INITIALIZED))
-        return_errno(FALSE, EDEADLK);
-
-    // do something only if there is at least one waiters (POSIX semantics)
-    if (cond->cn_waiters > 0) {
-      // signal the condition
-      do {
-       thread_t *t = dequeue(&cond->wait_queue);
-       assert (t != NULL);
-       thread_resume(t);   // t could also be a timed out thread, but it doesn't matter
-       cond->cn_waiters--;
-      } while (broadcast && !queue_isempty(&cond->wait_queue));
-      
-      // and give other threads a chance to grab the CPU 
-      CAP_SET_SYSCALL();
-      thread_yield();
-      CAP_CLEAR_SYSCALL();
-    }
-
-    /* return to caller */
-    return TRUE;
-}
-
-int thread_cond_signal(cond_t *cond) {
-  return _thread_cond_signal(cond, FALSE);
-}
-
-int thread_cond_broadcast(cond_t *cond) {
-  return _thread_cond_signal(cond, TRUE);
-}
-
-// Simple queue implementation
-#define WRAP_LEN(head, tail, n) (head) <= (tail) ? ((tail) - (head)) \
-                                : ((n) + (tail) - (head))
-#define WRAP_DEC(x, n) ((x) == 0 ? (n) - 1 : (x) - 1)
-#define WRAP_INC(x, n) ((x) == ((n) - 1) ? 0 : (x) + 1)
-
-static void queue_init(queue_t *q, int n) {
-  q->size = n + 1;
-  q->data = (void **)malloc((n + 1) * sizeof(void *));
-  assert(q->data);
-  q->head = 0;
-  q->tail = 0;
-}
-
-static void queue_free(queue_t *q) {
-  free(q->data);
-}
-
-static void enqueue(queue_t *q, void *v) {
-  int cur_size = WRAP_LEN(q->head, q->tail, q->size);
-  if (cur_size == q->size - 1) {
-
-    /* Enlarge the queue */
-    int newsize;
-    if (q->size == 0)
-      newsize = 2;
-    else 
-      newsize = q->size + q->size;
-
-    q->data = realloc(q->data, newsize * sizeof(void *));
-    assert(q->data);
-    if (q->head > q->tail) {   /* do we need to move data? */
-      memmove(q->data + newsize - (q->size - q->head), q->data + q->head, (q->size - q->head)
-             * sizeof(void *));  
-      q->head = newsize - (q->size - q->head);
-      assert(*(q->data + newsize - 1) == *(q->data + q->size - 1) ); // the old last element should now be at the end of the larger block
-    }
-    q->size = newsize;
-  }
-  *(q->data + q->tail) = v;
-  q->tail = (q->tail == q->size - 1) ? 0 : q->tail + 1;
-}
-
-static void *dequeue(queue_t *q) {
-  void *r;
-
-  // the queue is empty
-  if(q->head == q->tail) 
-    return NULL;
-
-  r = *(q->data + q->head);
-  q->head = (q->head == q->size - 1) ? 0 : q->head + 1;
-  return r;
-}
-
-// remove the first occurance of a certain value from the queue
-// return TRUE if the value is found
-// FIXME: this is O(N)!
-static int queue_remove(queue_t *q, void *v) {
-  int i = q->head;
-  int rv = FALSE;
-
-  while (i != q->tail) {
-    if (q->data[i] == v) {
-      q->tail = WRAP_DEC(q->tail, q->size);
-      q->data[i] = q->data[q->tail];
-      rv = TRUE;
-      break;
-    }
-    i = WRAP_INC(i, q->size);
-  }
-
-  return rv;
-}
-
-static int queue_isempty(queue_t *q) {
-  return q->head == q->tail;
-}
-
-#undef WRAP_LEN
-
diff --git a/user/c3po/threads/pthread.c b/user/c3po/threads/pthread.c
deleted file mode 100644 (file)
index 62bfaa4..0000000
+++ /dev/null
@@ -1,1009 +0,0 @@
-
-// pthread.h must be the first file included
-#define _PTHREAD_PRIVATE
-#include <pthread.h>
-#include "threadlib.h"
-#include "threadlib_internal.h"
-#undef _PTHREAD_PRIVATE
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include "util.h"
-
-#ifndef DEBUG_pthread_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// comment out, to enable debugging in this file
-//#define debug(...)
-
-#ifdef OK
-#undef OK
-#endif
-#define OK 0
-
-// Add code to ensure initialization code here
-#define pthread_initialize()
-
-/*
-**  THREAD ATTRIBUTE ROUTINES
-*/
-
-int pthread_attr_init(pthread_attr_t *attr)
-{
-  thread_attr_t na;
-  if (attr == NULL)
-    return_errno(EINVAL, EINVAL);
-  if ((na = thread_attr_new()) == NULL)
-    return errno;
-  (*attr) = (pthread_attr_t)na;
-  return OK;
-}
-
-int pthread_attr_destroy(pthread_attr_t *attr)
-{
-  thread_attr_t na;
-  if (attr == NULL || *attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    na = (thread_attr_t)(*attr);
-    thread_attr_destroy(na);
-    *attr = NULL;
-    return OK;
-}
-
-int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
-{
-    (void) inheritsched;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched)
-{
-    if (attr == NULL || inheritsched == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param *schedparam)
-{
-    (void) schedparam;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *schedparam)
-{
-    if (attr == NULL || schedparam == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setschedpolicy(pthread_attr_t *attr, int schedpolicy)
-{
-    (void) schedpolicy;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *schedpolicy)
-{
-    if (attr == NULL || schedpolicy == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setscope(pthread_attr_t *attr, int scope)
-{
-    (void) scope;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
-{
-    if (attr == NULL || scope == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
-{
-    (void) stacksize;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    // FIXME: now doing nothing
-
-    return OK;
-}
-
-int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
-{
-    if (attr == NULL || stacksize == NULL)
-        return_errno(EINVAL, EINVAL);
-
-    // FIXME: returning a faked one
-    *stacksize = 256 * 1024;
-    return OK;
-}
-
-// FIXME: implemente this
-int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
-{
-    (void) stackaddr;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
-{
-    if (attr == NULL || stackaddr == NULL)
-        return_errno(EINVAL, EINVAL);
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
-{
-    int s;
-
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (detachstate == PTHREAD_CREATE_DETACHED)
-        s = THREAD_CREATE_DETACHED;
-    else  if (detachstate == PTHREAD_CREATE_JOINABLE)
-        s = THREAD_CREATE_JOINABLE;
-    else
-        return_errno(EINVAL, EINVAL);
-    if (!thread_attr_set((thread_attr_t)(*attr), THREAD_ATTR_JOINABLE, s))
-        return errno;
-    return OK;
-}
-
-int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
-{
-    int s;
-
-    if (attr == NULL || detachstate == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (!thread_attr_get((thread_attr_t)(*attr), THREAD_ATTR_JOINABLE, &s))
-        return errno;
-    if (s == THREAD_CREATE_JOINABLE)
-        *detachstate = PTHREAD_CREATE_JOINABLE;
-    else
-        *detachstate = PTHREAD_CREATE_DETACHED;
-    return OK;
-}
-
-int pthread_attr_setguardsize(pthread_attr_t *attr, int stacksize)
-{
-    if (attr == NULL || stacksize < 0)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_getguardsize(const pthread_attr_t *attr, int *stacksize)
-{
-    if (attr == NULL || stacksize == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_attr_setname_np(pthread_attr_t *attr, char *name)
-{
-    if (attr == NULL || name == NULL)
-        return_errno(EINVAL, EINVAL);
-    notimplemented(pthread_attr_setname_np);
-    //    if (!thread_attr_set((thread_attr_t)(*attr), THREAD_ATTR_NAME, name))
-    //        return errno;
-    return OK;
-}
-
-int pthread_attr_getname_np(const pthread_attr_t *attr, char **name)
-{
-    if (attr == NULL || name == NULL)
-        return_errno(EINVAL, EINVAL);
-    //    if (!thread_attr_get((thread_attr_t)(*attr), THREAD_ATTR_NAME, name))
-    //        return errno;
-    notimplemented(pthread_attr_getname_np);
-    *name = "FAKE_NAME";
-    return OK;
-}
-
-int pthread_attr_setprio_np(pthread_attr_t *attr, int prio)
-{
-  //    if (attr == NULL || (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX))
-  //      return_errno(EINVAL, EINVAL);
-    if (!thread_attr_set((thread_attr_t)(*attr), THREAD_ATTR_PRIO, prio))
-        return errno;
-    return OK;
-}
-
-int pthread_attr_getprio_np(const pthread_attr_t *attr, int *prio)
-{
-    if (attr == NULL || prio == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (!thread_attr_get((thread_attr_t)(*attr), THREAD_ATTR_PRIO, prio))
-        return errno;
-    return OK;
-}
-
-
-
-/*
-**  THREAD ROUTINES
-*/
-
-int pthread_create(
-    pthread_t *thread, const pthread_attr_t *attr,
-    void *(*start_routine)(void *), void *arg)
-{
-    pthread_initialize();
-    if (thread == NULL || start_routine == NULL)
-        return_errno(EINVAL, EINVAL);
-    //    if (thread_ctrl(THREAD_CTRL_GETTHREADS) >= PTHREAD_THREADS_MAX)
-    //    return_errno(EAGAIN, EAGAIN);
-    if (attr == NULL)
-        *thread = (pthread_t)thread_spawn(NULL, start_routine, arg);
-    else
-        *thread = (pthread_t)thread_spawn_with_attr(NULL, start_routine, arg, (thread_attr_t)(*attr));
-    if (*thread == NULL) {
-        errno = ENOMEM;
-        return -1;
-    }
-    return OK;
-}
-
-int __pthread_detach(pthread_t thread)
-{
-    thread_attr_t na;
-
-    if (thread == NULL)
-        return_errno(EINVAL, EINVAL);
-    if ((na = thread_attr_of((thread_t *)thread)) == NULL)
-        return errno;
-    if (!thread_attr_set(na, THREAD_ATTR_JOINABLE, FALSE))
-        return errno;
-    thread_attr_destroy(na);
-    return OK;
-}
-
-int pthread_detach(pthread_t thread)
-{
-    return __pthread_detach(thread);
-}
-
-pthread_t pthread_self(void)
-{
-    pthread_initialize();
-    return (pthread_t)thread_self();
-}
-
-int pthread_equal(pthread_t t1, pthread_t t2)
-{
-    return (t1 == t2);
-}
-
-int pthread_yield_np(void)
-{
-    pthread_initialize();
-    thread_yield();
-    return OK;
-}
-
-int pthread_yield(void)
-{
-    pthread_initialize();
-    thread_yield();
-    return OK;
-}
-
-void pthread_exit(void *value_ptr)
-{
-    pthread_initialize();
-    thread_exit(value_ptr);
-    return;
-}
-
-int pthread_join(pthread_t thread, void **value_ptr)
-{
-    pthread_initialize();
-    if (!thread_join((thread_t *)thread, value_ptr))
-        return errno;
-    //    if (value_ptr != NULL)
-    //        if (*value_ptr == THREAD_CANCELED)
-    //            *value_ptr = PTHREAD_CANCELED;
-    return OK;
-}
-
-int pthread_once(
-    pthread_once_t *once_control, void (*init_routine)(void))
-{
-    pthread_initialize();
-    if (once_control == NULL || init_routine == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*once_control != 1)
-        init_routine();
-    *once_control = 1;
-    return OK;
-}
-strong_alias(pthread_once,__pthread_once);
-
-int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
-{
-    return sigprocmask(how, set, oset);                // this is our implementation
-}
-
-int pthread_kill(pthread_t thread, int sig)
-{
-    pthread_initialize();
-       
-//    return thread_kill((thread_t*)thread, sig);
-}
-
-/*
-**  CONCURRENCY ROUTINES
-**  
-**  We just have to provide the interface, because SUSv2 says:
-**  "The pthread_setconcurrency() function allows an application to
-**  inform the threads implementation of its desired concurrency
-**  level, new_level. The actual level of concurrency provided by the
-**  implementation as a result of this function call is unspecified."
-*/
-
-static int pthread_concurrency = 0;
-
-int pthread_getconcurrency(void)
-{
-    return pthread_concurrency;
-}
-
-int pthread_setconcurrency(int new_level)
-{
-    if (new_level < 0)
-        return_errno(EINVAL, EINVAL);
-    pthread_concurrency = new_level;
-    return OK;
-}
-
-/*
-**  CONTEXT ROUTINES
-*/
-
-int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
-{
-    pthread_initialize();
-    if (!thread_key_create((thread_key_t *)key, destructor))
-        return errno;
-    return OK;
-}
-
-int pthread_key_delete(pthread_key_t key)
-{
-    if (!thread_key_delete((thread_key_t)key))
-        return errno;
-    return OK;
-}
-
-int pthread_setspecific(pthread_key_t key, const void *value)
-{
-    if (!thread_key_setdata((thread_key_t)key, value))
-        return errno;
-    return OK;
-}
-
-void *pthread_getspecific(pthread_key_t key)
-{
-    return thread_key_getdata((thread_key_t)key);
-}
-
-/*
-**  CANCEL ROUTINES
-*/
-
-int pthread_cancel(pthread_t thread)
-{
-    (void) thread;
-  //    if (!thread_cancel((thread_t)thread))
-  //      return errno;
-  notimplemented(pthread_cancel);
-    return OK;
-}
-
-void pthread_testcancel(void)
-{
-  //    thread_cancel_point();
-  notimplemented(pthread_testcancel);
-    return;
-}
-
-int pthread_setcancelstate(int state, int *oldstate)
-{
-    (void) state;
-    (void) oldstate;
-  /*
-    int s, os;
-
-    if (oldstate != NULL) {
-        thread_cancel_state(0, &os);
-        if (os & THREAD_CANCEL_ENABLE)
-            *oldstate = PTHREAD_CANCEL_ENABLE;
-        else
-            *oldstate = PTHREAD_CANCEL_DISABLE;
-    }
-    if (state != 0) {
-        thread_cancel_state(0, &s);
-        if (state == PTHREAD_CANCEL_ENABLE) {
-            s |= THREAD_CANCEL_ENABLE;
-            s &= ~(THREAD_CANCEL_DISABLE);
-        }
-        else {
-            s |= THREAD_CANCEL_DISABLE;
-            s &= ~(THREAD_CANCEL_ENABLE);
-        }
-        thread_cancel_state(s, NULL);
-    }
-  */
-  notimplemented(pthread_setcancelstate);
-    return OK;
-}
-
-int pthread_setcanceltype(int type, int *oldtype)
-{
-    (void) type;
-    (void) oldtype;
-  /*
-    int t, ot;
-
-    if (oldtype != NULL) {
-        thread_cancel_state(0, &ot);
-        if (ot & THREAD_CANCEL_DEFERRED)
-            *oldtype = PTHREAD_CANCEL_DEFERRED;
-        else
-            *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
-    }
-    if (type != 0) {
-        thread_cancel_state(0, &t);
-        if (type == PTHREAD_CANCEL_DEFERRED) {
-            t |= THREAD_CANCEL_DEFERRED;
-            t &= ~(THREAD_CANCEL_ASYNCHRONOUS);
-        }
-        else {
-            t |= THREAD_CANCEL_ASYNCHRONOUS;
-            t &= ~(THREAD_CANCEL_DEFERRED);
-        }
-        thread_cancel_state(t, NULL);
-    }
-  */
-  notimplemented(pthread_setcanceltype);
-    return OK;
-}
-
-/*
-**  SCHEDULER ROUTINES
-*/
-
-int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param)
-{
-    (void) pthread;
-    (void) policy;
-    (void) param;
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param)
-{
-    (void) pthread;
-    (void) policy;
-    (void) param;
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-/*
-**  CLEANUP ROUTINES
-*/
-
-void pthread_cleanup_push(void (*routine)(void *), void *arg)
-{
-    (void) routine;
-    (void) arg;
-    pthread_initialize();
-    //    thread_cleanup_push(routine, arg);
-    notimplemented(pthread_cleanup_push);
-    return;
-}
-
-void pthread_cleanup_pop(int execute)
-{
-    (void) execute;
-  //    thread_cleanup_pop(execute);
-  notimplemented(pthread_cleanup_pop);
-    return;
-}
-
-/*
-**  AT-FORK SUPPORT
-*/
-int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
-{
-    (void) prepare;
-    (void) parent;
-    (void) child;
-    return_errno(ENOSYS, ENOSYS);
-}
-
-/*
-**  MUTEX ATTRIBUTE ROUTINES
-*/
-
-int pthread_mutexattr_init(pthread_mutexattr_t *attr)
-{
-    pthread_initialize();
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
-{
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
-{
-    (void) prioceiling;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *attr, int *prioceiling)
-{
-    (void) prioceiling;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
-{
-    (void) protocol;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_getprotocol(pthread_mutexattr_t *attr, int *protocol)
-{
-    (void) protocol;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
-{
-    (void) type;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
-{
-    (void) type;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-/*
-**  MUTEX ROUTINES
-*/
-
-int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
-{
-    mutex_t *m;
-    (void) attr;
-
-    pthread_initialize();
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if ((m = (mutex_t *)malloc(sizeof(mutex_t))) == NULL)
-        return errno;
-    if (!thread_mutex_init(m, "pthread_mutex"))
-        return errno;
-    (*mutex) = (pthread_mutex_t)m;
-    return OK;
-}
-
-int pthread_mutex_destroy(pthread_mutex_t *mutex)
-{
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    free(*mutex);
-    *mutex = NULL;
-    return OK;
-}
-
-int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling)
-{
-    (void) prioceiling;
-    (void) old_ceiling;
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutex_getprioceiling(pthread_mutex_t *mutex, int *prioceiling)
-{
-    (void) prioceiling;
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_mutex_lock(pthread_mutex_t *mutex)
-{
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    if (!thread_mutex_lock((mutex_t *)(*mutex)))
-        return errno;
-    return OK;
-}
-
-int pthread_mutex_trylock(pthread_mutex_t *mutex)
-{
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    if (!thread_mutex_trylock((mutex_t *)(*mutex)))
-        return errno;
-    return OK;
-}
-
-int pthread_mutex_unlock(pthread_mutex_t *mutex)
-{
-    if (mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    if (!thread_mutex_unlock((mutex_t *)(*mutex)))
-        return errno;
-    return OK;
-}
-
-/*
-**  LOCK ATTRIBUTE ROUTINES
-*/
-
-int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
-{
-    pthread_initialize();
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
-{
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-/*
-**  LOCK ROUTINES
-*/
-
-int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
-{
-    rwlock_t *rw;
-    (void) attr;
-
-    pthread_initialize();
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if ((rw = (rwlock_t *)malloc(sizeof(rwlock_t))) == NULL)
-        return errno;
-    if (!thread_rwlock_init(rw))
-        return errno;
-    (*rwlock) = (pthread_rwlock_t)rw;
-    return OK;
-}
-
-int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    free(*rwlock);
-    *rwlock = NULL;
-    return OK;
-}
-
-int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
-        if (pthread_rwlock_init(rwlock, NULL) != OK)
-            return errno;
-    if (!thread_rwlock_lock((rwlock_t *)(*rwlock), RWLOCK_RD))
-        return errno;
-    return OK;
-}
-
-int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
-        if (pthread_rwlock_init(rwlock, NULL) != OK)
-            return errno;
-    if (!thread_rwlock_trylock((rwlock_t *)(*rwlock), RWLOCK_RD))
-        return errno;
-    return OK;
-}
-
-int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
-        if (pthread_rwlock_init(rwlock, NULL) != OK)
-            return errno;
-    if (!thread_rwlock_lock((rwlock_t *)(*rwlock), RWLOCK_RW))
-        return errno;
-    return OK;
-}
-
-int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
-        if (pthread_rwlock_init(rwlock, NULL) != OK)
-            return errno;
-    if (!thread_rwlock_trylock((rwlock_t *)(*rwlock), RWLOCK_RW))
-        return errno;
-    return OK;
-}
-
-int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
-{
-    if (rwlock == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
-        if (pthread_rwlock_init(rwlock, NULL) != OK)
-            return errno;
-    if (!thread_rwlock_unlock((rwlock_t *)(*rwlock)))
-        return errno;
-    return OK;
-}
-
-/*
-**  CONDITION ATTRIBUTE ROUTINES
-*/
-
-int pthread_condattr_init(pthread_condattr_t *attr)
-{
-    pthread_initialize();
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_condattr_destroy(pthread_condattr_t *attr)
-{
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* nothing to do for us */
-    return OK;
-}
-
-int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared)
-{
-    (void) pshared;
-    if (attr == NULL)
-        return_errno(EINVAL, EINVAL);
-    /* not supported */
-    return_errno(ENOSYS, ENOSYS);
-}
-
-/*
-**  CONDITION ROUTINES
-*/
-
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
-{
-    cond_t *cn;
-    (void) attr;
-
-    pthread_initialize();
-    if (cond == NULL)
-        return_errno(EINVAL, EINVAL);
-    if ((cn = (cond_t *)malloc(sizeof(cond_t))) == NULL)
-        return errno;
-    if (!thread_cond_init(cn))
-        return errno;
-    (*cond) = (pthread_cond_t)cn;
-    return OK;
-}
-
-int pthread_cond_destroy(pthread_cond_t *cond)
-{
-    if (cond == NULL)
-        return_errno(EINVAL, EINVAL);
-    free(*cond);
-    *cond = NULL;
-    return OK;
-}
-
-int pthread_cond_broadcast(pthread_cond_t *cond)
-{
-    if (cond == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*cond == PTHREAD_COND_INITIALIZER)
-        if (pthread_cond_init(cond, NULL) != OK)
-            return errno;
-    if (!thread_cond_broadcast((cond_t *)(*cond)))
-        return errno;
-    return OK;
-}
-
-int pthread_cond_signal(pthread_cond_t *cond)
-{
-    if (cond == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*cond == PTHREAD_COND_INITIALIZER)
-        if (pthread_cond_init(cond, NULL) != OK)
-            return errno;
-    if (!thread_cond_signal((cond_t *)(*cond)))
-        return errno;
-    return OK;
-}
-
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
-    if (cond == NULL || mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*cond == PTHREAD_COND_INITIALIZER)
-        if (pthread_cond_init(cond, NULL) != OK)
-            return errno;
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    if (!thread_cond_wait((cond_t *)(*cond), (mutex_t *)(*mutex)))
-        return errno;
-    return OK;
-}
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
-                           const struct timespec *abstime)
-{
-    if (cond == NULL || mutex == NULL)
-        return_errno(EINVAL, EINVAL);
-    if (*cond == PTHREAD_COND_INITIALIZER)
-        if (pthread_cond_init(cond, NULL) != OK)
-            return errno;
-    if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-        if (pthread_mutex_init(mutex, NULL) != OK)
-            return errno;
-    if (!thread_cond_timedwait((cond_t *)(*cond), (mutex_t *)(*mutex), abstime))
-      return errno;
-    return OK;
-}
-
-/*
-**  POSIX 1003.1j
-*/
-
-/*
-int pthread_abort(pthread_t thread)
-{
-    if (!thread_abort((thread_t)thread))
-        return errno;
-    return OK;
-}
-
-
-*/
-
-//////////////////////////////////////////////////
-// Set the emacs indentation offset
-// Local Variables: ***
-// c-basic-offset:4 ***
-// End: ***
-//////////////////////////////////////////////////
diff --git a/user/c3po/threads/pthreadtest.c b/user/c3po/threads/pthreadtest.c
deleted file mode 100644 (file)
index 35fd7ca..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-**  test_pthread.c: Pth test program (pthread API)
-*/
-
-#ifdef GLOBAL
-#include <pthread.h>
-#define pthread_yield_np sched_yield
-#else
-#include "pthread.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#define die(str) \
-    do { \
-        fprintf(stdout, "**die: %s: errno=%d\n", str, errno); \
-        exit(1); \
-    } while (0)
-
-static void *child(void *_arg)
-{
-    char *name = (char *)_arg;
-    int i;
-
-    fprintf(stdout, "child: startup %s\n", name);
-    for (i = 0; i < 100; i++) {
-        if (i++ % 10 == 0)
-            pthread_yield_np();
-        fprintf(stdout, "child: %s counts i=%d\n", name, i);
-    }
-    fprintf(stdout, "child: shutdown %s\n", name);
-    return _arg;
-}
-
-int main(int argc, char *argv[])
-{
-    pthread_attr_t thread_attr;
-    pthread_t thread[4];
-    char *rc;
-    (void) argc;
-    (void) argv;
-
-    fprintf(stdout, "main: init\n");
-
-    fprintf(stdout, "main: initializing attribute object\n");
-    if (pthread_attr_init(&thread_attr) != 0)
-        die("pthread_attr_init");
-    if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE) != 0)
-        die("pthread_attr_setdetachstate");
-
-    fprintf(stdout, "main: create thread 1\n");
-    if (pthread_create(&thread[0], &thread_attr, child, (void *)"foo") != 0)
-        die("pthread_create");
-    fprintf(stdout, "main: create thread 2\n");
-    if (pthread_create(&thread[1], &thread_attr, child, (void *)"bar") != 0)
-        die("pthread_create");
-    fprintf(stdout, "main: create thread 3\n");
-    if (pthread_create(&thread[2], &thread_attr, child, (void *)"baz") != 0)
-        die("pthread_create");
-    fprintf(stdout, "main: create thread 4\n");
-    if (pthread_create(&thread[3], &thread_attr, child, (void *)"quux") != 0)
-        die("pthread_create");
-
-    fprintf(stdout, "main: destroying attribute object\n");
-    if (pthread_attr_destroy(&thread_attr) != 0)
-        die("pthread_attr_destroy");
-
-    pthread_yield_np();
-
-    fprintf(stdout, "main: joining...\n");
-    if (pthread_join(thread[0], (void **)&rc) != 0)
-        die("pthread_join");
-    fprintf(stdout, "main: joined thread: %s\n", rc);
-    if (pthread_join(thread[1], (void **)&rc) != 0)
-        die("pthread_join");
-    fprintf(stdout, "main: joined thread: %s\n", rc);
-    if (pthread_join(thread[2], (void **)&rc) != 0)
-        die("pthread_join");
-    fprintf(stdout, "main: joined thread: %s\n", rc);
-    if (pthread_join(thread[3], (void **)&rc) != 0)
-        die("pthread_join");
-    fprintf(stdout, "main: joined thread: %s\n", rc);
-
-    fprintf(stdout, "main: exit\n");
-    return 0;
-}
-
diff --git a/user/c3po/threads/readproc.c b/user/c3po/threads/readproc.c
deleted file mode 100644 (file)
index 5bf7d6c..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ros/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include "util.h"
-#include "readproc.h"
-
-
-
-
-/**
- * read data from a file in /proc, caching the FD if that seems to work.
- **/
-int read_proc_file(int *fdp, char *name, char *buf, int len)
-{
-  register int ret;
-  register int fd = *fdp;
-
-  // open the proc file
-  if( fd < 0 ) {
-    fd = syscall(SYS_open,name,O_RDONLY); 
-    if(fd < 0) {
-      warning("error opening %s: %s\n",name,strerror(errno));
-      *fdp = -2;
-      return -1;
-    }
-    *fdp = fd;
-  }
-
-  // read
-  // FIXME: pread should be better, but it always returns 0 bytes on my home system.  Why?
-#define USE_PREAD 0
-#if USE_PREAD
-  ret = syscall(SYS_pread, fd, buf, len, 0);
-#else
-  /*  if( syscall(SYS_lseek, fd, 0, SEEK_SET) < 0 ) {
-    warning("error w/ lseek: %s\n", strerror(errno));
-    close(fd);
-    *fdp = -2; 
-    return -1;
-    }  */
-  ret = syscall(SYS_read, fd, buf, len);
-  // FIXME: fd caching seems to flake out someitmes - why??
-  syscall(SYS_close, fd);
-  *fdp = -1;
-#endif
-
-  if( ret < 50 ) {
-    warning("too little data in %s (%d bytes)\n",name,ret);
-    if( fd >= 0 ) syscall(SYS_close, fd);
-    *fdp = -1;
-    return -1;
-  }
-
-  return ret;
-}
-
-
-/**
- * Read stats from /proc/self/stat.
- *
- * FIXME: the FD caching may not work correctly for cloned children -
- * check on this later.
- **/
-void refresh_process_stats(proc_self_stat_t *stat)
-{
-  static int fd = -1;
-  char buf[256];
-  int ret;
-  //int len;
-
-  ret = read_proc_file(&fd, "/proc/self/stat", buf, sizeof(buf));
-  if( ret < 0 ) return;
-  if( ret == sizeof(buf) ) {
-    warning("too much data in /proc/self/stat - can't get valid stats\n"); 
-    if( fd >= 0) close(fd);
-    fd = -2;
-    return;
-  }
-  
-  // parse.  We could do this faster ourselves, by not keeping all of
-  // this data.  The speed shouldn't really matter, though, since this
-  // routine should only be called a few times / second.
-  ret = sscanf(buf, "%d (%[^)]) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu",
-
-               &stat->pid, 
-               &stat->comm[0],
-               &stat->state,
-               &stat->ppid,
-               &stat->pgrp,
-               &stat->session,
-               &stat->tty_nr,
-               &stat->tty_pgrp,
-
-               &stat->flags,
-               &stat->min_flt,
-               &stat->cmin_flt,
-               &stat->maj_flt,
-               &stat->cmaj_flt,
-               &stat->tms_utime,
-               &stat->tms_stime,
-               &stat->tms_cutime,
-               &stat->tms_cstime,
-
-               &stat->priority,
-               &stat->nice,
-               &stat->removed, 
-               &stat->it_real_value,
-               &stat->start_time, // just unsigned long in 2.4
-  
-               &stat->vsize,
-               &stat->rss,
-               &stat->rss_rlim_cur,
-               &stat->start_code,
-               &stat->end_code,
-               &stat->start_stack,
-               &stat->esp,
-               &stat->eip,
-
-               &stat->pending_sig, // obsolete - use /proc/self/status
-               &stat->blocked_sig, // obsolete - use /proc/self/status
-               &stat->sigign,      // obsolete - use /proc/self/status
-               &stat->sigcatch,    // obsolete - use /proc/self/status
-               &stat->wchan,
-
-               &stat->nswap,
-               &stat->cnswap,
-               &stat->exit_signal,
-               &stat->cpu_num,
-               &stat->rt_priority, // new in 2.5
-               &stat->policy      // new in 2.5
-               );
-
-  warning("stats: %d (%s)... %ld %ld   %ld  ret=%d\n", 
-          stat->pid, 
-          stat->comm,
-          stat->vsize,
-          stat->rss,
-          stat->maj_flt,
-          ret);
-  
-  if( ret != 39 && ret != 41 ) {
-    warning("error parsing /proc/self/stat - got %d items\n", ret);
-    //bzero(stat, sizeof(proc_self_stat_t));
-    if( fd >= 0) close(fd);
-    fd = -1;
-    return;
-  }
-}
-
-
-
-
-void refresh_global_stats(proc_global_stats_t *stat)
-{
-  static int proc_stat_fd = -1;
-  char buf[1024], *p, *end;
-  int ret;
-
-  ret = read_proc_file(&proc_stat_fd, "/proc/stat", buf, sizeof(buf)-1);
-  if( ret < 0 ) return;
-  buf[ret] = '\0';
-
-
-  // FIXME: parse CPU info (?)
-
-  // parse pageing activity
-  p = strstr(buf,"page ");
-  if( p == NULL ) {warning("couldn't find page data in /proc/stat!\n"); return;}
-
-  p += 5; // strlen("page ");
-  stat->pages_in = strtol(p, &end, 0);
-  if( p == end ) {warning("bad pagein data\n"); return;}
-  
-  p = end;
-  stat->pages_out = strtol(p, &end, 0);
-  if( p == end ) {warning("bad pagein data\n"); return;}
-
-  
-  // parse swap file activity
-  p = strstr(buf,"swap ");
-  if( p == NULL ) {warning("couldn't find swap data in /proc/stat!\n"); return;}
-
-  p += 5; // strlen("swap ");
-  stat->pages_swapin = strtol(p, &end, 0);
-  if( p == end ) {warning("bad pswapin data\n"); return;}
-  
-  p = end;
-  stat->pages_swapout = strtol(p, &end, 0);
-  if( p == end ) {warning("bad pswapout data\n"); return;}
-
-
-  warning("gstats:   %d %d   %d %d\n",
-          stat->pages_in, stat->pages_out,
-          stat->pages_swapin, stat->pages_swapout);
-}
-
-
-#ifdef READPROC_DEFINE_MAIN
-
-
-void printstats(proc_self_stat_t *stat)
-{
-  printf("%s:  vsize=%lu  rss=%ld  min_flt=%lu  maj_flt=%lu\n", 
-         stat->comm, stat->vsize/1024/1024, stat->rss*4/1024,
-         stat->min_flt, stat->maj_flt);
-}
-
-
-int main(int argc, char **argv)
-{
-  proc_self_stat_t selfstats;
-  (void) argc; (void) argv;
-
-  refresh_process_stats(&selfstats); printstats(&selfstats);
-
-  malloc(1024*1024);
-  refresh_process_stats(&selfstats);
-  printstats(&selfstats);
-
-  {
-    char *p = malloc(1024*1024);
-    int i;
-
-    refresh_process_stats(&selfstats); printstats(&selfstats);
-    for( i=0; i<1024; i++ )
-      p[i*1024] = 4;
-    refresh_process_stats(&selfstats); printstats(&selfstats);
-  }
-
-  malloc(1024*1024);
-  refresh_process_stats(&selfstats); printstats(&selfstats);
-
-}
-
-
-#endif
diff --git a/user/c3po/threads/readproc.h b/user/c3po/threads/readproc.h
deleted file mode 100644 (file)
index f94a83a..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-\
-#ifndef READPROC_H
-#define READPROC_H
-
-typedef struct {
-  int pid;
-  char comm[256]; // FIXME: a really long command name would mess things up
-  char state;
-  int ppid;
-  int pgrp;
-  int session;
-  int tty_nr;
-  int tty_pgrp;
-
-  unsigned long flags;
-  unsigned long min_flt;
-  unsigned long cmin_flt;
-  unsigned long maj_flt;
-  unsigned long cmaj_flt;
-  unsigned long tms_utime;
-  unsigned long tms_stime;
-  long tms_cutime;
-  long tms_cstime;
-
-  long priority;
-  long nice;
-  long removed; 
-  long it_real_value;
-  unsigned long long start_time; // just unsigned long in 2.4
-  
-  unsigned long vsize;
-  long rss;
-  unsigned long rss_rlim_cur;
-  unsigned long start_code;
-  unsigned long end_code;
-  unsigned long start_stack;
-  unsigned long esp;
-  unsigned long eip;
-
-  unsigned long pending_sig; // obsolete - use /proc/self/status
-  unsigned long blocked_sig; // obsolete - use /proc/self/status
-  unsigned long sigign;      // obsolete - use /proc/self/status
-  unsigned long sigcatch;    // obsolete - use /proc/self/status
-  unsigned long wchan;
-
-  unsigned long nswap;
-  unsigned long cnswap;
-  int exit_signal;
-  int cpu_num;
-
-  unsigned long rt_priority; // new in 2.5
-  unsigned long policy;      // new in 2.5
-
-} proc_self_stat_t;
-
-
-typedef struct {
-  int pages_in;
-  int pages_out;
-  int pages_swapin;
-  int pages_swapout;
-} proc_global_stats_t;
-
-void refresh_process_stats(proc_self_stat_t *stat);
-void refresh_global_stats(proc_global_stats_t *stat);
-
-#endif // READPROC_H
diff --git a/user/c3po/threads/resource_stats.c b/user/c3po/threads/resource_stats.c
deleted file mode 100644 (file)
index 7ecb983..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-
-
-#include "threadlib_internal.h"
-#include "readproc.h"
-
-#include <math.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/resource.h>
-#include <ros/syscall.h>
-
-#ifndef DEBUG_resource_stats_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// statistics
-int total_sockets_in_use = 0;
-int total_socket_opens = 0;
-int total_socket_closes = 0;
-long long total_socket_lifetime = 0;
-
-int total_files_in_use = 0;
-int total_file_opens = 0;
-int total_file_closes = 0;
-long long total_file_lifetime = 0;
-
-long long total_heap_in_use = 0;
-long long total_stack_in_use = 0;
-
-cpu_tick_t total_edge_cycles = 0;
-int total_edges_taken = 0;
-static cpu_tick_t prev_edge_cycles = 0;
-static int prev_edges_taken = 0;
-
-
-#define IOSTAT_INITIALIZER {0,0,0,0,0,0}
-
-iostats_t sockio_stats      = IOSTAT_INITIALIZER;
-iostats_t diskio_stats      = IOSTAT_INITIALIZER;
-
-
-
-long long max_memory;
-int max_fds;
-proc_self_stat_t proc_stats, prev_proc_stats;
-proc_global_stats_t global_stats, prev_global_stats;
-
-
-typeof(__free_hook) orig_free_hook;
-typeof(__malloc_hook) orig_malloc_hook;
-typeof(__realloc_hook) orig_realloc_hook;
-
-
-static void *capriccio_malloc_hook(size_t size, const void *callsite)
-{
-  void *ret;
-  (void) callsite;
-  
-  // FIXME: race
-  __malloc_hook = orig_malloc_hook;
-  ret = malloc(size);
-  __malloc_hook = (typeof(__malloc_hook))capriccio_malloc_hook;
-
-  if( !ret ) return NULL;
-
-  thread_stats_add_heap( malloc_usable_size(ret) );
-  
-  return ret;
-}
-
-
-static void capriccio_free_hook(void *ptr, const void *callsite)
-{
-  (void) callsite;
-  if( !ptr ) return;
-
-  // FIXME: subtracts for cases in which free() fails.  ;-/ It also
-  // behaves incorrectly if things are freed that were malloc-ed
-  // before this lib is initialized (because of bad ordering of
-  // initializers, say.)  
-  //
-  // We'll need our own (thread-safe) memory allocator anyway when we
-  // go to multiple CPUs, so just ignore this for now.
-  thread_stats_add_heap( 0 - malloc_usable_size(ptr) );
-
-  // FIXME: race
-  __free_hook = orig_free_hook;
-  free(ptr);
-  __free_hook = capriccio_free_hook;
-}
-
-
-static void* capriccio_realloc_hook(void *ptr, size_t size, const void *callsite)
-{
-  (void) callsite;
-  if( ptr )
-    thread_stats_add_heap( 0 - malloc_usable_size(ptr) );
-
-  // FIXME: race
-  __realloc_hook = orig_realloc_hook;
-  ptr = realloc(ptr,size);
-  __realloc_hook = capriccio_realloc_hook;
-
-  if( !ptr ) return NULL;
-
-  thread_stats_add_heap( malloc_usable_size(ptr) );
-  
-  return ptr;
-}
-
-
-
-
-
-inline void thread_stats_add_heap(long size) 
-{
-  if( current_thread )
-    current_thread->curr_stats.heap += size;
-
-  total_heap_in_use += size;
-  
-  // FIXME: bugs in accounting make this not always true!!
-  //assert( total_heap_in_use >= 0 );
-  if( total_heap_in_use < 0 )
-    total_heap_in_use = 0;
-}
-
-
-/**
- * Update some global stats about system performance.  
- **/
-
-// FIXME: temporarily make these global, for debugging & testing
-int socket_overload = 0; 
-int vm_overload = 0;
-
-
-// FIXME: MAJOR KLUDGE - make these public, so we can print them out from knot
-double open_rate;
-double close_rate;
-double avg_socket_lifetime;
-
-static void check_socket_overload( cpu_tick_t now )
-{
-  static cpu_tick_t then = 0;
-  static int prev_socket_opens = 0;
-  static int prev_socket_closes = 0;
-  static cpu_tick_t prev_socket_lifetime=0;
-
-  // calcualte rates
-  open_rate = (double) (total_socket_opens - prev_socket_opens) * ticks_per_second / (now - then);
-  close_rate = (double) (total_socket_closes - prev_socket_closes) * ticks_per_second / (now - then);
-  avg_socket_lifetime = (total_socket_closes <= prev_socket_closes) ? 0 : 
-    (double)(total_socket_lifetime - prev_socket_lifetime) / 
-    (total_socket_closes - prev_socket_closes) / 
-    ticks_per_millisecond; 
-
-  // FIXME: this stuff doesn't seem to work well at present!
-  //
-  // we are overloaded if the incoming queue is increasing too fast
-  //if( open_rate > 1500  &&  open_rate > 1.05 * close_rate )
-  if( avg_socket_lifetime > 300 )
-    socket_overload = 1;
-  else 
-    socket_overload = 0;
-
-
-  // update history  
-  then = now;
-  prev_socket_opens = total_socket_opens;
-  prev_socket_closes = total_socket_closes;
-  prev_socket_lifetime = total_socket_lifetime;
-}
-
-
-static void check_vm_overload( cpu_tick_t now )
-{
-  static cpu_tick_t then = 0;
-
-  if( then == 0 ) {
-    then = now;
-    return;
-  }
-
-  // rotate the stats
-  if( 0 ) {
-    prev_proc_stats = proc_stats;
-    refresh_process_stats( &proc_stats );
-  }
-
-  prev_global_stats = global_stats;
-  refresh_global_stats( &global_stats );
-
-  // no more than 1 every 50 ms
-  // FIXME: tune this, based on disk activity?
-  //if(  (proc_stats.maj_flt - prev_proc_stats.maj_flt) > (now-then)/ticks_per_millisecond/50 ) 
-  //if( proc_stats.maj_flt > prev_proc_stats.maj_flt )
-  if( global_stats.pages_swapout > prev_global_stats.pages_swapout ||
-      global_stats.pages_swapin > prev_global_stats.pages_swapin )
-    vm_overload = 1;
-  else 
-    vm_overload = 0;
-
-}
-
-
-void check_overload( cpu_tick_t now )
-{
-  check_vm_overload( now );
-  check_socket_overload( now );
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// keep histograms of timing info
-//////////////////////////////////////////////////////////////////////
-
-#define HISTOGRAM_BUCKETS 60
-
-typedef struct {
-  int buckets[ HISTOGRAM_BUCKETS ];
-  int num;
-  double sum;
-  int overflow;
-  double overflow_sum;
-} histogram_t;
-
-histogram_t file_lifetime_hist;
-histogram_t socket_lifetime_hist;
-
-
-static inline void update_lifetime_histogram( histogram_t *hist, cpu_tick_t lifetime )
-{
-  register long millis = (long) (lifetime / ticks_per_millisecond);
-  register int idx = 0;
-
-  // the buckets get increasingly broader as we go up in time
-  while( millis > 10 )
-    idx += 10, millis /= 10;
-
-  if( idx + millis < HISTOGRAM_BUCKETS )
-    hist->buckets[ idx + millis ]++;
-  else 
-    hist->overflow++, hist->overflow_sum++;
-
-  hist->num++;
-  hist->sum += millis;
-}
-
-static void histogram_stats( histogram_t *hist, double *mean, double *dev )
-{
-  int i, j, multiplier;
-  double sum, m;
-
-  if(hist->num == 0)
-    *mean = *dev = 0;
-  
-  *mean = m = hist->sum / hist->num;
-
-  sum = (0.5 - m) * (0.5 - m) * hist->buckets[0];
-  multiplier = 1;
-  for(i=0; i<HISTOGRAM_BUCKETS/10; i++) {
-    for(j=1; j<10; j++) {
-      sum += hist->buckets[10*i + j] * ((0.5 + j) * multiplier - m) * ((0.5 + j) * multiplier - m);
-    }
-    multiplier *= 10;
-  }
-  sum += (hist->overflow_sum/hist->overflow - m) * (hist->overflow_sum/hist->overflow - m);
-
-  *dev = sqrt( sum / hist->num );
-}
-
-
-
-
-
-void thread_stats_open_socket() 
-{
-  if( current_thread )
-    current_thread->curr_stats.sockets++;
-  total_sockets_in_use++;
-  total_socket_opens++;
-}
-
-void thread_stats_close_socket(cpu_tick_t lifetime) 
-{
-  if( current_thread )
-    current_thread->curr_stats.sockets--;
-  total_sockets_in_use--;
-  total_socket_closes++;
-  total_socket_lifetime += lifetime;
-
-  update_lifetime_histogram( &socket_lifetime_hist, lifetime );
-}
-
-
-void thread_stats_open_file() 
-{
-  if( current_thread )
-    current_thread->curr_stats.files++;
-  total_files_in_use++;
-  total_file_opens++;
-}
-
-void thread_stats_close_file(cpu_tick_t lifetime) 
-{
-  if( current_thread )
-    current_thread->curr_stats.files--;
-  total_files_in_use--;
-  total_file_lifetime += lifetime;
-  total_file_closes++;
-
-  update_lifetime_histogram( &file_lifetime_hist, lifetime );
-}
-
-
-/**
- * Check to see if running this thread would violate the current
- * admission control policy.
- *
- * Return value: 1 to admit, 0 to reject.
- *
- * FIXME: this should really return a preference value, for how "good"
- * this node is, based on current resource usage.  
- **/
-int check_admission_control(bg_node_t *node)
-{
-  // FIXME: so far, just assume memory preassure comes from the heap
-  if( vm_overload  &&  node->stats.heap > 0 ) {
-    debug("rejecting node '%d' for vm usage\n",node->node_num);
-    return 0;
-  }
-
-  if( socket_overload  &&  node->stats.sockets > 0 ) {
-    debug("rejecting node '%d' for socket usage\n",node->node_num);
-    return 0;
-  }  
-  
-  return 1;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// output function
-//////////////////////////////////////////////////////////////////////
-
-// FIXME: it is probably faster to 
-
-void print_resource_stats(void)
-{
-  static double then = 0;
-  static iostats_t prev_sockio_stats, prev_diskio_stats;
-  double now = current_usecs();
-  double elapsed = (now - then) / 1e6;
-
-  output("resources:  %d file    %d sock      %lld KB heap     %lld KB stack\n", 
-         total_files_in_use, total_sockets_in_use, (total_heap_in_use / 1024), (total_stack_in_use / 1024));
-  output("limits:     %d max fds (%.0f%% used)     %lld KB max memory (%.0f%% used)\n", 
-         max_fds, (float)100*(total_files_in_use+total_sockets_in_use) / max_fds,
-         max_memory/1024, (float)100*(total_heap_in_use + total_stack_in_use) / max_memory);
-
-  // show edge timings
-  if( prev_edges_taken != total_edges_taken ) {
-    output("timings:  %d edges    %lld ticks avg.  (%lld usec)\n",
-           total_edges_taken - prev_edges_taken, 
-           (total_edge_cycles - prev_edge_cycles) / (total_edges_taken - prev_edges_taken), 
-           (total_edge_cycles - prev_edge_cycles) / (total_edges_taken - prev_edges_taken) / ticks_per_microsecond);
-    prev_edge_cycles = total_edge_cycles;
-    prev_edges_taken = total_edges_taken;
-  } else {
-    output("timings:  0 edges    0 ticks avg.  (0 usec)\n");
-  }
-
-
-  // show throughput
-  if( then > 0 ) {
-    double mean, dev;
-
-    output("sockios per sec:   %.0f req   %.0f comp   %.1f Mb read   %.1f Mb written  %.0f err\n",
-           (sockio_stats.requests - prev_sockio_stats.requests) / elapsed,
-           (sockio_stats.completions - prev_sockio_stats.completions) / elapsed,
-           8*(sockio_stats.bytes_read - prev_sockio_stats.bytes_read) / elapsed / (1024*1024),
-           8*(sockio_stats.bytes_written - prev_sockio_stats.bytes_written) / elapsed / (1024*1024),
-           (sockio_stats.errors - prev_sockio_stats.errors) / elapsed);
-
-    output("diskios per sec:   %.0f req   %.0f comp   %.1f MB read   %.1f MB written  %.0f err\n",
-           (diskio_stats.requests - prev_diskio_stats.requests) / elapsed,
-           (diskio_stats.completions - prev_diskio_stats.completions) / elapsed,
-           (diskio_stats.bytes_read - prev_diskio_stats.bytes_read) / elapsed / (1024*1024),
-           (diskio_stats.bytes_written - prev_diskio_stats.bytes_written) / elapsed / (1024*1024),
-           (diskio_stats.errors - prev_diskio_stats.errors) / elapsed);
-
-    histogram_stats( &socket_lifetime_hist, &mean, &dev );
-    output("socket lifetime:   %.1f ms avg   %.1f stddev\n", mean, dev);
-
-    histogram_stats( &file_lifetime_hist, &mean, &dev );
-    output("file lifetime:     %.1f ms avg   %.1f stddev\n", mean, dev);
-  }
-
-  then = now;
-  prev_sockio_stats = sockio_stats;
-  prev_diskio_stats = diskio_stats;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// initialization
-//////////////////////////////////////////////////////////////////////
-
-//static void resource_stats_init() __attribute__((constructor));
-static void resource_stats_init()
-{
-  // clear out IO histograms
-  bzero( &socket_lifetime_hist, sizeof(socket_lifetime_hist) );
-  bzero( &file_lifetime_hist, sizeof(file_lifetime_hist) );
-
-
-  // install malloc hooks
-  orig_free_hook = __free_hook;
-  orig_malloc_hook = __malloc_hook;
-  orig_realloc_hook = __realloc_hook;
-  __free_hook = capriccio_free_hook;
-  __malloc_hook = capriccio_malloc_hook;
-  __realloc_hook = capriccio_realloc_hook;
-
-
-  // heap
-
-  // this just returns the size of virtual memory - not very useful.  ;-(
-  {
-    struct rlimit r;
-    int ret;
-    ret = getrlimit(RLIMIT_RSS, &r);       assert( ret == 0 );
-    max_memory = r.rlim_cur;
-    r.rlim_cur = r.rlim_max;
-    if( setrlimit(RLIMIT_RSS, &r) == 0 )
-      max_memory = r.rlim_cur;
-  }
-
-  // read memory info from /proc/meminfo.  
-  // PORT: for similar things for non-Linux platforms, look at meminfo (http://meminfo.seva.net/)
-  {
-    char buf[1024];
-    int fd, ret;
-    char *p;
-
-    fd = syscall(SYS_open, "/proc/meminfo", O_RDONLY);    assert( fd >= 0);
-    ret = syscall(SYS_read, fd, buf, sizeof(buf)-1);      assert( ret > 0);
-    buf[ret] = '\0';
-    
-    p = strstr(buf,"MemTotal:");   assert( p );
-    p += strlen("MemTotal:");
-    while( *p == ' ' ) p++;
-    
-    max_memory = atoi( p ) * 1024;
-  }
-
-
-  // fds
-  {
-    struct rlimit r;
-    int ret;
-    ret = getrlimit(RLIMIT_NOFILE, &r);       assert( ret == 0 );
-    max_fds = r.rlim_cur;
-    r.rlim_cur = r.rlim_max;
-    if( setrlimit(RLIMIT_NOFILE, &r) == 0 )
-      max_fds = r.rlim_cur;
-  }
-
-  // baseline process stats
-  refresh_process_stats(&proc_stats);
-  prev_proc_stats = proc_stats;
-}
-
-
diff --git a/user/c3po/threads/resource_stats.h b/user/c3po/threads/resource_stats.h
deleted file mode 100644 (file)
index 7b5c6c7..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-#ifndef RESOURCE_STATS_H
-#define RESOURCE_STATS_H
-
-#include "clock.h"
-
-struct bg_node_st;
-// track the thread's resource
-typedef struct thread_resources_st {
-  int epoch;                // for validating versions when taking diffs
-  struct bg_node_st *node;  // the most recently seen graph node
-
-  unsigned int count;       // number of times the edge has been seen
-
-  long stack;               // total stack space
-  int files;                // number of files
-  int sockets;              // number of sockets
-  cpu_tick_t cpu_ticks;      // cpu time
-  cpu_tick_t real_ticks;     // real time, including time swapped out - only used if USE_PERFCTR is defined
-  long heap;                // bytes of heap used by the thread 
-  //int mutexes;              // locks held
-
-  // FIXME: performance counter stuff.
-  // icache misses
-  // dcache misses
-
-} thread_stats_t;
-
-
-extern void thread_stats_open_socket();
-extern void thread_stats_close_socket(cpu_tick_t lifetime);
-extern void thread_stats_open_file();
-extern void thread_stats_close_file(cpu_tick_t lifetime);
-
-extern int check_admission_control(struct bg_node_st *node);
-
-
-#define OVERLOAD_CHECK_INTERVAL (200*ticks_per_millisecond)
-extern void check_overload( cpu_tick_t now );
-
-
-/**
- * track global edge timings
- **/
-extern cpu_tick_t total_edge_cycles;
-extern int total_edges_taken;
-static inline void update_edge_totals(cpu_tick_t ticks)
-{
-  total_edge_cycles += ticks;
-  total_edges_taken++;
-}
-
-void print_resource_stats(void);
-
-
-
-#endif
diff --git a/user/c3po/threads/sched_global_rr.c b/user/c3po/threads/sched_global_rr.c
deleted file mode 100644 (file)
index 761e2df..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- *
- *  Basic Round Robin scheduling with single global queue
- *
- **/
-
-#include "threadlib_internal.h"
-#include "util.h"
-#include <stdio.h>
-
-#ifndef DEBUG_sched_global_rr_c
-#undef debug
-#define debug(...)
-//#undef tdebug
-//#define tdebug(...)
-#endif
-
-
-static pointer_list_t *runlist = NULL;
-
-
-//////////////////////////////////////////////////////////////////////
-// generic stuff
-//////////////////////////////////////////////////////////////////////
-
-
-void sched_global_generic_init(void)
-{
-  runlist = new_pointer_list("sched_global_rr_runlist");
-}
-
-thread_t* sched_global_generic_next_thread(void) 
-{
-  thread_t *next = pl_remove_head(runlist);
-  if( next == (thread_t*) -1 ) 
-    return NULL;
-  else 
-    return next;
-}
-
-
-
-//////////////////////////////////////////////////////////////////////
-// Round robin scheduler
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_global_generic_init, sched_global_rr_init );
-strong_alias( sched_global_generic_next_thread, sched_global_rr_next_thread );
-
-void sched_global_rr_add_thread(thread_t *t)
-{
-  pl_add_tail(runlist, t);
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// LIFO scheduler
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_global_generic_init, sched_global_lifo_init );
-strong_alias( sched_global_generic_next_thread, sched_global_lifo_next_thread );
-
-void sched_global_lifo_add_thread(thread_t *t)
-{
-  pl_add_head(runlist, t);
-}
-
diff --git a/user/c3po/threads/sched_graph_priority.c b/user/c3po/threads/sched_graph_priority.c
deleted file mode 100644 (file)
index 723839b..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/**
- *
- *  Basic scheduler with different queues for each graph node
- *
- **/
-#include "threadlib_internal.h"
-#include "util.h"
-
-#ifndef DEBUG_graph_priority_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-// number of threads we'll run before checking priorities again
-static int threads_in_epoch;
-
-// flag, regarding whether or not we should include admission control
-int do_admission_control = 0;
-
-
-// sorted array of nodes.
-// FIXME: either auto-size this, or use w/ static node list from cil
-#define GP_NODELIST_SIZE 1024
-bg_node_t *gp_nodelist[ GP_NODELIST_SIZE ];
-int gp_nodelist_num = 1;
-
-// our current position in the node list
-static int gp_nodelist_pos = 1;
-
-
-void show_node_priorities() __attribute__((unused));
-
-
-//////////////////////////////////////////////////////////////////////
-// internal functions, to recalculate priorities, etc.
-//////////////////////////////////////////////////////////////////////
-
-
-static PRIntn edge_enumerator(PLHashEntry *e, PRIntn i, void *arg)
-{
-  bg_edge_t *edge = (bg_edge_t*) e->value;
-  thread_stats_t *stats = (thread_stats_t*) arg;
-  (void) i;
-
-  thread_latch( edge->latch );
-
-  stats->count += edge->stats.count;
-  stats->cpu_ticks += edge->stats.cpu_ticks;
-  stats->stack += edge->stats.stack;
-  stats->files += edge->stats.files;
-  stats->sockets += edge->stats.sockets;
-  stats->heap += edge->stats.heap;
-  //stats->mutexes += edge->stats.mutexes;
-
-  // FIXME: is this the right place for this?  Perhaps use exponential history instead
-  bzero(&edge->stats, sizeof(edge->stats));
-
-  thread_unlatch( edge->latch );
-
-  return 0;
-}
-
-
-static void calculate_node_score(bg_node_t *node)
-{
-  thread_stats_t stats;
-
-  // zero out the summary info
-  bzero(&stats, sizeof(thread_stats_t));
-
-  thread_latch( node->latch );
-
-  // collect totals from all edges
-  PL_HashTableEnumerateEntries( node->edgehash, edge_enumerator, &stats);
-
-  // just return, if no edges were taken
-  // FIXME: keep a count in the node, so we don't have to visit edges in order to find this out
-  if(stats.count <= 0) {
-    // allow the previous score to decay
-    node->sched.g_pri.score = ( node->sched.g_pri.score >> 2 );
-    thread_unlatch( node->latch );
-    return;
-  }
-
-  // divide to get per-iteration numbers
-  stats.stack /= stats.count;
-  stats.heap /= stats.count;
-  stats.cpu_ticks /= stats.count;
-  stats.files /= stats.count;
-  stats.sockets /= stats.count;
-
-  // do the weighting
-  // 
-  // FIXME: this should depend in part on which resources are scarce.
-  // For example, things that allocate memory or stack should be more
-  // heavily penalized when memory is tight.
-
-  //node->sched.g_pri.score = stats.stack * 4 + stats.cpu_ticks /100 + stats.fds * 100;
-  node->sched.g_pri.score = (stats.stack + stats.heap) + stats.files * 10000 + stats.sockets+1000;
-
-  thread_unlatch( node->latch );
-
-#ifdef DEBUG_sched_graph_priority_c
-  show_node_priorities();
-#endif
-
-  //debug("--- node %d:   %d  (%ld s, %lld T, %d fd)\n",
-  //      node->node_num, node->sched.graph_priority.score, stats.stack, stats.cpu_ticks, stats.count);
-
-}
-
-
-
-// adjust priorities for all nodes
-static void adjust_priorities(void)
-{
-  int i;
-
-  for( i=1; i<gp_nodelist_num; i++ ) {
-    calculate_node_score( gp_nodelist[i] );
-  }
-
-}
-
-
-// sort the node list, based on priority.  We use a bublesort, which
-// should be reasonable as long as the order doesn't change too often.
-static void sort_nodelist(void)
-{
-  int i,j;
-  bg_node_t *node;
-
-  // walk the list, and find things that are out of order
-  for( i=1; i<gp_nodelist_num-1; i++ ) {
-    // bubble up if out of order
-    if( gp_nodelist[i+1]->sched.g_pri.score < gp_nodelist[i]->sched.g_pri.score ) {
-      node = gp_nodelist[i+1];
-
-      j = i;
-      do {
-        gp_nodelist[j+1] = gp_nodelist[j];
-        gp_nodelist[j+1]->sched.g_pri.listpos = j+1;
-        
-        j--;
-      } while( j > 0  &&  node->sched.g_pri.score < gp_nodelist[j]->sched.g_pri.score );
-
-      gp_nodelist[j+1] = node;
-      gp_nodelist[j+1]->sched.g_pri.listpos = j+1;
-    }
-  }
-  
-
-  // sanity check
-#if 0
-  assert( !gp_nodelist[0] );
-  assert( !gp_nodelist[ gp_nodelist_num ] );
-  for( i=1; i<gp_nodelist_num-1; i++ ) {
-    assert(gp_nodelist[i]->node_num != gp_nodelist[i+1]->node_num);
-    assert(gp_nodelist[i]->sched.g_pri.score <= gp_nodelist[i+1]->sched.g_pri.score);
-  }
-#endif
-
-}
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// externally-visible functions
-//////////////////////////////////////////////////////////////////////
-
-
-// The algorithm for picking the next thread is as follows:  
-//   - find a thread that is likely to generally release resources by walking the list of nodes
-//   - skip nodes that allocate something that is too close to maxed out.
-
-// FIXME: current algorithm will lead to starvation if the highest
-// priority stage has one or more threads that just yield, and don't
-// block.  ;-(
-
-thread_t* sched_graph_priority_next_thread(void) 
-{
-  thread_t* t=NULL;
-
-  // some debug output
-#ifdef DEBUG_sched_graph_priority_c
-  {
-    static unsigned long long then = 0;
-    unsigned long long now = current_usecs();
-    if( now - then > 1e6 ) {
-      show_node_priorities();
-      then = now;
-    }
-  }    
-#endif
-
-  threads_in_epoch--;
-
-  // fix up the node priorities if it's been a while
-  if( threads_in_epoch <= 0 ) {
-    adjust_priorities();
-    sort_nodelist();
-    gp_nodelist_pos = 1;
-
-    // FIXME: choose this based on (a) the number of runnable threads
-    // and (b) the volatility of the priorities.  If things haven't
-    // changed recently, assume that we're OK for a bit longer than if
-    // they are still changing.
-    threads_in_epoch = 1;
-  }
-
-  
-  // look for a good node
-  while( gp_nodelist_pos < gp_nodelist_num ) {
-    bg_node_t *node = gp_nodelist[ gp_nodelist_pos ];
-
-    // skip nodes that would force allocation of scarce resources
-    //if( do_admission_control )
-    //  ;// FIXME: add this
-
-    // get the next thread from the current node
-    t = pl_remove_head( node->sched.g_pri.runlist );
-    if( valid_thread(t) ) 
-      break;
-    else 
-      gp_nodelist_pos++;
-  } 
-
-  // sanity check.  As long as we aren't doing admission control, we should always find a good t
-  //if( !do_admission_control )
-  //  assert( valid_thread(t) );
-
-
-  return t;
-}
-
-
-void sched_graph_priority_init(void)
-{
-
-  // pick something relatively small, so we can adjust this soon
-  threads_in_epoch = 1;
-
-  bzero(gp_nodelist, sizeof(gp_nodelist));
-}
-
-
-void sched_graph_priority_add_thread(thread_t *t)
-{
-  bg_node_t *node = t->curr_stats.node;
-
-  // add nodes that we have't seen before to the end of our list
-  if( node->sched.g_pri.listpos <= 0 ) {
-    node->sched.g_pri.listpos = gp_nodelist_num;
-    gp_nodelist[ gp_nodelist_num ] = node;
-    gp_nodelist_num++;
-    assert( gp_nodelist_num < GP_NODELIST_SIZE );  // make sure we aren't out of space
-
-    // allocate the runlist, if necessary
-    assert( node->sched.g_pri.runlist == NULL );
-    node->sched.g_pri.runlist = new_pointer_list("node_runlist");
-    node->sched.g_pri.score = 0;
-  }
-
-  // adjust our position in the node list, if this node has higher
-  // priority.  A position of 0 indicates that the node hasn't been
-  // seen yet.
-  // 
-  // fixme: think about this more --- this could lead to starvation.
-  // Also, is it really necessary?
-  //
-  //else if( node->sched.g_pri.listpos < gp_nodelist_pos ) {
-  //  gp_nodelist_pos = node->sched.g_pri.listpos;
-  //}
-
-  // add the node to the runlist
-  pl_add_tail(node->sched.g_pri.runlist, t);
-}
-
-
-void show_node_priorities()
-{
-  int i;
-
-  output("Node priority list:\n");
-  for( i=1; i<gp_nodelist_num; i++ ) {
-    output("  %15lld  node %d\n", gp_nodelist[i]->sched.g_pri.score, gp_nodelist[i]->node_num);
-  }
-  output("\n\n");
-}
-
-
diff --git a/user/c3po/threads/sched_graph_rr.c b/user/c3po/threads/sched_graph_rr.c
deleted file mode 100644 (file)
index 15bac0e..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- *
- *  Basic scheduler with different queues for each graph node
- *
- **/
-#include "threadlib_internal.h"
-#include "util.h"
-
-#ifndef DEBUG_graph_rr_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// global scheduler latch
-static latch_t scheduler_latch = LATCH_INITIALIZER_UNLOCKED;
-
-
-//////////////////////////////////////////////////////////////////////
-// generic functions, used by many variations of the stage scheduler 
-//////////////////////////////////////////////////////////////////////
-void sched_graph_generic_init(void)
-{
-}
-
-
-void sched_graph_generic_add_thread(thread_t *t)
-{
-  bg_node_t *node = t->curr_stats.node;
-
-  thread_latch( scheduler_latch );
-
-  // allocate the runlist, if necessary
-  if( node->sched.g_rr.runlist == NULL ) {
-    node->sched.g_rr.runlist = new_pointer_list("node_runlist");
-  }
-
-  // add the node to the runlist
-  pl_add_tail(node->sched.g_rr.runlist, t);
-
-  thread_unlatch( scheduler_latch );
-}
-
-
-
-//////////////////////////////////////////////////////////////////////
-// RR among stages - moving up in stage number
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_graph_generic_init, sched_graph_rr_init );
-strong_alias( sched_graph_generic_add_thread, sched_graph_rr_add_thread );
-
-// do RR among stages
-thread_t* sched_graph_rr_next_thread(void) 
-{
-  static int curr_stage = 0;
-  int i;
-  thread_t *t = NULL;
-
-  thread_latch( scheduler_latch );
-
-  // find the next node that has a runnable thread
-  i = curr_stage;
-  do {
-    //if( bg_nodelist[i]->sched.g_rr.runlist ) 
-    if( bg_nodelist[i]->sched.g_rr.runlist  &&  check_admission_control(bg_nodelist[i]) )
-      t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-    i = (i + 1) % bg_num_nodes;
-  } while( !valid_thread(t)  &&  i != curr_stage );
-
-  curr_stage = i;
-
-  thread_unlatch( scheduler_latch );
-
-  return t;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// RR among stages - moving down in stage number
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_graph_generic_init, sched_graph_rr_down_init );
-strong_alias( sched_graph_generic_add_thread, sched_graph_rr_down_add_thread );
-
-// do RR among stages
-thread_t* sched_graph_rr_down_next_thread(void) 
-{
-  static int curr_stage = 0;
-  int i;
-  thread_t *t = NULL;
-
-  thread_latch( scheduler_latch );
-
-  // find the next node that has a runnable thread
-  i = curr_stage;
-  do {
-    i = (i + bg_num_nodes - 1) % bg_num_nodes;
-    if( bg_nodelist[i]  &&  bg_nodelist[i]->sched.g_rr.runlist )
-      t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-  } while( !valid_thread(t) && i != curr_stage );
-  curr_stage = i;
-
-  // this happens if the original curr_stage was the only one w/ runnable thraeds
-  if( !valid_thread(t)  &&  bg_nodelist[i]  &&  bg_nodelist[i]->sched.g_rr.runlist )
-    t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-
-  thread_unlatch( scheduler_latch );
-
-  return t;
-}
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////
-// A batching scheduler.
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_graph_generic_init, sched_graph_batch_init );
-strong_alias( sched_graph_generic_add_thread, sched_graph_batch_add_thread );
-
-// process everything from the current stage, before moving on to the next
-thread_t* sched_graph_batch_next_thread(void) 
-{
-  static int curr_stage = 0;
-  static int left_in_stage = 0;
-  int start_stage, i;
-  thread_t *t = NULL;
-
-  thread_latch( scheduler_latch );
-
-  // update the stage, if we have reached the max
-  if( left_in_stage <= 0 ) {
-    start_stage = curr_stage;
-    do {
-      curr_stage++;  curr_stage = curr_stage%bg_num_nodes;
-    } while( curr_stage!=start_stage && bg_nodelist[curr_stage]->sched.g_rr.runlist == NULL );
-    
-    // allow at most 1.5x the current number of threads
-    left_in_stage = pl_size( bg_nodelist[curr_stage]->sched.g_rr.runlist ) * 3 / 2;
-  }
-
-  // check the current stage for runnable threads
-  if( bg_nodelist[curr_stage]  &&  bg_nodelist[curr_stage]->sched.g_rr.runlist )
-    t = pl_remove_head( bg_nodelist[curr_stage]->sched.g_rr.runlist );
-  if( valid_thread(t) ) {
-    thread_unlatch( scheduler_latch );
-    left_in_stage--;
-    return t;
-  }
-
-  // find the next node that has a runnable thread
-  i = curr_stage;
-  do {
-    i = (i + 1) % bg_num_nodes;
-    if( bg_nodelist[i]  &&  bg_nodelist[i]->sched.g_rr.runlist )
-      t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-  } while( !valid_thread(t) && i != curr_stage );
-
-  if( i != curr_stage ) {
-    curr_stage = i;
-    left_in_stage = pl_size( bg_nodelist[curr_stage]->sched.g_rr.runlist ) * 3 / 2;
-  }
-
-  thread_unlatch( scheduler_latch );
-
-  return t;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// pick threads from highest number first, but with admission control 
-//////////////////////////////////////////////////////////////////////
-
-strong_alias( sched_graph_generic_init, sched_graph_highnum_init );
-strong_alias( sched_graph_generic_add_thread, sched_graph_highnum_add_thread );
-
-// find the first available thread from the highest numbered node
-thread_t* sched_graph_highnum_next_thread(void) 
-{
-  static int iterations = 100;
-  static int rr_stage = 0;
-  thread_t *t=NULL;
-  int i;
-
-  thread_latch( scheduler_latch );
-
-  // every so often, give other stages a chance to run.
-  if( iterations <= 0 ) {
-    iterations = 100;
-    i = rr_stage;
-    do {
-      if( bg_nodelist[i]->sched.g_rr.runlist &&
-          check_admission_control(bg_nodelist[i]) ) {
-        t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-      }
-      if( valid_thread(t) ) break;
-      i = (i+1) % bg_num_nodes;
-    } while( i != rr_stage );
-    rr_stage = i;
-  } 
-  
-  // otherwise, do the normal algorithm
-  else {
-    i = bg_num_nodes-1;
-    do {
-      if( bg_nodelist[i]->sched.g_rr.runlist  &&
-          check_admission_control(bg_nodelist[i]) ) {
-        t = pl_remove_head( bg_nodelist[i]->sched.g_rr.runlist );
-      }
-      i--;
-    } while( i >= 0  &&  !valid_thread(t) );
-
-    iterations--;
-  }
-
-  thread_unlatch( scheduler_latch );
-
-  return t;
-}
-
-
-
diff --git a/user/c3po/threads/semaphore.h b/user/c3po/threads/semaphore.h
deleted file mode 100644 (file)
index e5fcf42..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Dummy stub for unimplemented thread semaphere */
-
-
-#ifndef _SEMAPHORE_H
-#define _SEMAPHORE_H    1
-
-#include <pthread.h>
-
-#include <features.h>
-#include <sys/types.h>
-#ifdef __USE_XOPEN2K
-# define __need_timespec
-# include <time.h>
-#endif
-
-#ifndef _PTHREAD_DESCR_DEFINED
-/* Thread descriptors.  Needed for `sem_t' definition.  */
-typedef struct _pthread_descr_struct *_pthread_descr;
-# define _PTHREAD_DESCR_DEFINED
-#endif
-
-/* System specific semaphore definition.  */
-typedef struct
-{
-//  struct _pthread_fastlock __sem_lock;
-//  int __sem_value;
-//  _pthread_descr __sem_waiting;
-} sem_t;
-
-
-
-/* Value returned if `sem_open' failed.  */
-#define SEM_FAILED     ((sem_t *) 0)
-
-/* Maximum value the semaphore can have.  */
-#define SEM_VALUE_MAX  ((int) ((~0u) >> 1))
-
-
-__BEGIN_DECLS
-
-/* Initialize semaphore object SEM to VALUE.  If PSHARED then share it
-   with other processes.  */
-extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW;
-
-/* Free resources associated with semaphore object SEM.  */
-extern int sem_destroy (sem_t *__sem) __THROW;
-
-/* Open a named semaphore NAME with open flaot OFLAG.  */
-extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW;
-
-/* Close descriptor for named semaphore SEM.  */
-extern int sem_close (sem_t *__sem) __THROW;
-
-/* Remove named semaphore NAME.  */
-extern int sem_unlink (__const char *__name) __THROW;
-
-/* Wait for SEM being posted.  */
-extern int sem_wait (sem_t *__sem) __THROW;
-
-#ifdef __USE_XOPEN2K
-/* Similar to `sem_wait' but wait only until ABSTIME.  */
-extern int sem_timedwait (sem_t *__restrict __sem,
-                         __const struct timespec *__restrict __abstime)
-     __THROW;
-#endif
-
-/* Test whether SEM is posted.  */
-extern int sem_trywait (sem_t *__sem) __THROW;
-
-/* Post SEM.  */
-extern int sem_post (sem_t *__sem) __THROW;
-
-/* Get current value of SEM and store it in *SVAL.  */
-extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval)
-     __THROW;
-
-__END_DECLS
-
-#endif  /* semaphore.h */
diff --git a/user/c3po/threads/threadlib.c b/user/c3po/threads/threadlib.c
deleted file mode 100644 (file)
index b10f3e8..0000000
+++ /dev/null
@@ -1,1520 +0,0 @@
-// ROS Specific headers
-#include <vcore.h>
-#include <mcs.h>
-#include <ros/syscall.h>
-
-// Capriccio Specific headers
-#include "ucontext.h"
-#include "threadlib_internal.h"
-#include "util.h"
-#include "config.h"
-#include "blocking_graph.h"
-#include "stacklink.h"
-
-// Glibc Specific headers
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <execinfo.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <syscall.h>
-#include <sys/syscall.h>
-
-/******************************************************************************/
-/******************************* Configuration ********************************/
-/******************************************************************************/
-
-// Comment out, to enable debugging in this file
-#ifndef DEBUG_threadlib_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// Chose the size of the scheduler threads stack in the case of using
-// NIO vs. AIO
-#ifdef USE_NIO
-#define SCHEDULER_STACK_SIZE 1024*128
-#else
-#define SCHEDULER_STACK_SIZE 1024
-#endif
-
-/******************************************************************************/
-/***************************** Global Variables *******************************/
-/******************************************************************************/
-
-// The PID of the main process.  This is useful to prevent errors when
-// forked children call exit_func().
-static pid_t main_pid;
-
-// Variable used to hold the time when the program first started executing
-static unsigned long long start_usec;
-
-// Variables used to store the amount of time spent in different parts of 
-// the application code: the scheduler, main thread, all other threads
-static struct {
-  cap_timer_t scheduler;
-  cap_timer_t main;
-  cap_timer_t app;
-} timers;
-
-// Pointer to the main thread
-static thread_t* main_thread=NULL;
-
-// Lock used to restrict access to all thread lists, thread state changes,
-// and the count of threads in different states
-static mcs_lock_t thread_lock = MCS_LOCK_INIT;
-
-// A list of all threads in the system (i.e. spawned, but not exited yet)
-static pointer_list_t *threadlist = NULL;
-
-// Variable used to maintain global counts of how 
-// many threads are in a given state (used only for bookkeeping)
-static struct {
-  int running;
-  int runnable;
-  int suspended;
-  int detached;
-  int zombie;
-  int total;
-} num_threads = {0, 0, 0, 0};
-
-// Set of global flags
-static struct {
-  // Flag to indicate whether or not to override syscalls.  We don't
-  // override during initialization, in order to avoid loops w/
-  // libraries such as perfctr that must do IO.  We also don't override
-  // syscalls after SIG_ABRT, so we can get proper core dumps.
-  // Only really necessary for linux, as ROS does all IO asyncronously.
-  volatile unsigned int override_syscalls: 1;
-
-  // Flags regarding the state of the main_thread
-  volatile unsigned int main_exited: 1;
-  volatile unsigned int exit_func_done: 1;
-} gflags = {1, 0, 0};
-
-// Set of thread local flags (only useful in scheduler or vcore context)
-static __thread struct {
-  // Flag indicating whether we are currently running scheduler code 
-  // on the core or not
-  int in_scheduler: 1;
-} lflags = {0};
-
-// Function pointers for plugging in modular scheduling algorithms
-// Run queues are maintained locally in each algorithm
-static void (*sched_init)(void); 
-static void (*sched_add_thread)(thread_t *t); 
-static thread_t* (*sched_next_thread)(void); 
-
-// Sleep queue, containing any sleeping threads
-static pointer_list_t *sleepq = NULL;
-
-// Variables used to regulate sleep times of sleeping threads
-static struct {
-  // When is the sleep time calculated from
-  unsigned long long last_check;   
-  // Wall clock time of the wake time of the first sleeping thread
-  unsigned long long first_wake;
-  // Length of the whole sleep queue, in microseconds
-  unsigned long long max;    
-} sleep_times = {0, 0, 0};
-
-// Function pointer to the io polling function being used
-// Only really makes sense in Linux, as ROS uses all async IO and
-// event queues for IO
-static void (*io_polling_func)(long long usecs);
-
-// Variables set by CIL when executing using linked stacks
-void **start_node_addrs = NULL;
-int *start_node_stacks = NULL;
-
-/******************************************************************************/
-/************************** Function Declarations *****************************/
-/******************************************************************************/
-
-// Vcore functions
-inline static bool __query_vcore_request();
-inline static bool __query_vcore_yield();
-
-// Sleep queue functions
-inline static void sleepq_add_thread(thread_t *t, unsigned long long timeout);
-inline static void sleepq_remove_thread(thread_t *t);
-inline static void sleepq_check_wakeup();
-
-// Thread related functions
-void run_next_thread();
-inline static void __thread_resume(thread_t *t);
-inline static void __thread_make_runnable(thread_t *t);
-inline static void __free_thread_prep(thread_t *t);
-inline static void free_thread(thread_t *t);
-
-// Helper Functions 
-static void exit_func(void);
-static void pick_scheduler();
-static int get_stack_size_kb_log2(void *func);
-
-/******************************************************************************/
-/********************************** Macros ************************************/
-/******************************************************************************/
-
-// Sanity check THREAD_KEY_MAX and size of key_data_count
-//#if THREAD_KEY_MAX >> (sizeof(thread_t.key_data_count)-1) != 1
-//#error not enough space in thread_t.key_data_count
-//#endif
-
-/******************************************************************************/
-/*************************** Function Definitions *****************************/
-/******************************************************************************/
-
-/**
- * This will be called as part of the initialization sequence
- **/
-void main_thread_init() 
-{
-  tdebug("Enter\n");
-  static int init_done = 0;
-  if(init_done) 
-    return;
-  init_done = 1;
-
-  // Make sure the clock init is already done, so we don't wind up w/
-  // a dependancy loop b/w perfctr and the rest of the code.
-//  init_cycle_clock();
-//  init_debug();
-
-  // Initialize and Register all timers
-//  init_timer(&timers.main);
-//  init_timer(&timers.scheduler);
-//  init_timer(&timers.app);
-//  register_timer("total", &timers.main);
-//  register_timer("sheduler", &timers.scheduler);
-//  register_timer("app", &timers.app);
-
-  // Start the main timer
-//  start_timer(&timers.main);
-
-  // Init the scheduler function pointers
-  pick_scheduler();
-
-  // Init the scheduler code
-  sched_init();
-
-  // Create the main thread
-  main_thread = malloc(sizeof(thread_t));  
-  assert(main_thread);
-  bzero(main_thread, sizeof(thread_t));
-  main_thread->context = create_context(main_thread, NULL, NULL);
-  main_thread->name = "main_thread";
-  main_thread->initial_arg = NULL;
-  main_thread->initial_func = NULL;
-  main_thread->tid = 0;   // fixed value
-  main_thread->joinable = 0;
-  main_thread->sleep = -1;
-
-  // Create global thread list
-  threadlist = new_pointer_list("thread_list");
-
-  // Create sleep queue
-  sleepq = new_pointer_list("sleep_queue");
-  sleep_times.max = 0;
-  sleep_times.last_check = 0;
-  sleep_times.first_wake = 0;
-
-  // Add main thread to the global list of threads
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  pl_add_tail(threadlist, main_thread);
-  num_threads.total++;
-  // Update number of running threads
-  main_thread->state = RUNNING;
-  num_threads.running++;
-  num_threads.detached++;
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-  
-  // intialize blocking graph functions
-//  init_blocking_graph();
-
-//  // Set stats for the main thread
-//  {
-//    bg_dummy_node->num_here++;
-//    current_thread->curr_stats.node = bg_dummy_node;
-//    current_thread->curr_stats.files = 0;
-//    current_thread->curr_stats.sockets = 0;
-//    current_thread->curr_stats.heap = 0;
-//    bg_set_current_stats( &current_thread->curr_stats );
-//
-//    current_thread->prev_stats = current_thread->curr_stats;
-//  }
-
-  // Setup custom exit function called by glibc when exit() called
-  // Don't exit when main exits - wait for threads to die
-  atexit(exit_func);
-
-  // Mark the time the program starts running
-//  start_usec = current_usecs();
-
-  // Things are all set up, so now turn on the syscall overrides
-  // Only really required by the linux port.
-//  gflags.override_syscalls = 1;
-  tdebug("Exit\n");
-}
-
-/**
- * Function to select and launch the next thread with the selected scheduler.
- * Only called from within vcore context.  Keep this in mind when reasoning
- * about how thread local variables, etc. are used.
- **/
-void run_next_thread()
-{
-  tdebug("Enter\n");
-  // Make sure we start out by saving edge stats
-//  static int init_done = 0;
-//  static cpu_tick_t next_info_dump = 0, next_graph_stats = 0, now = 0;
-//  if( !init_done ) {
-//    init_done = 1;
-//    if (conf_no_statcollect) 
-//      bg_save_stats = 0;
-//    else
-//      bg_save_stats = 1;
-//    
-//    GET_REAL_CPU_TICKS( now );
-//    next_graph_stats = now + 1 * ticks_per_second;
-//    
-//    start_timer(&timers.scheduler);
-//  }
-//  // Cheesy way of handling things with timing requirements
-//  {
-//    GET_REAL_CPU_TICKS( now );
-//      
-//    // toggle stats collection
-//    if( conf_no_statcollect == 0 && next_graph_stats < now ) {
-//      bg_save_stats = 1 - bg_save_stats;
-// 
-//      if( bg_save_stats ) { 
-//        // record stats for 100 ms
-//        next_graph_stats = now + 100 * ticks_per_millisecond;
-//          
-//        // update the stats epoch, to allow proper handling of the first data items
-//        bg_stats_epoch++;
-//      }            
-//      else {
-//        // avoid stats for 2000 ms
-//        next_graph_stats = now + 2000 * ticks_per_millisecond;
-//      }
-//      //output(" *********************** graph stats %s\n", bg_save_stats ? "ON" : "OFF" );
-//    }
-//      
-//    // Poll for I/O
-//    static cpu_tick_t next_poll = 0;
-//    static int pollcount = 1000;
-//    if( likely( (int)io_polling_func) ) {
-//      if( num_threads.runnable == 0  ||  --pollcount <= 0  ||  next_poll < now ) {
-//        long long timeout = 0;
-// 
-//        if( num_threads.runnable == 0 ) {
-//          if (sleep_times.first_wake == 0) {
-//            timeout = -1;
-//          } else {
-//            // there are threads in the sleep queue
-//            // so poll for i/o till at most that time
-//            unsigned long long now;
-//            now = current_usecs();
-//            tdebug ("first_wake: %lld, now: %lld\n", sleep_times.first_wake, now);
-//            if (sleep_times.first_wake > now)
-//              timeout = sleep_times.first_wake - now;
-//          }
-//        }
-// 
-//        stop_timer(&timers.scheduler);
-//        //if( timeout != -1 )  output("timeout is not zero\n");
-//        io_polling_func( timeout ); // allow blocking
-//        start_timer(&timers.scheduler);
-// 
-//        next_poll = now + (ticks_per_millisecond << 13);
-//        pollcount = 10000;
-//      }
-//    }
-//
-//    // Gather debug stats
-//    if( 0 && next_info_dump < now ) {
-//      dump_debug_info();
-//      next_info_dump = now + 5 * ticks_per_second;
-//    }
-//  }
-
-  // Wake up threads that are asleep who's timeouts have expired
-  sleepq_check_wakeup(FALSE);   
-  // Keep trying to get a thread off of the scheduler queue
-  thread_t *t; 
-  struct mcs_lock_qnode local_qn = {0};
-  while(1) {
-    mcs_lock_lock(&thread_lock, &local_qn);
-       // Check to see if we are in the processes of exiting the entire program.
-       // If we are, then go ahead and yield this vcore. We are dying, afterall..
-       if(gflags.exit_func_done) {
-      bool yieldcore = __query_vcore_yield();
-      mcs_lock_unlock(&thread_lock, &local_qn);
-      if(yieldcore) vcore_yield(FALSE);
-    }
-               
-    // Otherwise, grab a thread from the scheduler queue 
-    t = sched_next_thread();
-
-       // If there aren't any, if there aren't any, go ahead and yield the core
-       // back to the kernel.  This can only really happen when there are only
-       // running and suspended threads in the system, but no runnable ones. When
-       // a suspended thread is woken up, it will try and request a new vcore from
-       // the system if appropriate.
-    if(t == NULL) {
-      bool yieldcore = __query_vcore_yield();
-      mcs_lock_unlock(&thread_lock, &local_qn);
-      if(yieldcore) vcore_yield(FALSE);
-    }
-       // Otherwise, if the thread is in the ZOMBIE state, then it must have been
-       // detached and added back to the queue for the scheduler to reap.  
-    // Reap it now, then go and grab the next thread.
-    else if(t->state == ZOMBIE) {
-      __free_thread_prep(t);
-      mcs_lock_unlock(&thread_lock, &local_qn);
-      free_thread(t);
-    }
-    // Otherwise, we've found a thread to run, so continue.
-    else
-      break;
-  }
-  // Update the num_threads variables and the thread state
-  num_threads.runnable--;
-  num_threads.running++;
-  t->state = RUNNING;
-  mcs_lock_unlock(&thread_lock, &local_qn);
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-  tdebug("About to run TID %d (%s)\n", t->tid, t->name ? t->name : "no name");
-  // Run the thread
-//  stop_timer(&timers.scheduler);
-//  start_timer(&timers.app);
-  tdebug("Exit\n");
-  assert(!current_thread);
-  restore_context(t->context);
-}
-
-/**
- * Wrapper function for new threads.  This allows us to clean up
- * correctly if a thread exits without calling thread_exit().
- **/
-static void* __attribute__((noreturn)) new_thread_wrapper(void *arg)
-{
-  tdebug("Enter\n");
-  // set up initial stats
-//  current_thread->curr_stats.files = 0;
-//  current_thread->curr_stats.sockets = 0;
-//  current_thread->curr_stats.heap = 0;
-//  bg_set_current_stats( &current_thread->curr_stats );
-//  current_thread->prev_stats = current_thread->curr_stats;
-//
-//  // set up stack limit for new thread
-//  stack_bottom = current_thread->stack_bottom;
-//  stack_fingerprint = current_thread->stack_fingerprint;
-
-  // start the thread
-  tdebug("Initial arg = %p\n", current_thread->initial_arg);
-  void *ret = current_thread->initial_func(current_thread->initial_arg);
-  
-  // call thread_exit() to do the cleanup
-  thread_exit(ret);
-  assert(0);
-}
-
-inline static bool __query_vcore_request()
-{
-  return FALSE;
-  //return TRUE;
-  //return (num_vcores() < 2);
-  //return ((num_threads.total-num_threads.zombie) > num_vcores());
-  //return ((num_threads.total-num_threads.zombie) > num_vcores());
-}
-
-inline static bool __query_vcore_yield()
-{
-  return FALSE;
-  //return TRUE;
-}
-
-/* Create a new thread and add it to the scheduler queue */
-static thread_t* new_thread(char *name, void* (*func)(void *), void *arg, thread_attr_t attr)
-{
-  tdebug("Enter\n");
-  static unsigned max_tid = 1;
-  thread_t *t = malloc( sizeof(thread_t) );
-  int stack_size_kb_log2 = 10;//get_stack_size_kb_log2(func);
-  int stack_size = 1 << (stack_size_kb_log2 + 10);
-  void *stack = malloc(stack_size);//stack_get_chunk( stack_size_kb_log2 );
-
-  if( !t || !stack ) {
-    if (t) free(t);
-    if (stack) free(stack);//stack_return_chunk(stack_size_kb_log2, stack);
-    printf("Uh Oh!\n");
-    return NULL;
-  }
-
-  bzero(t, sizeof(thread_t));
-  t->context = create_context(t, new_thread_wrapper, stack+stack_size);
-  t->stack = stack;
-  t->stack_size_kb_log2 = stack_size_kb_log2;
-  t->stack_bottom = stack;
-  t->stack_fingerprint = 0;
-  t->name = (name ? name : "noname"); 
-  t->initial_func = func;
-  t->initial_arg = arg;
-  t->joinable = 1;
-  t->tid = max_tid++;
-  t->sleep = -1;
-
-  // Make sure the thread has a valid node before we add it to the scheduling list
-//  bg_dummy_node->num_here++;
-//  t->curr_stats.node = bg_dummy_node;
-
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  // Up the count of detached threads if this thread should be detached
-  if( attr ) {
-    t->joinable = attr->joinable;
-    if(!t->joinable) {
-      num_threads.detached++;
-    }
-  }
-  // Add the thread to the global list of all threads
-  pl_add_tail(threadlist, t);
-  num_threads.total++;
-  // Add the thread to the scheduler to make it runnable
-  sched_add_thread(t);
-  t->state = RUNNABLE;
-  num_threads.runnable++;
-  bool requestcore = __query_vcore_request();
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-
-  /* Possibly request a new vcore.  In the best case, we have 1 core per thread
-   * that we launch.  If not, it never hurts to ask for another one.  The
-   * system will simply deny us and the scheduler will multiplex all threads on
-   * the available vcores. */
-  if(requestcore) vcore_request(1);
-
-  tdebug("Exit\n");
-  // Return the newly created thread.
-  return t;
-}
-
-/**
- * Free the memory associated with the given thread.
- * Needs to be protected by the thread_lock.
- **/
-inline static void __free_thread_prep(thread_t *t)
-{
-  // Make sure we should actually be freeing this thread
-  assert(t->state == ZOMBIE);
-  // Make this zombie a ghost!
-  t->state = GHOST;
-  // Drop the count of zombie threads in the system
-  num_threads.zombie--;
-  // Remove this thread from the global list of all threads
-  pl_remove_pointer(threadlist, t);
-  num_threads.total--;
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-}
-
-/**
- * Actually free the memory associated with a thread.  Should only be called
- * after first calling __free_thread_prep while holding the thread_lock.  Make
- * sure to NOT call this function while holding the thread_lock though.
- **/
-inline static void free_thread(thread_t *t)
-{
-  // Free the thread memory
-  if( t != main_thread ) {
-    free(t->stack);//stack_return_chunk(t->stack_size_kb_log2, t->stack);
-  }
-  destroy_context(t->context);
-  free(t);
-}
-
-/**
- * Give control back to the scheduler after main() exits.  This allows
- * remaining threads to continue running.
- * FIXME: we don't know whether user explicitly calls exit() or main() normally returns
- * in the previous case, we should exit immediately, while in the latter, we should 
- * join other threads.
- * Overriding exit() does not work because normal returning from
- * main() also calls exit().
- **/
-static void exit_func(void)
-{
-  tdebug("Enter\n");
-  // Don't do anything if we're in a forked child process
-  if(current_thread != main_thread)
-    return;
-
-  tdebug("current=%s, gflags.main_exited=%d\n", 
-          current_thread?current_thread->name : "NULL", gflags.main_exited);
-
-  gflags.main_exited = TRUE;
-//  if( !gflags.exit_whole_program )
-       // this will block until all other threads finish
-    thread_exit(NULL);
-
-//  // dump the blocking graph before we exit
-//  if( conf_dump_blocking_graph ) {
-//    tdebug("dumping blocking graph from exit_func()\n");
-//    dump_blocking_graph(); 
-//  }
-//
-//  // FIXME: make sure to kill cloned children
-//
-//  if( conf_dump_timing_info ) {
-//    if( timers.main.running )   stop_timer(&timers.main);
-//    if( timers.scheduler.running )   stop_timer(&timers.scheduler);
-//    if( timers.app.running )   stop_timer(&timers.app);
-//    print_timers();
-//  }
-  tdebug("Exit\n");
-}
-
-static char *THREAD_STATES[] = {"RUNNING", "RUNNABLE", "SUSPENDED", "ZOMBIE", "GHOST"};
-
-// dump status to stderr 
-void dump_debug_info()
-{
-  output("\n\n-- Capriccio Status Dump --\n");
-  output("Current thread %d  (%s)\n", 
-         current_thread ? (int)thread_tid(current_thread) : -1,
-         (current_thread && current_thread->name) ? current_thread->name : "noname");
-  output("threads:    %d runnable    %d suspended    %d detached\n", 
-         num_threads.runnable, num_threads.suspended, num_threads.detached);
-
-  print_resource_stats();
-
-  stack_report_usage_stats();
-  stack_report_call_stats();
-
-  {
-    int i;
-    output("thread locations:");
-    for(i=0; i<bg_num_nodes; i++) {
-      bg_node_t *node = bg_nodelist[i];
-      if(node->num_here)
-        output("  %d:%d", node->node_num, node->num_here);
-    }
-    output("\n");
-  }
-
-  output("\n\n");
-}
-void dump_thread_state()
-{
-  void *bt[100];
-  int count, i;
-  linked_list_entry_t *e;
-
-  output("\n-- State of all threads --\n");
-
-  e = ll_view_head(threadlist);
-  while (e) {
-    char sleepstr[80];
-    thread_t *t = (thread_t *) pl_get_pointer(e);
-
-    output("Thread %2d (%s)  %s    %d file   %d sock    %ld KB heap   ? KB stack    %s%s%s\n", 
-           thread_tid(t), t->name, THREAD_STATES[t->state], 
-           t->curr_stats.files, 
-           t->curr_stats.sockets, 
-           t->curr_stats.heap / 1024,
-           //(long)-1, // FIXME: add total stack numbers after incorporating Jeremy's code
-           t->joinable ? "joinable  " : "",
-           t->sleep > 0 ? (sprintf(sleepstr,"sleep=%lld  ",t->sleep), sleepstr) : "");
-    e = ll_view_next(threadlist, e);
-  }
-
-  return;
-}
-
-
-
-
-/**
- * decide on the scheduler to use, based on the CAPRICCIO_SCHEDULER
- * environment variable.  This function should only be called once,
- * durring the initialization of the thread runtime.
- **/
-#define SET_SCHEDULER(s) do {\
-  sched_init = sched_##s##_init; \
-  sched_next_thread = sched_##s##_next_thread; \
-  sched_add_thread = sched_##s##_add_thread; \
-  if( !conf_no_init_messages ) \
-    output("CAPRICCIO_SCHEDULER=%s\n",__STRING(s)); \
-} while(0)
-
-static void pick_scheduler()
-{
-  char *sched = getenv("CAPRICCIO_SCHEDULER");
-
-  if(sched == NULL) 
-    SET_SCHEDULER( global_rr ); // defaults
-  else if( !strcasecmp(sched,"global_rr") )
-    SET_SCHEDULER( global_rr );
-  else if( !strcasecmp(sched,"global_lifo") )
-    SET_SCHEDULER( global_lifo );
-  else if( !strcasecmp(sched,"graph_rr") )
-    SET_SCHEDULER( graph_rr );
-  else if( !strcasecmp(sched,"graph_rr_down") )
-    SET_SCHEDULER( graph_rr_down );
-  else if( !strcasecmp(sched,"graph_batch") )
-    SET_SCHEDULER( graph_batch );
-  else if( !strcasecmp(sched,"graph_highnum") )
-    SET_SCHEDULER( graph_highnum );
-  else if( !strcasecmp(sched,"graph_priority") )
-    SET_SCHEDULER( graph_priority );
-  else
-    fatal("Invalid value for CAPRICCIO_SCHEDULER: '%s'\n",sched);
-
-}
-
-/**
- * Perform necessary management to yield the current thread
- * if suspend == TRUE && timeout != 0 -> the thread is added 
- * to the sleep queue and later woken up when the clock times out.
- * Returns FALSE if time-out actually happens, TRUE if woken up
- * by other threads, INTERRUPTED if interrupted by a signal.
- **/
-static int __thread_yield(int suspend, unsigned long long timeout)
-{
-  tdebug("Enter\n");
-  // Now we use a per-thread errno stored in thread_t
-  int savederrno;
-  savederrno = errno;
-
-  tdebug("current_thread=%p\n",current_thread);
-
-//  {
-//#ifdef SHOW_EDGE_TIMES
-//    cpu_tick_t start, end, rstart, rend;
-//    GET_CPU_TICKS(start);
-//    GET_REAL_CPU_TICKS(rstart);
-//#endif
-//
-//    // Figure out the current node in the graph
-//    if( !conf_no_stacktrace )
-//      bg_backtrace_set_node();
-//    // FIXME: fake out what cil would do...  current_thread->curr_stats.node = bg_dummy_node;
-//
-//    // We should already have been told the node by CIL or directly by the programmer
-//    assert( current_thread->curr_stats.node != NULL );
-//    
-//    // Update node counts
-//    current_thread->prev_stats.node->num_here--;
-//    current_thread->curr_stats.node->num_here++;
-//    
-//    // Update the blocking graph info
-//    if( bg_save_stats )
-//      bg_update_stats();
-//  
-//#ifdef SHOW_EDGE_TIMES
-//    GET_CPU_TICKS(end);
-//    GET_REAL_CPU_TICKS(rend);
-//    {
-//      thread_stats_t *curr = &current_thread->curr_stats;
-//      thread_stats_t *prev = &current_thread->prev_stats;
-//      output(" %3d -> %-3d     %7lld ticks  (%lld ms)   %7lld rticks (%lld ms)    ", 
-//             prev->node->node_num,  curr->node->node_num, 
-//             curr->cpu_ticks - prev->cpu_ticks,
-//             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond,
-//# ifdef USE_PERFCTR
-//             curr->real_ticks - prev->real_ticks,
-//             (curr->real_ticks - prev->real_ticks) / ticks_per_millisecond
-//# else
-//             curr->cpu_ticks - prev->cpu_ticks,
-//             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond
-//# endif
-//             );
-//
-//      output("update bg node %d:   %lld   (%lld ms)   real: %lld (%lld ms)\n", 
-//             current_thread->curr_stats.node->node_num, 
-//             (end-start), (end-start)/ticks_per_millisecond, 
-//             (rend-rstart), (rend-rstart)/ticks_per_millisecond);
-//    }
-//#endif
-//  }
-
-  // Decide what to do with the thread
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  // Drop the count of running threads
-  num_threads.running--;
-  // If we should suspend it, do so for the specified timeout
-  if(suspend) { 
-    current_thread->state = SUSPENDED;
-    num_threads.suspended++;
-       // Add the thread to the sleep queue if a timeout was given
-    // If no timeout was given, that means we should sleep forever
-       // or until some other thread wakes us up (i.e. on a join)      
-    if(timeout)
-      sleepq_add_thread(current_thread, timeout);
-  }
-  else {
-    current_thread->state = RUNNABLE;
-    num_threads.runnable++;
-    sched_add_thread(current_thread);
-  }
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-
-//  // squirrel away the stack limit for next time
-//  current_thread->stack_bottom = stack_bottom;
-//  current_thread->stack_fingerprint = stack_fingerprint;
-
-  // Save the context of the currently running thread.
-  // When it is restored it will start up again right here
-  save_context(current_thread->context);
-
-  // We only want to call switch_to_vcore() when running through
-  // this function at the time of the yield() call.  Since our 
-  // context is restored right here though, we need a way to jump around
-  // the call to switch_to_vcore() once the thread is woken back up.
-  volatile bool yielding = TRUE;
-  if (yielding) {
-    yielding = FALSE; /* for when it starts back up */
-    // Switch back to vcore context to run the scheduler
-    switch_to_vcore();
-  }
-  // Thread context restored...
-  
-//  // Set up stack limit for new thread
-//  stack_bottom = current_thread->stack_bottom;
-//  stack_fingerprint = current_thread->stack_fingerprint;
-//
-//  // rotate the stats
-//  if( bg_save_stats ) {
-//    current_thread->prev_stats = current_thread->curr_stats;
-//    
-//    // update thread time, to skip time asleep
-//    GET_CPU_TICKS( current_thread->prev_stats.cpu_ticks );
-//    current_thread->prev_stats.cpu_ticks -= ticks_diff;  // FIXME: subtract out time to do debug output
-//#ifdef USE_PERFCTR
-//    GET_REAL_CPU_TICKS( current_thread->prev_stats.real_ticks );
-//    current_thread->prev_stats.real_ticks -= ticks_rdiff;  // FIXME: subtract out time to do debug output
-//#endif    
-//  } else {
-//    current_thread->prev_stats.node = current_thread->curr_stats.node;
-//  }
-//  
-//  // Check whether time-out happened already or not
-  int rv = OK;
-//  if (suspend && timeout && current_thread->timeout) {
-//    rv = TIMEDOUT;
-//    current_thread->timeout = 0;
-//  }
-//
-//  // Check for and process pending signals
-//  if ( likely(!current_thread->sig_waiting) ) {
-//    if (sig_process_pending())
-//             rv = INTERRUPTED;
-//  } else {
-//       // If sig_waiting is 1, sigwait() itself will handle the remaining    
-//       rv = INTERRUPTED;
-//  }
-  
-  errno = savederrno;
-  tdebug("Exit\n");
-  return rv;
-}
-
-void thread_yield()
-{
-  CAP_SET_SYSCALL();
-  __thread_yield(FALSE,0);
-  CAP_CLEAR_SYSCALL();
-}
-
-int sched_yield(void)
-{
-  thread_yield();
-  return 0;
-}
-strong_alias(sched_yield,__sched_yield);
-
-// Timeout == 0 means infinite time
-int thread_suspend_self(unsigned long long timeout)
-{
-  return __thread_yield(TRUE, timeout);
-}
-
-//////////////////////////////////////////////////////////////////////
-// 
-//  External functions
-// 
-//////////////////////////////////////////////////////////////////////
-
-inline thread_t *thread_spawn_with_attr(char *name, void* (*func)(void *), 
-                                 void *arg, thread_attr_t attr)
-{
-  return new_thread(name, func, arg, attr);
-}
-
-inline thread_t *thread_spawn(char *name, void* (*func)(void *), void *arg)
-{
-  return new_thread(name, func, arg, NULL);
-}
-
-static inline bool time_to_die() {
-return ((gflags.main_exited == TRUE) &&
-        ((num_threads.total-num_threads.zombie) == num_threads.detached)
-       );
-}
-
-void thread_exit(void *ret)
-{
-  tdebug("Enter\n");
-  thread_t *t = current_thread;
-
-  //printf("current=%s, gflags.main_exited=%d\n", 
-  //        current_thread?current_thread->name : "NULL", gflags.main_exited);
-
-  if (current_thread == main_thread && gflags.main_exited == FALSE) {
-       // The case when the user calls thread_exit() in main thread is complicated
-       // we cannot simply terminate the main thread, because we need that stack to terminate the
-       // whole program normally.  so we call exit() to make the c runtime help us get the stack
-       // context where we can just return to terminate the whole program
-       // this will call exit_func() and in turn call thread_exit() again
-    gflags.main_exited = TRUE;
-       exit(0);                
-  }
-
-//  // Note the thread exit in the blocking graph
-//  current_thread->curr_stats.node = bg_exit_node;
-//  current_thread->prev_stats.node->num_here--;
-//  current_thread->curr_stats.node->num_here++;
-//  if( bg_save_stats ) {
-//    bg_update_stats();
-//  }
-    
-  // If we are the main thread...
-  struct mcs_lock_qnode local_qn = {0};
-  while(unlikely(t == main_thread)) {
-    // Check if we really can exit the program now.
-    // If so, end of program!
-    if(time_to_die()) {
-      //// Dump the blocking graph
-      //if( gflags.exit_func_done && conf_dump_blocking_graph ) {
-      //  tdebug("dumping blocking graph from run_next_thread()\n");
-      //  dump_blocking_graph(); 
-      //}
-
-      // Return back to glibc and exit the program!
-         // First set a global flag so no other vcores try to pull new threads off
-         // of any lists (these lists are about to be deallocated...)
-      mcs_lock_lock(&thread_lock, &local_qn);
-      gflags.exit_func_done = TRUE;
-      mcs_lock_unlock(&thread_lock, &local_qn);
-
-      printf("Dying with %d vcores\n", num_vcores());
-      printf("Program exiting normally!\n");
-      return;
-    }
-    // Otherwise, suspend ourselves to be woken up when it is time to die
-    else {
-      // Suspend myself
-      thread_suspend_self(0);
-    }
-  }
-  // Otherwise...
-  // Update thread counts and resume blocked threads
-  mcs_lock_lock(&thread_lock, &local_qn);
-  num_threads.running--;
-  num_threads.zombie++;
-  t->state = ZOMBIE;
-
-  // Check if it's time to die now. If it is, wakeup the main thread so we can
-  // exit the program
-  if(unlikely(time_to_die()))
-      __thread_resume(main_thread);
-
-  // Otherwise, if the thread is joinable, resume the thread that joined on it.
-  // If no one has joined on it yet, we have alreadu set its thread state to
-  // ZOMBIE so that the thread that eventually tries to join on it can see
-  // this, and free it.
-  else if(likely(t->joinable)) {
-    t->ret = ret;
-    if (t->join_thread) {
-      __thread_resume(t->join_thread);
-    }
-  }
-
-  // Otherwise, update the count of detached threads and put the thread back on
-  // the scheduler queue. The thread will be freed by the scheduler the next
-  // time it attempts to run.
-  else {
-    num_threads.detached--;
-    sched_add_thread(t);
-  }
-
-  // Check to see if we now have less threads than we have vcores.  If so,
-  // prepare to yield the current core back to the system.
-  bool yieldcore = __query_vcore_yield();
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-
-  /* If we were told to yield the vcore, do it! */
-  if(yieldcore)
-    vcore_yield(FALSE);
-         
-  /* Otherwise switch back to vcore context to schedule the next thread. */
-  switch_to_vcore();
-  assert(0);
-}
-
-int thread_join(thread_t *t, void **ret)
-{
-  tdebug("Enter\n");
-  // Return errors if the argument is bogus
-  if(t == NULL)
-    return_errno(FALSE, EINVAL);
-  if(!t->joinable)
-    return_errno(FALSE, EINVAL);
-
-  // A thread can be joined only once
-  if(t->join_thread)   
-    return_errno(FALSE, EACCES);   
-
-  // Wait for the thread to complete
-  tdebug( "thread state: %d\n" ,t->state);
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  if(t->state != ZOMBIE) {
-    t->join_thread = current_thread;
-    mcs_lock_unlock(&thread_lock, &local_qn);
-       CAP_SET_SYSCALL();
-    thread_suspend_self(0);
-    CAP_CLEAR_SYSCALL();
-    mcs_lock_lock(&thread_lock, &local_qn);
-  }
-
-  // Set the return value
-  if(ret != NULL) 
-    *ret = t->ret;
-
-  // Free the memory associated with the joined thread. 
-  __free_thread_prep(t);
-  mcs_lock_unlock(&thread_lock, &local_qn);
-  free_thread(t);
-
-  tdebug("Exit\n");
-  return TRUE;
-}
-
-// Only resume the thread internally
-// Don't touch the timeout flag and the sleep queue
-// Call to this needs to be protected by the thread_lock
-static void __thread_make_runnable(thread_t *t)
-{
-  tdebug("Enter\n");
-  tdebug("t=%p\n",t);
-  if (t->state != SUSPENDED)
-    return;
-
-  assert(t->state == SUSPENDED);
-  assert( t->sleep == -1 );
-  t->state = RUNNABLE;
-  num_threads.suspended--;
-  num_threads.runnable++;
-  sched_add_thread(t);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-
-  tdebug("Exit\n");
-}
-
-// Resume a sleeping thread
-// Call to this needs to be protected by the thread_lock
-static void __thread_resume(thread_t *t)
-{
-  // Remove the thread from the sleep queue
-  if (t->sleep != -1)
-    sleepq_remove_thread(t);
-
-  // Make the thread runnable
-  __thread_make_runnable(t);
-}
-
-void thread_resume(thread_t *t)
-{
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  __thread_resume(t);
-  bool requestcore = __query_vcore_request();
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  // Maybe request a new vcore if we are running low
-  if(requestcore) vcore_request(1);
-}
-
-void thread_set_detached(thread_t *t)
-{
-  if(!t->joinable)
-    return;
-  
-  struct mcs_lock_qnode local_qn = {0};
-  mcs_lock_lock(&thread_lock, &local_qn);
-  t->joinable = 0;
-  num_threads.detached++;
-  mcs_lock_unlock(&thread_lock, &local_qn);
-
-  tdebug("running: %d, runnable: %d, suspended: %d, detached: %d\n", 
-         num_threads.running, num_threads.runnable, 
-         num_threads.suspended, num_threads.detached);
-}
-
-inline char* thread_name(thread_t *t)
-{
-  return t->name;
-}
-
-void thread_exit_program(int exitcode)
-{
-  raise( SIGINT );
-  syscall(SYS_proc_destroy, exitcode);
-}
-
-// Thread attribute handling
-thread_attr_t thread_attr_of(thread_t *t) {
-  thread_attr_t attr = (thread_attr_t)malloc(sizeof(struct _thread_attr));
-  attr->thread = t;
-  return attr;
-}
-
-thread_attr_t thread_attr_new()
-{
-  thread_attr_t attr = (thread_attr_t)malloc(sizeof(struct _thread_attr));
-  attr->thread = NULL;
-  thread_attr_init(attr);
-  return attr;
-}
-
-int thread_attr_init(thread_attr_t attr)
-{
-  if (attr == NULL)
-    return_errno(FALSE, EINVAL);
-  if (attr->thread)
-    return_errno(FALSE, EPERM);
-  attr->joinable = TRUE;
-  return TRUE;
-}
-
-int thread_attr_set(thread_attr_t attr, int field, ...)
-{
-  va_list ap;
-  int rc = TRUE;
-  if(attr == NULL) 
-    return EINVAL;
-
-  va_start(ap, field);
-  switch (field) {
-  case THREAD_ATTR_JOINABLE: {
-    int val = va_arg(ap, int);
-    if(attr->thread == NULL) {
-      if( val == THREAD_CREATE_JOINABLE ) 
-        attr->joinable = TRUE;
-      else
-        attr->joinable = FALSE;
-    } else {
-      if( val == THREAD_CREATE_JOINABLE ) 
-        attr->thread->joinable = 1;
-      else
-        attr->thread->joinable = 0;
-    }
-    break;
-  }
-  default:
-    notimplemented(thread_attr_set);
-  }
-  va_end(ap);
-  return rc;
-}
-
-int thread_attr_get(thread_attr_t attr, int field, ...) 
-{
-  va_list ap;
-  int rc = TRUE;
-  va_start(ap, field);
-  switch (field) {
-  case THREAD_ATTR_JOINABLE: {
-    int *val = va_arg(ap, int *);
-    int joinable = (attr->thread == NULL) ? attr->joinable : attr->thread->joinable;
-    *val = joinable ? THREAD_CREATE_JOINABLE : THREAD_CREATE_DETACHED;
-  }
-  default:
-    notimplemented(thread_attr_get);
-  }
-  va_end(ap);
-  return rc;
-}
-
-int thread_attr_destroy(thread_attr_t attr)
-{
-  free(attr);
-  return TRUE;
-}
-
-// Thread-specific storage
-struct thread_keytab_st {
-    int used;
-    void (*destructor)(void *);
-};
-
-static struct thread_keytab_st thread_keytab[THREAD_KEY_MAX];
-
-int thread_key_create(thread_key_t *key, void (*func)(void *))
-{
-    for ((*key) = 0; (*key) < THREAD_KEY_MAX; (*key)++) {
-        if (thread_keytab[(*key)].used == FALSE) {
-            thread_keytab[(*key)].used = TRUE;
-            thread_keytab[(*key)].destructor = func;
-            return TRUE;
-        }
-    }
-    return_errno(FALSE, EAGAIN);
-}
-
-int thread_key_delete(thread_key_t key)
-{
-    if (key >= THREAD_KEY_MAX)
-        return_errno(FALSE, EINVAL);
-    if (!thread_keytab[key].used)
-        return_errno(FALSE, EINVAL);
-    thread_keytab[key].used = FALSE;
-    return TRUE;
-}
-
-int thread_key_setdata(thread_key_t key, const void *value)
-{
-    if (key >= THREAD_KEY_MAX)
-        return_errno(FALSE, EINVAL);
-    if (!thread_keytab[key].used)
-        return_errno(FALSE, EINVAL);
-    if (current_thread->key_data_value == NULL) {
-        current_thread->key_data_value = (const void **)calloc(1, sizeof(void *)*THREAD_KEY_MAX);
-        if (current_thread->key_data_value == NULL)
-            return_errno(FALSE, ENOMEM);
-    }
-    if (current_thread->key_data_value[key] == NULL) {
-        if (value != NULL)
-            current_thread->key_data_count++;
-    }
-    else {
-        if (value == NULL)
-            current_thread->key_data_count--;
-    }
-    current_thread->key_data_value[key] = value;
-    return TRUE;
-}
-
-void *thread_key_getdata(thread_key_t key)
-{
-    if (key >= THREAD_KEY_MAX)
-        return_errno(NULL, EINVAL);
-    if (!thread_keytab[key].used)
-        return_errno(NULL, EINVAL);
-    if (current_thread->key_data_value == NULL)
-        return NULL;
-    return (void *)current_thread->key_data_value[key];
-}
-
-void thread_key_destroydata(thread_t *t)
-{
-    void *data;
-    int key;
-    int itr;
-    void (*destructor)(void *);
-
-    if (t == NULL)
-        return;
-    if (t->key_data_value == NULL)
-        return;
-    /* POSIX thread iteration scheme */
-    for (itr = 0; itr < THREAD_DESTRUCTOR_ITERATIONS; itr++) {
-        for (key = 0; key < THREAD_KEY_MAX; key++) {
-            if (t->key_data_count > 0) {
-                destructor = NULL;
-                data = NULL;
-                if (thread_keytab[key].used) {
-                    if (t->key_data_value[key] != NULL) {
-                        data = (void *)t->key_data_value[key];
-                        t->key_data_value[key] = NULL;
-                        t->key_data_count--;
-                        destructor = thread_keytab[key].destructor;
-                    }
-                }
-                if (destructor != NULL)
-                    destructor(data);
-            }
-            if (t->key_data_count == 0)
-                break;
-        }
-        if (t->key_data_count == 0)
-            break;
-    }
-    free(t->key_data_value);
-    t->key_data_value = NULL;
-    return;
-}
-
-unsigned thread_tid(thread_t *t)
-{
-  return t ? t->tid : 0xffffffff;
-}
-
-int __attribute__((unused)) print_sleep_queue(void)
-{
-  linked_list_entry_t *e; 
-  unsigned long long _total = 0; 
-  e = ll_view_head(sleepq);
-
-  while (e) {
-    thread_t *tt = (thread_t *)pl_get_pointer(e);
-    _total += tt->sleep;
-    output(" %s:  %lld   (%lld)\n", tt->name ? tt->name : "null", tt->sleep, _total );
-    e = ll_view_next(sleepq, e);
-  }
-  return 1;
-}
-
-/**
- * Put a thread to sleep for the specified timeout 
- **/
-void thread_usleep(unsigned long long timeout)
-{
-  thread_suspend_self(timeout);
-}
-
-/**
- * Check sleep queue to wake up all timed-out threads
- * sync == TRUE -> force synchronization of last_check_time
- **/
-static void sleepq_check_wakeup(int sync)
-{
-  // Shortcut to return if no threads sleeping
-  if (!sync && sleep_times.max == 0) {  
-    sleep_times.first_wake = 0;
-    return;
-  }
-
-  // Get interval since last check time and update 
-  // last check time to now
-  unsigned long long now;
-  long long interval;
-  now = current_usecs();
-  if( now > sleep_times.last_check ) 
-    interval = now-sleep_times.last_check;
-  else 
-    interval = 0;
-  sleep_times.last_check = now;
-
-  // Adjust max_sleep_time based on the interval just computed
-  if (sleep_times.max < (unsigned long long)interval)
-    sleep_times.max = 0;
-  else
-    sleep_times.max -= interval;
-  
-  // Walk through the sleepq and pull off and resume all threads
-  // whose remaining sleep time is less than the interval since 
-  // the last check. If it's greater, update the remaining sleep time
-  // and set first_wake to now + the new sleep time.
-  linked_list_entry_t *e;
-  struct mcs_lock_qnode local_qn = {0};
-  while (interval > 0 && (e = ll_view_head(sleepq))) {
-    thread_t *t = (thread_t *)pl_get_pointer(e);
-
-    if (t->sleep > interval) {
-      t->sleep -= interval;
-      sleep_times.first_wake = now + t->sleep;
-      break;
-    }
-
-    interval -= t->sleep;
-    t->sleep = -1;
-    t->timeout = 1;
-
-    mcs_lock_lock(&thread_lock, &local_qn);
-    ll_free_entry(sleepq, ll_remove_head(sleepq));
-    __thread_make_runnable(t);
-    mcs_lock_unlock(&thread_lock, &local_qn);
-  }
-
-  if (ll_size(sleepq) == 0) {
-     // the sleepq is empty again
-     sleep_times.first_wake = 0;
-  }
-}
-
-/**
- * Set a timer on a thread that will wake up after timeout
- * microseconds.  This is used to implement thread_suspend_self(timeout)
- **/
-static void sleepq_add_thread(thread_t *t, unsigned long long timeout)
-{
-  // Make sure the current thread doesn't already have a sleep time set
-  assert(t->sleep == -1);
-
-  // No need to grab the sleepq_lock before making the following function
-  // call, as calls to this function should already be protected by it.
-  sleepq_check_wakeup(TRUE); // make sure: last_check_time == now
-  
-  // If the tieout is greater than the maximum sleep time of the 
-  // longest sleeping thread, update the maximum, set the sleep
-  // time of the thread (relative to all inserted before it), and
-  // update the max sleep time
-  if (timeout >= sleep_times.max) {
-    // Set sleep_times.first_wake if this is the first item
-    if( pl_view_head(sleepq) == NULL )
-      sleep_times.first_wake = current_usecs() + timeout;
-
-    // Just append the thread to the end of sleep queue
-    pl_add_tail(sleepq, t);
-    t->sleep = timeout - sleep_times.max;
-    assert( t->sleep >= 0 );
-    sleep_times.max = timeout;
-    return;
-  }
-
-  // Otherwise we need to find the proper place to insert the thread in
-  // the sleep queue, given its timeout length. 
-  // We search the list backwards.
-  linked_list_entry_t *e;
-  long long total_time;
-  e = ll_view_tail(sleepq);
-  total_time = sleep_times.max;
-  while (e) {
-    thread_t *tt = (thread_t *)pl_get_pointer(e);
-    assert(tt->sleep >= 0);
-    total_time -= tt->sleep;
-
-    assert (total_time >= 0); // can be == 0 if we are adding the head item
-    if ((unsigned long long)total_time <= timeout) {
-      // insert t into the queue
-      linked_list_entry_t *newp = ll_insert_before(sleepq, e);
-      pl_set_pointer(newp, t);
-      t->sleep = timeout - total_time;
-      assert( t->sleep > 0 );
-
-      // set sleep_times.first_wake if this is the first item
-      if( total_time == 0 )
-        sleep_times.first_wake = current_usecs() + timeout;
-
-      // update the sleep time of the thread right after t
-      tt->sleep -= t->sleep;
-      assert( tt->sleep > 0 );
-      break;
-    }
-    e = ll_view_prev(sleepq, e);
-  }
-
-  // We're sure to find such an e
-  assert (e != NULL);
-}
-
-/**
- * Remove a sleeping thread from the sleep queue before
- * its timer expires.
- **/
-inline static void sleepq_remove_thread(thread_t *t)
-{
-  // The thread must be in the sleep queue
-  assert(t->sleep >= 0);  
-  
-  // Let's find the thread in the queue
-  linked_list_entry_t *e;
-  e = ll_view_head(sleepq);
-  while (e) {
-    thread_t *tt = (thread_t *)pl_get_pointer(e);
-    if (tt == t) {
-      linked_list_entry_t *nexte = ll_view_next(sleepq, e);
-      if (nexte) {
-           // e is not the last thread in the queue
-           // we need to lengthen the time the next thread will sleep
-           thread_t *nextt = (thread_t *)pl_get_pointer(nexte);
-           nextt->sleep += t->sleep;
-      } else {
-           // e is the last thread, so we need to adjust max_sleep_time
-           sleep_times.max -= t->sleep;
-      }
-      // remove t
-      ll_remove_entry(sleepq, e);
-      ll_free_entry(sleepq, e);
-      t->sleep = -1;
-      assert (!t->timeout);    // if this fails, someone must have
-                               // forgotten to reset timeout some time ago
-      break;
-    }
-    e = ll_view_next(sleepq, e);
-  }
-  assert( t->sleep == -1);
-  assert (e != NULL);   // we must find t in sleep queue
-}
-
-/**
- * Set the IO polling function.  Used by the aio routines.  Shouldn't
- * be used elsewhere.
- **/
-void set_io_polling_func(void (*func)(long long))
-{
-  assert( !io_polling_func );
-  io_polling_func = func;
-}
-
-
-/******************************************************************************/
-/****************************** Helper Functions ******************************/
-/******************************************************************************/
-
-static int get_stack_size_kb_log2(void *func)
-{
-  int result = conf_new_stack_kb_log2;
-  if (start_node_addrs != NULL) {
-    int i = 0;
-    while (start_node_addrs[i] != NULL && start_node_addrs[i] != func) {
-      i++;
-    }
-    if (start_node_addrs[i] == func) {
-      result = start_node_stacks[i];
-    } else {
-      fatal("Couldn't find stack size for thread entry point %p\n", func);
-    }
-  }
-  return result;
-}
-
-
diff --git a/user/c3po/threads/threadlib.h b/user/c3po/threads/threadlib.h
deleted file mode 100644 (file)
index 708b749..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-
-#ifndef THREADLIB_H
-#define THREADLIB_H
-
-#include "pthread.h"
-#include "resource_stats.h"
-#include <stdbool.h>
-#include <time.h>
-#include <signal.h>
-
-#define likely(x)   __builtin_expect(!!(x),1)
-#define unlikely(x) __builtin_expect(!!(x),0)
-
-struct thread_st;
-typedef struct thread_st thread_t;
-
-typedef enum {
-  UNLOCKED = 0,
-  LOCKED   = 1,
-} lock_state_t;
-
-typedef struct latch_st {
-  thread_t *state;
-} latch_t;
-
-// Queue used for mutex implementation
-typedef struct queue_st {
-  void **data;   /* allocated data */
-  int size;  /* allocated size */
-  int head, tail;   /* valid data in [head, tail) */
-} queue_t;
-
-typedef struct {
-  latch_t latch;
-  lock_state_t state;
-  int count;   // for recursive locking
-  char *name;
-  queue_t wait_queue;
-  thread_t *owner;   // for sanity checking in thread_mutex_unlock()
-} mutex_t;
-
-// the read-write lock structure
-typedef struct rwlock_st { /* not hidden to avoid destructor */
-  int            rw_state;
-  unsigned int   rw_mode;
-  unsigned long  rw_readers;
-  mutex_t    rw_mutex_rd;
-  mutex_t    rw_mutex_rw;
-} rwlock_t;
-
-// the condition variable structure
-typedef struct cond_st { /* not hidden to avoid destructor */
-  unsigned long cn_state;
-  unsigned int  cn_waiters;
-  queue_t wait_queue;
-} cond_t;
-
-
-// All thread attributes
-enum {
-  THREAD_ATTR_JOINABLE = 1,
-  THREAD_ATTR_NAME,  // Not implemented
-  THREAD_ATTR_PRIO   // Not implemented
-};
-
-// Thread joinable attribute
-enum {
-  THREAD_CREATE_DETACHED = 0,
-  THREAD_CREATE_JOINABLE = 1
-};
-
-enum {
-       OK = 0,
-       TIMEDOUT = 1,
-       INTERRUPTED = 2,
-};
-
-typedef struct _thread_attr *thread_attr_t;
-
-extern void switch_to_vcore();
-extern void run_next_thread();
-void thread_exit(void *ret);
-void thread_exit_program(int exitcode);
-void thread_yield();
-thread_t *thread_spawn(char *name, void* (*func)(void *), void *arg);
-thread_t *thread_spawn_with_attr(char *name, void* (*func)(void *), 
-                           void *arg, thread_attr_t attr);  // added for pthread layer
-// suspend the thread, optionally for a limited period of time (timeout)
-// timeout == 0 -> suspend infinitely unless resumed by another thread
-// return value: OK if resumed by someone else, TIMEDOUT is timedout
-//               INTERRUPTED is interrupted by a signal
-int thread_suspend_self(unsigned long long timeout);
-
-// resume is made idempotent - resuming an already runnable thread does nothing
-void thread_resume(thread_t* t);
-char* thread_name(thread_t *t);
-int thread_join(thread_t *t, void **val);
-void thread_set_daemon(thread_t *t);
-
-extern __thread thread_t *current_thread;
-static inline thread_t* thread_self() { return current_thread; }
-
-// Key-based thread specific storage
-typedef int thread_key_t;
-#define THREAD_DESTRUCTOR_ITERATIONS 4
-#define THREAD_KEY_MAX 256  // NOTE: change the size of thread_t.data_count if you change this!
-int thread_key_create(thread_key_t *key, void (*destructor)(void *));
-int thread_key_delete(thread_key_t key);
-int thread_key_setdata(thread_key_t key, const void *value);
-void *thread_key_getdata(thread_key_t key);
-
-void thread_usleep(unsigned long long timeout);
-
-// Mutex - return TRUE on success
-int thread_mutex_init(mutex_t *m, char *name);
-int thread_mutex_lock(mutex_t *m);
-int thread_mutex_trylock(mutex_t *m);    // do not block, return FALSE when mutex held but others
-int thread_mutex_unlock(mutex_t *m);
-
-// Rwlocks
-enum rwlock_op {
-  RWLOCK_RD = 1,
-  RWLOCK_RW
-};
-
-int thread_rwlock_init(rwlock_t *l);
-int thread_rwlock_lock(rwlock_t *l, int op);
-int thread_rwlock_trylock(rwlock_t *l, int op);
-int thread_rwlock_unlock(rwlock_t *l);
-
-// Condition variables
-int thread_cond_init(cond_t *c);
-int thread_cond_wait(cond_t *c, mutex_t *m);
-int thread_cond_timedwait(cond_t *c, mutex_t *m, const struct timespec *timeout);
-int thread_cond_signal(cond_t *c);
-int thread_cond_broadcast(cond_t *c);
-
-// attribute
-thread_attr_t thread_attr_of(thread_t *t);
-thread_attr_t thread_attr_new();
-int thread_attr_init(thread_attr_t attr);
-int thread_attr_set(thread_attr_t attr, int field, ...);
-int thread_attr_get(thread_attr_t attr, int field, ...);
-int thread_attr_destroy(thread_attr_t attr);
-
-unsigned thread_tid(thread_t *t);
-
-int thread_kill(thread_t* t, int sig);
-int thread_kill_all(int sig);
-int thread_sigwait(const sigset_t *set, int *sig);
-
-extern void thread_stats_add_heap(long size);
-extern void thread_stats_add_fds(int num);
-
-
-typedef struct {
-  long active;
-  long long requests;
-  long long completions;
-  long long bytes_read;
-  long long bytes_written;
-  long long errors;
-} iostats_t;
-
-extern iostats_t sockio_stats;
-extern iostats_t diskio_stats;
-
-#define IOSTAT_START(type) {\
-  type##_stats.active++; \
-  type##_stats.requests++; \
-}
-#define IOSTAT_DONE(type, success) {\
-  type##_stats.active--; \
-  if( (success) ) type##_stats.completions++; \
-  else            type##_stats.errors++; \
-}
-
-extern const char *cap_current_syscall;  // used to inform the BG routines how they got there...
-#define CAP_SET_SYSCALL()   if(!cap_current_syscall) cap_current_syscall = __FUNCTION__
-#define CAP_CLEAR_SYSCALL() (cap_current_syscall = NULL)
-
-extern void set_io_polling_func( void (*func)(long long) );
-
-// latches
-
-// FIXME: if there is a single kernel thread, it is an error if the latch is already locked 
-// FIXME: need a spinlock, test&set, futex, etc. for multiple kernel threads 
-#define LATCH_UNLOCKED NULL
-#define LATCH_UNKNOWN ((thread_t*)-1)
-#if OPTIMIZE < 2
-#define thread_latch(latch) \
-do {\
-  assert(latch.state == LATCH_UNLOCKED); \
-  latch.state = thread_self() ? thread_self() : LATCH_UNKNOWN; \
-} while(0)
-#else
-#define thread_latch(latch) do { } while(0)
-#endif
-#if OPTIMIZE < 2
-#define thread_unlatch(latch) \
-do { \
-  assert(latch.state != LATCH_UNLOCKED); \
-  latch.state = UNLOCKED; \
-} while(0)
-#else
-#define thread_unlatch(latch) do { (void)(latch);} while(0)
-#endif
-
-#if OPTIMIZE < 2
-#define thread_latch_init(latch) \
-do { \
-  latch.state = LATCH_UNLOCKED; \
-} while(0)
-#else
-#define thread_latch_init(latch) do {(void)(latch);} while(0)
-#endif
-
-#define LATCH_INITIALIZER_UNLOCKED { LATCH_UNLOCKED }
-#define LATCH_INITIALIZER_LOCKED   { LATCH_UNKNOWN }
-
-#endif /* THREADLIB_H */
-
-
-
diff --git a/user/c3po/threads/threadlib_internal.h b/user/c3po/threads/threadlib_internal.h
deleted file mode 100644 (file)
index 570b5be..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-
-#ifndef THREADLIB_INTERNAL_H
-#define THREADLIB_INTERNAL_H
-
-#include "threadlib.h"
-#include "util.h"
-#include "blocking_graph.h"
-#include "signal.h"
-#include "ucontext.h"
-#ifdef USE_NIO
-#include <libaio.h>
-#endif
-
-// provide a way to adjust the behavior when unimplemented function is called
-#define notimplemented(x) output("WARNING: " #x " not implemented!\n")
-
-// thread attributes
-// This is a separate struct because pthread has API for users to initizalize
-// pthread_attr_t structs before thread creation
-struct _thread_attr {
-  thread_t *thread;    // != NULL when is bound to a thread
-
-  // Attributes below are valid only when thread == NULL
-  int joinable:1;
-  int daemon:1;
-
-  char *name;
-};
-
-#define THREAD_SIG_MAX 32
-
-struct thread_st {
-  unsigned tid;   // thread id, mainly for readability of debug output
-  struct thread_st *self; // pointer to itself 
-  struct u_context *context;
-  void *stack;
-  void *stack_bottom;
-  int stack_fingerprint;
-//  int __errno;       // thread-local errno
-
-  // misc. short fields, grouped to save space
-  enum {
-       RUNNING=0,
-    RUNNABLE,
-    SUSPENDED,
-    ZOMBIE,          // not yet reaped, for joinable threads
-    GHOST            // already freed, no valid thread should be in this state
-  } state:3;
-
-  unsigned int joinable:1;
-  unsigned int key_data_count:8;  // big enough for THREAD_KEY_MAX
-  unsigned int timeout:1;         // whether it is waken up because of timeout
-  unsigned int sig_waiting:1;  // the thread is waiting for a signal (any not blocked in sig_mask). 
-                       // when it arrives, the thread should be waken up and 
-                       // the signal handler should *not* be called
-  short sig_num_received;      // number of signals in sigs_received
-
-#ifdef USE_NIO
-  struct iocb iocb;        // aio control block
-  int ioret;               // i/o ret value, set by polling loop and used by wrapping functions
-  int iocount;            // number of I/O operations done without blocking, used to yield the processor when reached a fixed amount
-#endif
-
-  // startup stuff
-  void* (*initial_func)(void *);
-  void *initial_arg;
-  char *name;
-  int stack_size_kb_log2;
-
-  const void **key_data_value;  // thread specific values
-
-  // stats for the blocking graph.
-  // FIXME: move curr_stats to global var, to save space here.  (only need one anyway)
-  thread_stats_t prev_stats;
-  thread_stats_t curr_stats;
-
-  // per-thread signals
-  // NOTE: external(global) signals are in corresponding global variable
-  sigset_t sig_received;       // per-thread received but unhandled signals
-  sigset_t sig_mask;           // masked signals for this thread
-
-  thread_t *join_thread;   // thread waiting for the completion of the thread
-  void *ret;               // return value, returned to user by thread_join()
-
-  long long sleep;         // relative time for this thread to sleep after the prev one in sleep queue
-                           // -1 means thread is not in the sleep queue
-};
-
-
-extern thread_t *current;
-extern int in_scheduler;
-
-
-// scheduler functions
-#define DECLARE_SCHEDULER(s) \
-  extern void s##_init(void); \
-  extern void s##_add_thread(thread_t *t); \
-  extern thread_t* s##_next_thread(void); 
-
-DECLARE_SCHEDULER(sched_global_rr);
-DECLARE_SCHEDULER(sched_global_lifo);
-DECLARE_SCHEDULER(sched_graph_rr);
-DECLARE_SCHEDULER(sched_graph_rr_down);
-DECLARE_SCHEDULER(sched_graph_batch);
-DECLARE_SCHEDULER(sched_graph_highnum);
-DECLARE_SCHEDULER(sched_graph_priority);
-
-extern void sched_graph_generic_init(void);
-extern void sched_graph_generic_add_thread(thread_t *t);
-
-#define strong_alias(name, aliasname) extern __typeof (name) aliasname __attribute__ ((alias (#name)));
-#define valid_thread(t) (t != NULL  &&  t != (thread_t*)-1)
-#define thread_alive(t) ((t)->state == RUNNABLE || (t)->state == SUSPENDED)
-
-// Internal constants
-
-#define _BIT(n) (1<<(n))
-#define THREAD_RWLOCK_INITIALIZED _BIT(0)
-
-#define THREAD_COND_INITIALIZED _BIT(0)
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-#ifndef TRUE
-#define TRUE (~FALSE)
-#endif
-
-#define return_errno(return_val,errno_val) \
-        do { errno = (errno_val); \
-             debug("return 0x%lx with errno %d(\"%s\")\n", \
-                        (unsigned long)(return_val), (errno), strerror((errno))); \
-             return (return_val); } while (0)
-
-#define return_errno_unlatch(ret,err,latch) \
-do { \
-  thread_unlatch(latch); \
-  errno = (err); \
-  debug("return 0x%lx with errno %d(\"%s\")\n", (unsigned long)(ret), (err), strerror((err))); \
-  return (ret); \
-} while (0)
-
-
-extern void dump_debug_info();
-extern void dump_thread_state();
-
-extern long long total_stack_in_use;
-
-// process all pending signals.  returns 1 is any actually handled, 0 otherwise
-extern int sig_process_pending();
-
-#endif /* THREADLIB_INTERNAL_H */
diff --git a/user/c3po/threads/ucontext.c b/user/c3po/threads/ucontext.c
deleted file mode 100644 (file)
index b52aa0b..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <threadlib_internal.h>
-#include <vcore.h>
-#include <ucontext.h>
-
-
-/* Maintain a static reference to the main threads tls region */
-static void *__main_tls_desc;
-
-struct u_context* create_context(thread_t *t, void *entry_pt, void *stack_top)
-{
-       uint32_t vcoreid = vcore_id();
-
-       /* Allocate a new context struct */
-       /* TODO: careful of alignment here */
-       struct u_context *uc = malloc(sizeof(struct u_context));
-       if(!uc) return NULL;
-
-       /* If we are the main thread, then current_thread has not been set yet, so
-        * we set the tls descriptor to the tls on the currently running core */
-       if(current_thread == NULL) {
-               /* Make sure this only executes once! */
-               static int done = FALSE;
-               assert(!done); done = TRUE;
-
-               /* Set up the tls regions for the main thred */
-               uc->tls_desc = get_tls_desc(vcoreid);
-               __main_tls_desc = uc->tls_desc;
-
-               /* And set the current thread in this tls region */
-               current_thread = t;
-       }
-    /* Otherwise, allocate a new tls region for this context */
-       else {
-               /* Allocate the tls, freeing the whole uc if it fails */
-       uc->tls_desc = allocate_tls();
-               if(!uc->tls_desc) {
-                       free(uc);
-                       return NULL;
-               }
-               /* Temporarily switch into the new the context's tls region to set the
-                * current_thread variable in that tls region */
-               void *temp_tls = get_tls_desc(vcoreid);
-               set_tls_desc(uc->tls_desc, vcoreid);
-               current_thread = t;
-               /* Then switch back to the origin one */
-               set_tls_desc(temp_tls, vcoreid);
-       }
-
-       /* For good measure, also save the thread associated with this context in
-        * the ucontext struct */
-       uc->thread = t;
-
-       /* Initialize the trapframe for this context */
-       init_user_ctx(&uc->u_ctx, (uint32_t)entry_pt, (uint32_t)stack_top);
-       return uc;
-}
-
-void save_context(struct u_context *uc)
-{
-       /* Save the trapframe for this context */
-       save_user_ctx(&uc->u_ctx);
-}
-
-void restore_context(struct u_context *uc)
-{
-       uint32_t vcoreid = vcore_id();
-
-       /* Save the thread we are about to restore into current_thread
-        * in this vcores tls region */
-       current_thread = uc->thread;
-       /* Set the proper tls descriptor for the context we are restoring */
-    set_tls_desc(uc->tls_desc, vcoreid);
-       /* Tell the uthread which vcore it is on */
-       __vcoreid = vcoreid;
-       /* Pop the trapframe */
-       pop_user_ctx(&uc->u_ctx, vcoreid);
-}
-
-void destroy_context(struct u_context *uc)
-{
-    extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
-
-       /* Make sure we have passed in Non-Null pointers for our ucontext / tls */
-    assert(uc);
-    assert(uc->tls_desc);
-
-       /* Dont' deallocate the main tls descriptor, glibc will do that */
-       if(uc->tls_desc != __main_tls_desc)
-       _dl_deallocate_tls(uc->tls_desc, TRUE);
-       free(uc);
-}
-
-void print_context(struct u_context *uc)
-{
-       printf("GIANT WARNING: this assumes a HW ctx\n");
-       /* Just print the trapframe */
-       print_hw_tf(&uc->u_ctx.tf.hw_tf);
-}
-
diff --git a/user/c3po/threads/ucontext.h b/user/c3po/threads/ucontext.h
deleted file mode 100644 (file)
index ac32bfa..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef UCONTEXT_H
-#define UCONTEXT_H
-
-#include <stdint.h>
-#include <ros/trapframe.h>
-#include <threadlib_internal.h>
-struct u_context {
-       /* this seems rather screwed up, not inheriting a uthread */
-       struct user_context u_ctx;
-    void *tls_desc;
-       thread_t *thread;
-}; 
-
-struct u_context* create_context(thread_t *t, void *entry_pt, void *stack_top);
-void save_context(struct u_context *uc);
-void restore_context(struct u_context *uc);
-void destroy_context(struct u_context *uc);
-void print_context(struct u_context *uc);
-
-#endif
diff --git a/user/c3po/threads/vcore.c b/user/c3po/threads/vcore.c
deleted file mode 100644 (file)
index a9b7182..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#include <vcore.h>
-#include <mcs.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <parlib.h>
-#include <ros/event.h>
-#include <arch/atomic.h>
-#include <arch/arch.h>
-#include <sys/queue.h>
-#include <sys/mman.h>
-#include <event.h>
-#include <threadlib_internal.h>
-#include <threadlib.h>
-
-// Comment out, to enable debugging in this file
-#ifndef DEBUG_threadlib_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-// Thread local pointer to the user thread currently running on a given core. 
-// This variable is only meaningful to the context running
-// the scheduler code (i.e. vcore context in ROS, user thread or scheduler
-// context on linux depending on whether we use a scheduler thread or not)
-__thread thread_t* current_thread=NULL;
-
-/**
- * Bootup constructors.  Make sure things are initialized in the proper order.
- * Ideally we would be able to use the contsructor priorities instead of having
- * to call them all back to back like this, but for some reason I couldn't get
- * them to work properly. I.e. the priorities weren't being honored.
- **/
-extern void read_config();
-extern void main_thread_init();
-extern void vcore_startup();
-void __attribute__ ((constructor)) ctors()
-{
-       
-//     init_cycle_clock();
-       read_config();
-       main_thread_init();
-       vcore_startup();
-}
-
-       
-       //uint32_t vc = vcore_id();
-       //uint32_t kvc = ros_syscall(SYS_getvcoreid, 0, 0, 0, 0, 0, 0);
-       //set_tls_desc(vcore_thread_control_blocks[vcoreid], vcoreid);
-       ///* Verify that the currently running thread is the one that the vcore thought
-       // * was running */
-       //if(current_thread != t)
-       //      printf("variable:\tthread:vcore\n"
-       //             "current_thread:\t%p:%p\n"
-       //             "vcore_id:\t%p:%p\n"
-       //             "SYS_getvcoreid:\t%p:%p\n",
-       //             t, current_thread, vc, vcore_id(), kvc, ros_syscall(SYS_getvcoreid, 0, 0, 0, 0, 0, 0)
-       //            );
-       //assert(current_thread == t);
-
-/**
- * Initialize the vcores, including jumping into muticore mode.
- **/
-void vcore_startup()
-{
-       /* Initilize the bootstrap code for using the vcores */
-       vcore_init();
-       assert(vcore_id() == 0);
-
-       /* Tell the kernel where and how we want to receive events.  This is just an
-        * example of what to do to have a notification turned on.  We're turning on
-        * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
-        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid and
-        * private preference.  Also note that enable_kevent() is just an example,
-        * and you probably want to use parts of event.c to do what you want. */
-       enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
-
-       /* Grab a reference to the main_thread on the current stack (i.e.
-        * current_thread, since we know this has been set up for us properly by
-        * the fact that the constructor calls main_thread_init() before this
-        * function.  We will need this reference below. */
-       thread_t *t = current_thread;
-
-    /* Change temporarily to vcore0s tls region so we can save the main_thread
-        * into its thread local current_thread variable.  One minor issue is that
-        * vcore0's transition-TLS isn't TLS_INITed yet.  Until it is (right before
-        * vcore_entry(), don't try and take the address of any of its TLS vars. */
-       extern void** vcore_thread_control_blocks;
-       set_tls_desc(vcore_thread_control_blocks[0], 0);
-       current_thread = t;
-       set_tls_desc(t->context->tls_desc, 0);
-
-       /* Jump into multi-core mode! */
-       /* The next line of code that will run is inside vcore_entry().  When this
-        * thread is resumed, it will continue directly after this call to
-        * vcore_change_to_m() */
-       vcore_change_to_m();
-}
-
-/**
- * Switch into vcore mode to run the scheduler code. 
- **/
-void switch_to_vcore() {
-
-       uint32_t vcoreid = vcore_id();
-
-       /* Disable notifications.  Once we do this, we might miss a notif_pending,
-        * so we need to enter vcore entry later.  Need to disable notifs so we
-        * don't get in weird loops */
-       struct preempt_data *vcpd = vcpd_of(vcoreid);
-       vcpd->notif_disabled = TRUE;
-
-       /* Grab a reference to the currently running thread on this vcore */
-       thread_t *t = current_thread; 
-
-       /* Switch to the vcore's tls region */
-       extern void** vcore_thread_control_blocks;
-       set_tls_desc(vcore_thread_control_blocks[vcoreid], vcoreid);
-       
-       /* Verify that the thread the vcore thinks was running is the same as the thread
-        * that was actually running */
-       assert(current_thread == t);
-
-       /* Set the stack pointer to the stack of the vcore. 
-        * We know this function is always inlined because of the attribute we set
-        * on it, so there will be no stack unwinding when this function "returns".
-        * After this call, make sure you don't use local variables. */
-       set_stack_pointer((void*)vcpd->transition_stack);
-       assert(in_vcore_context());
-
-       /* Leave the current vcore completely */
-       current_thread = NULL; 
-       
-       /* Restart the vcore and run the scheduler code */
-       vcore_entry();
-       assert(0);
-}
-
-/**
- * Entry point for the vcore.  Basic job is to either resume the thread that
- * was interrupted in the case of a notification coming in, or to find a new
- * thread from the user level threading library and launch it.
- **/
-void __attribute__((noreturn)) vcore_entry()
-{
-       /* Grab references to the current vcoreid vcore preemption data, and the
-     * vcoremap */
-       assert(in_vcore_context());
-       uint32_t vcoreid = vcore_id();
-       struct preempt_data *vcpd = vcpd_of(vcoreid);
-       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
-
-       tdebug("current=%s, vcore=%d\n",
-               current_thread?current_thread->name : "NULL", vcoreid);
-
-       /* Assert that notifications are disabled. Should always have notifications
-        * disabled when coming in here. */
-       assert(vcpd->notif_disabled == TRUE);
-
-       /* Put this in the loop that deals with notifications.  It will return if
-        * there is no preempt pending. */ 
-       if (vc->preempt_pending)
-               sys_yield(TRUE);
-
-       /* When running vcore_entry(), we are using the TLS of the vcore, not any
-        * particular thread.  If current_thread is set in the vcore's TLS, then 
-        * that means the thread did not yield voluntarily, and was, instead, 
-        * interrupted by a notification.  We therefore need to restore the thread
-        * context from the notification trapframe, not the one stored in the 
-        * thread struct itself. */
-    if (unlikely(current_thread)) {
-        vcpd->notif_pending = 0;
-        /* Do one last check for notifs after clearing pending */
-        // TODO: call the handle_notif() here (first)
-
-               /* Copy the notification trapframe into the current 
-                * threads trapframe */
-               memcpy(&current_thread->context->u_ctx, &vcpd->uthread_ctx, 
-                      sizeof(struct user_context));
-
-        /* Restore the context from the current_thread's trapframe */
-        restore_context(current_thread->context);
-        assert(0);
-    }
-
-       /* Otherwise either a vcore is coming up for the first time, or a thread
-        * has just yielded and vcore_entry() was called directly. In this case we 
-        * need to figure out which thread to schedule next on the vcore */
-       run_next_thread();
-       assert(0);
-}
-
diff --git a/user/c3po/util/Makefrag b/user/c3po/util/Makefrag
deleted file mode 100644 (file)
index f8d1395..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-UTIL_NAME    := util
-UTIL_UCNAME  := $(call uc, $(UTIL_NAME))
-UTIL_CFLAGS  := $(CFLAGS_USER)
-UTIL_HEADERS := $(wildcard $(UTILDIR)/*.h)
-UTIL_CFILES  := $(wildcard $(UTILDIR)/*.c)
-UTIL_OBJDIR  := $(OBJDIR)/$(UTIL_NAME)
-UTIL_OBJS    := $(patsubst %.c, %.o, $(UTIL_CFILES))
-UTIL_OBJS    := $(foreach x, $(UTIL_OBJS), $(UTIL_OBJDIR)/$(call filename,$(x)))
-
-LIBUTIL = $(UTIL_OBJDIR)/lib$(UTIL_NAME).a
-
-$(UTIL_NAME)-clean:
-       @echo + clean [$(LIBUCNAME) $(UTIL_UCNAME)]
-       $(Q)rm -rf $(UTIL_OBJS) $(LIBUTIL)
-       $(Q)rm -rf $(UTIL_OBJDIR)
-
-$(LIBUTIL): $(UTIL_OBJS)
-       @echo + ar [$(LIBUCNAME) $(UTIL_UCNAME)] $@
-       $(Q)$(AR) rc $@ $^
-
-$(UTIL_OBJDIR)/%.o: $(UTILDIR)/%.c $(UTIL_HEADERS)
-       @echo + cc [$(LIBUCNAME) $(UTIL_UCNAME)] $<
-       @mkdir -p $(@D)
-       $(Q)$(CC) $(UTIL_CFLAGS) $(INCS) -o $@ -c $<
-
diff --git a/user/c3po/util/atomic.h b/user/c3po/util/atomic.h
deleted file mode 100644 (file)
index 546e78f..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Assembly language for x86 atomic operations.  These were coopted
- * from the glibc include files for linux, as noted below.  We have
- * included them here (unmodified) because the include files only
- * define them when in kernel mode.
- **/
-
-#include <unistd.h>
-#include <ros/syscall.h>
-
-// from /usr/include/asm/linux/autoconf.h
-#define CONFIG_SMP 1
-#ifdef CONFIG_SMP
-#define LOCK_PREFIX "lock ; "
-#else
-#define LOCK_PREFIX ""
-#endif
-
-
-// Everything below is from /usr/include/asm/system.h
-
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- *       but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-       switch (size) {
-               case 1:
-                       __asm__ __volatile__("xchgb %b0,%1"
-                               :"=q" (x)
-                               :"m" (*__xg(ptr)), "0" (x)
-                               :"memory");
-                       break;
-               case 2:
-                       __asm__ __volatile__("xchgw %w0,%1"
-                               :"=r" (x)
-                               :"m" (*__xg(ptr)), "0" (x)
-                               :"memory");
-                       break;
-               case 4:
-                       __asm__ __volatile__("xchgl %0,%1"
-                               :"=r" (x)
-                               :"m" (*__xg(ptr)), "0" (x)
-                               :"memory");
-                       break;
-       }
-       return x;
-}
-
-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
-
-static inline void spinlock_lock(int *ptr) 
-{ 
-  while( 1 ) {
-    register int i=1000;
-    while( i && (tas(ptr) == 1) ) 
-      i--; 
-    if( i ) 
-      return;
-    syscall(SYS_yield);
-  }
-}
-#define spinlock_unlock(ptr) { *(ptr)=0; }
-
-
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                     unsigned long new, int size)
-{
-       unsigned long prev;
-       switch (size) {
-       case 1:
-               __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
-                                    : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                                    : "memory");
-               return prev;
-       case 2:
-               __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
-                                    : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                                    : "memory");
-               return prev;
-       case 4:
-               __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
-                                    : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
-                                    : "memory");
-               return prev;
-       }
-       return old;
-}
-/*
-int atomic_h_mutex=0;
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-                                     unsigned long new, int size)
-{
-  unsigned long ret;
-  (void) size;
-  spinlock_lock( &atomic_h_mutex );
-  // assume size == sizeof(long)
-  if( *((unsigned long*)ptr) == old ) {
-    *((unsigned long*)ptr) = new;
-    ret = old;
-  } else {
-    ret = *((unsigned long*)ptr);
-  }
-  spinlock_unlock( &atomic_h_mutex );
-  return ret;
-}
-*/
-
-#define cmpxchg(ptr,o,n)\
-       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-                                       (unsigned long)(n),sizeof(*(ptr))))
-
-
-// FIXME: does this work?
-#define SERIALIZATION_BARRIER() { __asm__("cpuid"); }
diff --git a/user/c3po/util/clock.c b/user/c3po/util/clock.c
deleted file mode 100644 (file)
index 05f4fdb..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * routines for getting timing info from the cycle clock
- **/
-
-//#include <stdio.h>
-#include <sys/time.h>
-#include <sys/syscall.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "clock.h"
-#include "debug.h"
-
-
-#ifdef USE_PERFCTR
-
-// perfctr specific declarations
-static struct vperfctr *self = NULL;
-struct vperfctr *clock_perfctr = NULL;
-
-static struct perfctr_info info;
-static struct vperfctr_control control;
-
-static void init_perfctr() {
-    unsigned int tsc_on = 1;
-    unsigned int nractrs = 1;
-    unsigned int pmc_map0 = 0;
-    unsigned int evntsel0 = 0;
-
-    self = vperfctr_open();
-    clock_perfctr = self;
-    if( !self ) {
-      char *str = "vperfctr_open() failed!!\n";
-      syscall(SYS_write, 2, str, strlen(str));
-      exit(1);
-    }
-    if( vperfctr_info(clock_perfctr, &info) < 0 ) {
-      char *str = "vperfctr_info() failed!!\n";
-      syscall(SYS_write, 2, str, strlen(str));
-      exit(1);
-    }
-
-    memset(&control, 0, sizeof control);
-
-    /* Attempt to set up control to count clocks via the TSC
-       and retired instructions via PMC0. */
-    switch( info.cpu_type ) {
-      case PERFCTR_X86_GENERIC:
-        nractrs = 0;            /* no PMCs available */
-        break;
-      case PERFCTR_X86_INTEL_P5:
-      case PERFCTR_X86_INTEL_P5MMX:
-      case PERFCTR_X86_CYRIX_MII:
-        /* event 0x16 (INSTRUCTIONS_EXECUTED), count at CPL 3 */
-        evntsel0 = 0x16 | (2 << 6);
-        break;
-      case PERFCTR_X86_INTEL_P6:
-      case PERFCTR_X86_INTEL_PII:
-      case PERFCTR_X86_INTEL_PIII:
-      case PERFCTR_X86_AMD_K7:
-      case PERFCTR_X86_AMD_K8:
-        /* event 0xC0 (INST_RETIRED), count at CPL > 0, Enable */
-        evntsel0 = 0xC0 | (1 << 16) | (1 << 22);
-        break;
-      case PERFCTR_X86_WINCHIP_C6:
-        tsc_on = 0;             /* no working TSC available */
-        evntsel0 = 0x02;        /* X86_INSTRUCTIONS */
-        break;
-      case PERFCTR_X86_WINCHIP_2:
-        tsc_on = 0;             /* no working TSC available */
-        evntsel0 = 0x16;        /* INSTRUCTIONS_EXECUTED */
-        break;
-      case PERFCTR_X86_VIA_C3:
-        pmc_map0 = 1;           /* redirect PMC0 to PERFCTR1 */
-        evntsel0 = 0xC0;        /* INSTRUCTIONS_EXECUTED */  
-        break;
-      case PERFCTR_X86_INTEL_P4:
-      case PERFCTR_X86_INTEL_P4M2:
-        /* PMC0: IQ_COUNTER0 with fast RDPMC */
-        pmc_map0 = 0x0C | (1 << 31);
-        /* IQ_CCCR0: required flags, ESCR 4 (CRU_ESCR0), Enable */
-        evntsel0 = (0x3 << 16) | (4 << 13) | (1 << 12);
-        /* CRU_ESCR0: event 2 (instr_retired), NBOGUSNTAG, CPL>0 */
-        control.cpu_control.p4.escr[0] = (2 << 25) | (1 << 9) | (1 << 2);
-        break;
-    default: {
-          char *str = "cpu type not supported - perfctr init failed!!\n";
-          syscall(SYS_write, 2, str, strlen(str));
-          exit(1);
-        }
-    }
-    control.cpu_control.tsc_on = tsc_on;
-    control.cpu_control.nractrs = nractrs;
-    control.cpu_control.pmc_map[0] = pmc_map0;
-    control.cpu_control.evntsel[0] = evntsel0;
-
-    if (!nractrs) {
-      //output("error: your CPU (%s) doesn't support PMC timing\n", perfctr_info_cpu_name(&info));
-      char *str = "error: your CPU doesn't support PMC timing\n";
-      syscall(SYS_write, 2, str, strlen(str));
-      exit(1);
-    }
-
-    // start the perfctr
-    if( vperfctr_control(clock_perfctr, &control) < 0 ) {
-      char *str = "vperfctr_control failed!!!\n";
-      syscall(SYS_write, 2, str, strlen(str));
-      exit(1);
-    }
-}
-
-#endif
-
-
-
-
-/**
- * calibrate the cycle clock to wall-clock time. This is rough, but
- * hopefully good enough for our purposes.
- **/
-
-cpu_tick_t ticks_per_nanosecond  = 6*10e2;
-cpu_tick_t ticks_per_microsecond = 6*10e5;
-cpu_tick_t ticks_per_millisecond = 6*10e8;
-cpu_tick_t ticks_per_second      = 6*10e11;
-cpu_tick_t real_start_ticks = 0;
-cpu_tick_t virtual_start_ticks = 0;
-
-
-#define __usecs(t) (1e6*(long long)t.tv_sec + t.tv_usec)
-
-static long long timing_loop()
-{
-  struct timeval start_tv, end_tv;
-  long usec;
-  cpu_tick_t start_ticks, end_ticks;
-
-  while( 1 ) {
-    // start the counter right when the clock changes
-    gettimeofday(&start_tv, NULL);
-    usec = start_tv.tv_usec;
-    do {
-      gettimeofday(&start_tv, NULL);
-      GET_REAL_CPU_TICKS( start_ticks );
-    } while( start_tv.tv_usec == usec );
-
-    // now do the timing loop
-    do {
-      gettimeofday(&end_tv, NULL);
-      GET_REAL_CPU_TICKS( end_ticks );
-    } while( __usecs(end_tv) < __usecs(start_tv)+1000 );
-
-    if(__usecs(end_tv) == __usecs(start_tv)+1000)
-      break;
-  }
-  
-  return end_ticks - start_ticks;
-}
-
-
-//void init_cycle_clock() __attribute__((constructor));
-void init_cycle_clock(void)
-{
-  static int init_done = 0;
-  int i;
-  long long val = 0;
-
-  if(init_done) return;
-  init_done = 1;
-
-#ifdef USE_PERFCTR
-  init_perfctr();
-#endif
-  
-  // collect some samples
-  for(i=0; i<10; i++) {
-    val += timing_loop();
-  }
-  val = val / 10;
-
-  ticks_per_second      = val * 1e3;
-  ticks_per_millisecond = val * 1e0;
-  ticks_per_microsecond = val / 1e3;
-  ticks_per_nanosecond  = val / 1e6;
-
-  GET_REAL_CPU_TICKS( real_start_ticks );
-  GET_CPU_TICKS( virtual_start_ticks );
-}
-
-
-
-
-/*
-
-#include <sys/time.h>
-#include <unistd.h>
-
-#include "misc.h"
-#include "debug.h"
-
-#ifndef DEBUG_misc_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-long long current_usecs()
-{
-  struct timeval tv;
-  int rv;
-  rv = gettimeofday(&tv,NULL);
-  assert (rv == 0);
-
-  return ((long long)tv.tv_sec * 1000000) + tv.tv_usec;
-}
-
-*/
diff --git a/user/c3po/util/clock.h b/user/c3po/util/clock.h
deleted file mode 100644 (file)
index 3225887..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-
-#ifndef CLOCK_H
-#define CLOCK_H
-
-typedef long long cpu_tick_t;
-
-#define GET_REAL_CPU_TICKS(Var)        __asm__ __volatile__ ("rdtsc" : "=A" (Var))
-// interestingly, without __volatile__, it's slower
-//#define GET_REAL_CPU_TICKS(Var)      __asm__ ("rdtsc" : "=A" (Var))
-
-
-#ifndef USE_PERFCTR
-
-# define TIMING_NOW_64(Var) GET_REAL_CPU_TICKS(Var)
-# define GET_CPU_TICKS(Var) GET_REAL_CPU_TICKS(Var)
-
-#else
-
-#include "libperfctr.h"
-extern struct vperfctr *clock_perfctr;
-#define TIMING_NOW_64(var) var = vperfctr_read_tsc(clock_perfctr)
-#define GET_CPU_TICKS(var) var = vperfctr_read_tsc(clock_perfctr)
-
-#endif
-
-
-extern cpu_tick_t ticks_per_second;
-extern cpu_tick_t ticks_per_millisecond;
-extern cpu_tick_t ticks_per_microsecond;
-extern cpu_tick_t ticks_per_nanosecond;
-extern cpu_tick_t real_start_ticks;
-extern cpu_tick_t virtual_start_ticks;
-
-
-static inline long long current_usecs()
-{
-  register cpu_tick_t ret;
-  GET_REAL_CPU_TICKS( ret );
-  return (ret / ticks_per_microsecond);
-}
-
-void init_cycle_clock(void);
-
-#endif
-
-
diff --git a/user/c3po/util/config.c b/user/c3po/util/config.c
deleted file mode 100644 (file)
index 54d743e..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * 
- * Configure capriccio.  This is done via environment variables which are read at startup.
- *
- **/
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "threadlib.h"
-#include "debug.h"
-#include "config.h"
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-
-// define variables.  These should match config.h
-int conf_no_init_messages = FALSE;
-int conf_dump_blocking_graph = FALSE;
-int conf_dump_timing_info = FALSE;
-int conf_show_thread_stacks = FALSE;
-int conf_show_thread_details = FALSE;
-int conf_no_debug = FALSE;
-int conf_no_stacktrace = FALSE;
-int conf_no_statcollect = FALSE;
-
-long conf_new_stack_size = 128*1024;
-int conf_new_stack_kb_log2 = 7;
-
-static inline int bool_value(char *str)
-{
-  if(str == NULL) return 0;
-  if( atoi(str) ) return 1;
-  if( !strcasecmp(str,"true") ) return 1;
-  if( !strcasecmp(str,"yes") ) return 1;
-  if( !strcasecmp(str,"y") ) return 1;
-  return 0;
-}
-
-#define get_bool(env,var) {\
-  var = bool_value( getenv(__STRING(env)) ); \
-  if( !conf_no_init_messages ) \
-    output("%s=%s\n",__STRING(env), (var ? "yes" : "no")); \
-}  
-
-
-// for now, just read from env vars.  Add config file option later.
-void read_config(void) {
-  static int read_config_done = 0;
-  
-  if( read_config_done ) return;
-  read_config_done = 1;
-
-  // BOOLEAN FLAGS
-  get_bool(CAPRICCIO_NO_INIT_MESSAGES, conf_no_init_messages);
-  get_bool(CAPRICCIO_NO_DEBUG, conf_no_debug);
-  get_bool(CAPRICCIO_NO_STACKTRACE, conf_no_stacktrace);
-  get_bool(CAPRICCIO_NO_STATCOLLECT, conf_no_statcollect);
-
-  get_bool(CAPRICCIO_DUMP_BLOCKING_GRAPH, conf_dump_blocking_graph);
-  get_bool(CAPRICCIO_DUMP_TIMING_INFO, conf_dump_timing_info);
-  get_bool(CAPRICCIO_SHOW_THREAD_DETAILS, conf_show_thread_details);
-
-  // NOTE: this is subbordinate to CAPRICCIO_SHOW_THREAD_DETAILS
-  get_bool(CAPRICCIO_SHOW_THREAD_STACKS, conf_show_thread_stacks);
-
-
-  // STACK SIZE
-  {
-    char *str;
-    str = getenv("CAPRICCIO_DEFAULT_STACK_SIZE");
-    if( str != NULL ) {
-      char *p;
-      int mult=0;
-      long val;
-    
-      // read the value
-      val = strtol(str,&p,0);
-      if( p == str )
-        fatal("Bad number format for CAPRICCIO_DEFAULT_STACK_SIZE: '%s'\n", str); 
-    
-      // read the units
-      while( isspace(*p) ) p++;
-      if( *p == '\0' )
-        mult = 1024; // default to KB
-      else if( *p == 'b' || *p == 'B' )
-        mult = 1;        
-      else if( *p == 'k' || *p == 'K' )
-        mult = 1024;
-      else if( *p == 'm' || *p == 'M' )
-        mult = 1024*1024;
-      else 
-        fatal("Bad units for CAPRICCIO_DEFAULT_STACK_SIZE: '%s'\n",str);
-    
-      // pick the next bigger power of 2
-      // FIXME: allow smaller than 1K?
-      // FIXME: allow not power of 2?
-      conf_new_stack_size = 1024;
-      conf_new_stack_kb_log2 = 0;
-      while( conf_new_stack_size < mult * val ) {
-        conf_new_stack_kb_log2++;
-        conf_new_stack_size = conf_new_stack_size << 1;
-      }
-    }
-
-    if( !conf_no_init_messages ) {
-      // show MB, if big enough, and evenly divisible
-      if( conf_new_stack_size > 1024*1024  &&  !(conf_new_stack_size & 0xFFFFF) )
-        output("CAPRICCIO_DEFAULT_STACKSIZE=%ldM\n",conf_new_stack_size/1024/1024);
-
-      // show KB, if big enough, and evenly divisible
-      else if( conf_new_stack_size > 1024  &&  !(conf_new_stack_size & 0x3FF) )
-        output("CAPRICCIO_DEFAULT_STACKSIZE=%ldK\n",conf_new_stack_size/1024);
-
-      // otherwise, show in bytes
-      else
-        output("CAPRICCIO_DEFAULT_STACKSIZE=%ldb\n",conf_new_stack_size);
-    }
-  }
-
-
-  // FIXME: scan environment for unrecognized CAPRICCIO_* env vars,
-  // and warn about likely misspelling.
-
-}
-
-
-
diff --git a/user/c3po/util/config.h b/user/c3po/util/config.h
deleted file mode 100644 (file)
index 5cc8e97..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-// configuration flags
-extern int conf_no_init_messages;
-extern int conf_dump_blocking_graph;
-extern int conf_dump_timing_info;
-extern int conf_show_thread_stacks;
-extern int conf_show_thread_details;
-extern int conf_no_debug;
-extern int conf_no_stacktrace;
-extern int conf_no_statcollect;
-
-extern long conf_new_stack_size;
-extern int conf_new_stack_kb_log2;
-
-// this is exported so we can force this to be initialized before the
-// threading library.  
-//
-// FIXME: This should really be handled by initializer priorities.
-void read_config(void);
-
-
-#endif // CONFIG_H
diff --git a/user/c3po/util/debug.c b/user/c3po/util/debug.c
deleted file mode 100644 (file)
index 5b22219..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-
-
-/**
- * 
- *  Simple debug routine
- *
- **/
-
-
-#include <ros/syscall.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "debug.h"
-#include "clock.h"
-#include "config.h"
-#include <vcore.h>
-
-
-#define DBG_NO_TIMING -12312
-
-// NOTE: these are externally visible so the blocking graph stats
-// functions can subtract out debug print times.
-cpu_tick_t ticks_diff = 0;
-cpu_tick_t ticks_rdiff = 0;
-
-static cpu_tick_t vnow_prev = 0;
-static cpu_tick_t vrnow_prev = 0;
-
-//void init_debug() __attribute__((constructor));
-void init_debug() {
-  init_cycle_clock();
-  vnow_prev  = virtual_start_ticks;
-  vrnow_prev = real_start_ticks;
-}
-
-static inline void output_aux(int tid, const char *func, const char *fmt, va_list ap)
-{
-  char str[200];
-  int len=0, ret;
-#ifdef USE_PERFCTR
-  cpu_tick_t now,  vnow,  after;
-#endif
-  cpu_tick_t rnow, vrnow, rafter;
-
-  // get times
-  GET_REAL_CPU_TICKS( rnow );
-  vrnow = rnow - ticks_rdiff;
-#ifdef USE_PERFCTR
-  GET_CPU_TICKS( now );
-  vnow = now - ticks_diff;
-#endif
-
-  // add the timing header
-  if( tid != DBG_NO_TIMING ) {
-#ifdef USE_PERFCTR    
-    ret = snprintf(str+len, sizeof(str)-1-len, "%5d %12lld us %12lld us (%+8lld cyc %+8lld cyc): ", 
-                   tid, 
-                   (vnow-virtual_start_ticks)/ticks_per_microsecond, 
-                   (vrnow-real_start_ticks)/ticks_per_microsecond, 
-                   vnow - vnow_prev,  
-                   vrnow - vrnow_prev);
-#else
-    ret = snprintf(str+len, sizeof(str)-1-len, "%5d %12lld us (%+8lld cyc): ", 
-                   tid, 
-                   (vrnow-real_start_ticks)/ticks_per_microsecond, 
-                   vrnow - vrnow_prev);
-#endif
-    assert(ret > 0);
-    len += ret;
-  }
-
-  // add the vcore number
-  if( func ) {
-    ret = snprintf(str+len, sizeof(str)-1-len, "vcore %d - ", vcore_id());
-    assert(ret > 0);
-    len += ret;
-  }
-
-  // add the function name
-  if( func ) {
-    ret = snprintf(str+len, sizeof(str)-1-len, "%s() - ",func);
-    assert(ret > 0);
-    len += ret;
-  }
-
-  // add the message
-  ret = vsnprintf(str+len, sizeof(str)-1-len, fmt, ap);
-  assert(ret > 0);
-  len += ret;
-
-  // output the messag
-  syscall(SYS_write, 2, str, len);
-
-  // update timing info
-  vrnow_prev = vrnow;
-  GET_REAL_CPU_TICKS( rafter );
-  ticks_rdiff += (rafter - rnow);
-#ifdef USE_PERFCTR
-  vnow_prev = vnow;
-  GET_CPU_TICKS( after );
-  ticks_diff  += (after - now);
-#endif
-}
-
-void real_toutput(int tid, const char *func, const char *fmt, ...)
-{
-  va_list ap;
-  if (conf_no_debug)
-    return;
-  va_start(ap,fmt);
-  output_aux(tid, func, fmt,ap);
-  va_end(ap);
-}
-
-void real_debug(const char *func, const char *fmt, ...)
-{
-  va_list ap;
-  if (conf_no_debug)
-    return;
-  va_start(ap,fmt);
-  output_aux(DBG_NO_TIMING, func, fmt,ap);
-  va_end(ap);
-}
-
-void output(char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap,fmt);
-  output_aux(DBG_NO_TIMING, NULL, fmt,ap);
-  va_end(ap);
-}
-
-void warning(char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap,fmt);
-  output_aux(DBG_NO_TIMING, NULL, fmt,ap);
-  va_end(ap);
-}
-
-void fatal(char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap,fmt);
-  output_aux(DBG_NO_TIMING, NULL, fmt,ap);
-  va_end(ap);
-  abort();
-}
-
-
-#if OPTIMIZE < 2
-
-#ifdef USE_CCURED
-#define __progname NULL
-#else
-extern const char *__progname;
-#endif
-
-//extern void debug_sighandler(int);
-
-void assert_failed(char *file, unsigned int line, const char *func, char *expr)
-{
-  //debug_sighandler(-1);      // print all kinds of info
-  fatal("%s%s%s:%u: %s:  Assertion `%s' failed.\n",
-        __progname ? __progname : "",
-        __progname ? ": " : "",
-        file, line, func, expr);
-  abort();
-}
-#endif
diff --git a/user/c3po/util/debug.h b/user/c3po/util/debug.h
deleted file mode 100644 (file)
index 98ac3e2..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-
-#ifndef DEBUG_H
-#define DEBUG_H
-
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <string.h>
-#include "clock.h"
-
-#define tdebug(args...) \
-do {\
-  real_toutput(thread_tid(current_thread),__FUNCTION__,args); \
-} while( 0 )
-
-/*
-#define debug(args...) \
-do {\
-  real_debug(__FUNCTION__,args); \
-} while(0) 
-*/
-#define debug(args...) tdebug(args)
-
-
-#define toutput(args...) \
-do { \
-  real_toutput(thread_tid(current_thread),NULL,args); \
-  output(args); \
-} while( 0 )
-
-
-/*
-#include <stdio.h>
-#undef perror
-#define perror(str)  \
-do { \
-  warning("%s:%d - %s():  ",__FILE__,__LINE__,__FUNCTION__); \
-  warning("%s: %s\n",str,strerror(errno)); \
-} while(0)
-*/
-
-void real_debug(const char *func, const char *fmt, ...) __attribute__ ((format (printf,2,3)));
-void real_toutput(int tid, const char *func, const char *fmt, ...) __attribute__ ((format (printf,3,4)));
-void output(char *fmt, ...) __attribute__ ((format (printf,1,2)));
-void warning(char *fmt, ...) __attribute__ ((format (printf,1,2)));
-void fatal(char *fmt, ...) __attribute__ ((format (printf,1,2)));
-
-
-extern cpu_tick_t ticks_diff;
-extern cpu_tick_t ticks_rdiff;
-
-void init_debug();
-
-#endif
diff --git a/user/c3po/util/libperfctr.h b/user/c3po/util/libperfctr.h
deleted file mode 100644 (file)
index 633d638..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $Id: libperfctr.h,v 1.1 2003/03/22 07:41:06 zf Exp $
- * Library interface to Linux x86 Performance-Monitoring Counters.
- *
- * Copyright (C) 1999-2003  Mikael Pettersson
- */
-
-#ifndef __LIB_PERFCTR_H
-#define __LIB_PERFCTR_H
-
-#define CONFIG_KPERFCTR
-#include <linux/perfctr.h>
-
-/*
- * Operations on the process' own virtual-mode perfctrs.
- */
-
-struct vperfctr;       /* opaque */
-
-struct vperfctr *vperfctr_open(void);
-int vperfctr_info(const struct vperfctr*, struct perfctr_info*);
-unsigned long long vperfctr_read_tsc(const struct vperfctr*);
-unsigned long long vperfctr_read_pmc(const struct vperfctr*, unsigned);
-void vperfctr_read_ctrs(const struct vperfctr*, struct perfctr_sum_ctrs*);
-int vperfctr_read_state(const struct vperfctr*, struct perfctr_sum_ctrs*,
-                       struct vperfctr_control*);
-int vperfctr_control(const struct vperfctr*, struct vperfctr_control*);
-int vperfctr_stop(const struct vperfctr*);
-int vperfctr_is_running(const struct vperfctr*);
-int vperfctr_iresume(const struct vperfctr*);
-int vperfctr_unlink(const struct vperfctr*);
-void vperfctr_close(struct vperfctr*);
-
-/*
- * Operations on other processes' virtual-mode perfctrs.
- * (Preliminary, subject to change.)
- */
-
-struct rvperfctr;      /* opaque */
-
-struct rvperfctr *rvperfctr_open(int pid);
-int rvperfctr_pid(const struct rvperfctr*);
-int rvperfctr_info(const struct rvperfctr*, struct perfctr_info*);
-void rvperfctr_read_ctrs(const struct rvperfctr*, struct perfctr_sum_ctrs*);
-int rvperfctr_read_state(const struct rvperfctr*, struct perfctr_sum_ctrs*,
-                        struct vperfctr_control*);
-int rvperfctr_control(const struct rvperfctr*, struct vperfctr_control*);
-int rvperfctr_stop(const struct rvperfctr*);
-int rvperfctr_unlink(const struct rvperfctr*);
-void rvperfctr_close(struct rvperfctr*);
-
-/*
- * Operations on global-mode perfctrs.
- */
-
-struct gperfctr;       /* opaque */
-
-struct gperfctr *gperfctr_open(void);
-void gperfctr_close(struct gperfctr*);
-int gperfctr_control(const struct gperfctr*, struct gperfctr_control*);
-int gperfctr_read(const struct gperfctr*, struct gperfctr_state*);
-int gperfctr_stop(const struct gperfctr*);
-int gperfctr_info(const struct gperfctr*, struct perfctr_info*);
-
-/*
- * Descriptions of the events available for different processor types.
- */
-
-enum perfctr_unit_mask_type {
-    perfctr_um_type_fixed,     /* one fixed (required) value */
-    perfctr_um_type_exclusive, /* exactly one of N values */
-    perfctr_um_type_bitmask,   /* bitwise 'or' of N power-of-2 values */
-};
-
-struct perfctr_unit_mask_value {
-    unsigned int value;
-    const char *description;   /* [NAME:]text */
-};
-
-struct perfctr_unit_mask {
-    unsigned int default_value;
-    enum perfctr_unit_mask_type type:16;
-    unsigned short nvalues;
-    struct perfctr_unit_mask_value values[1/*nvalues*/];
-};
-
-struct perfctr_event {
-    unsigned int evntsel;
-    unsigned int counters_set; /* P4 force this to be CPU-specific */
-    const struct perfctr_unit_mask *unit_mask;
-    const char *name;
-    const char *description;
-};
-
-struct perfctr_event_set {
-    unsigned int cpu_type;
-    const char *event_prefix;
-    const struct perfctr_event_set *include;
-    unsigned int nevents;
-    const struct perfctr_event *events;
-};
-
-const struct perfctr_event_set *perfctr_cpu_event_set(unsigned int cpu_type);
-
-/*
- * Miscellaneous operations.
- */
-
-/* this checks the ABI between library and kernel -- it can also
-   be used by applications operating on raw file descriptors */
-int _perfctr_abi_check_fd(int fd, unsigned int user_abi_version);
-static __inline__ int perfctr_abi_check_fd(int fd)
-{
-    return _perfctr_abi_check_fd(fd, PERFCTR_ABI_VERSION);
-}
-
-int perfctr_info(int fd, struct perfctr_info *info);
-unsigned int perfctr_info_nrctrs(const struct perfctr_info*);
-const char *perfctr_info_cpu_name(const struct perfctr_info*);
-void perfctr_info_print(const struct perfctr_info*);
-void perfctr_cpu_control_print(const struct perfctr_cpu_control*);
-
-#endif /* __LIB_PERFCTR_H */
diff --git a/user/c3po/util/linked_list.c b/user/c3po/util/linked_list.c
deleted file mode 100644 (file)
index a3f3a02..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-
-
-#include <stdlib.h>
-#include "linked_list.h"
-#include "debug.h"
-
-#ifndef DEBUG_linked_list_c
-#undef debug
-#define debug(...)
-#undef tdebug
-#define tdebug(...)
-#endif
-
-
-// the minimum allocation block.  
-//
-// FIXME: this should probably not be static, and probably should not
-// be defined here.
-#define MIN_ALLOC_BLOCK (1024)
-
-// choose a macro for integrity checking
-#ifdef DEBUG_linked_list_c
-#define check_list_integrity(ll) {\
-  assert(ll->num_entries >= 0);  \
-  assert(ll->num_entries == 0  ? (ll->head == NULL  &&  ll->tail == NULL) : 1);  \
-  assert(ll->num_entries == 1  ? (ll->head == ll->tail) : 1);  \
-  assert(ll->num_entries  > 1  ? (ll->head != NULL  &&  ll->tail != NULL  &&  ll->head != ll->tail) : 1);  \
-  { \
-    int _num = 0; \
-    linked_list_entry_t *e = ll->head; \
-    assert( !e || !e->p.prev ); \
-    while( e ) { \
-      _num++; \
-      assert( e->list == ll ); \
-      if( e->p.next ) assert(e == (linked_list_entry_t*)e->p.next->prev); \
-      e = (linked_list_entry_t*)e->p.next; \
-    } \
-    assert( _num == ll->num_entries ); \
-  } \
-}
-#else
-#define check_list_integrity(ll) {}
-#endif
-
-/**
- * return a list entry to the free list
- *
- * FIXME: perhaps garbage collect entries over time?
- **/
-void ll_free_entry(linked_list_t *ll, void* e) 
-{
-  op_free_entry(ll->pool, (object_pool_entry_t*) e);
-}
-
-
-/**
- * Initialize an externally allocated linked list
- **/
-void ll_init(linked_list_t *ll, const char *name, object_pool_t *pool)
-{
-  ll->name = (name ? name : "noname");
-  ll->num_entries = 0;
-  ll->head = NULL;
-  ll->tail = NULL;
-  ll->pool = pool;  
-}
-
-
-/**
- * Create a new linked list
- **/
-linked_list_t* new_linked_list(const char *name, int entry_size)
-{
-  linked_list_t *ll;
-  object_pool_t *pool;
-
-  assert((unsigned int)entry_size > sizeof(linked_list_entry_t));
-
-  ll = (linked_list_t*) malloc(sizeof(linked_list_t));    assert(ll);
-  pool = new_object_pool(entry_size, MIN_ALLOC_BLOCK);    assert(pool);
-  
-  ll_init(ll, name, pool);
-  
-  check_list_integrity(ll);
-  
-  return ll;
-}
-
-
-/**
- * allocate & add a new entry to the end of the list.  The new entry
- * is returned, so the caller can fill in any required data.
- **/
-linked_list_entry_t* ll_add_tail(linked_list_t *ll)
-{
-  linked_list_entry_t *e;
-  
-  check_list_integrity(ll);
-
-  // allocate the new entry
-  e = (linked_list_entry_t*) op_new_object(ll->pool);
-
-  // add to the list
-  ll_add_existing_to_tail(ll, e);
-
-  check_list_integrity(ll);
-
-  return e;
-}
-
-/**
- * allocate & add a new entry to the end of the list.  The new entry
- * is returned, so the caller can fill in any required data.
- **/
-linked_list_entry_t* ll_add_head(linked_list_t *ll)
-{
-  linked_list_entry_t *e;
-  
-  check_list_integrity(ll);
-
-  // allocate the new entry
-  e = (linked_list_entry_t*) op_new_object(ll->pool);
-
-  // add to the list
-  ll_add_existing_to_head(ll, e);
-
-  check_list_integrity(ll);
-
-  return e;
-}
-
-
-linked_list_entry_t* ll_insert_before(linked_list_t *ll, linked_list_entry_t *item)
-{
-  linked_list_entry_t *e;
-  
-  check_list_integrity(ll);
-
-  assert(item->list == ll);
-  
-  // allocate the new entry
-  e = (linked_list_entry_t*) op_new_object(ll->pool);
-
-  // add to the list
-  ll_insert_existing_before(ll, item, e);
-
-  check_list_integrity(ll);
-
-  return e;
-}
-
-/**
- * add a pre-allocated item to the tail of the list
- **/
-void ll_add_existing_to_tail(linked_list_t *ll, linked_list_entry_t *e)
-{
-  check_list_integrity(ll);
-
-  // NOTE: it might be nice to check that e->list is not set, but this
-  // means that externally allocated request entries have to be
-  // specially initialized, which is error prone.
-  //assert(e->list == NULL);
-  e->list = ll;
-
-  // queue is empty
-  if(ll->head == NULL) {
-    e->p.next = NULL;
-    e->p.prev = NULL;
-    ll->head = ll->tail = e;
-  } 
-
-  // add to the tail
-  else {
-    ll->tail->p.next = (object_pool_entry_t*) e;
-    e->p.next = NULL;
-    e->p.prev = (object_pool_entry_t*) ll->tail;
-    ll->tai