Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / arch / sys_arch.c
diff --git a/geekos/src/lwip/arch/sys_arch.c b/geekos/src/lwip/arch/sys_arch.c
new file mode 100644 (file)
index 0000000..52746db
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/*
+ * Wed Apr 17 16:05:29 EDT 2002 (James Roth)
+ *
+ *  - Fixed an unlikely sys_thread_new() race condition.
+ *
+ *  - Made current_thread() work with threads which where
+ *    not created with sys_thread_new().  This includes
+ *    the main thread and threads made with pthread_create().
+ *
+ *  - Catch overflows where more than SYS_MBOX_SIZE messages
+ *    are waiting to be read.  The sys_mbox_post() routine
+ *    will block until there is more room instead of just
+ *    leaking messages.
+ */
+/*
+ * Modified by Lei Xia (lxia@northwestern.edu) to fit to Palacios, 9/29/2008
+ */
+#include "lwip/debug.h"
+
+#include <string.h>
+
+//#include <palacios/vmm.h>
+#include <geekos/synch.h>
+#include <geekos/kthread.h>
+#include <geekos/debug.h>
+#include <geekos/timer.h>
+#include <geekos/malloc.h>
+
+#include "lwip/sys.h"
+#include "lwip/opt.h"
+#include "lwip/stats.h"
+
+#define UMAX(a, b)      ((a) > (b) ? (a) : (b))
+
+static struct sys_thread *threads = NULL;
+
+//static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct Mutex threads_mutex; // !!!! need to be initiated, void Mutex_Init(struct Mutex* mutex);
+
+struct sys_mbox_msg {
+  struct sys_mbox_msg *next;
+  void *msg;
+};
+
+#define SYS_MBOX_SIZE 128
+
+struct sys_mbox {
+  int first, last;
+  void *msgs[SYS_MBOX_SIZE];
+  struct sys_sem *mail;
+  struct sys_sem *mutex;
+  int wait_send;
+};
+
+struct sys_sem {
+  unsigned int c;
+  
+  //pthread_cond_t cond;
+  struct Condition cond;
+  
+  //pthread_mutex_t mutex;
+  struct Mutex mutex;
+};
+
+struct sys_thread {
+  struct sys_thread *next;
+  struct sys_timeouts timeouts;
+  
+ // pthread_t pthread;
+  struct Kernel_Thread *pthread;
+};
+
+
+//static struct timeval starttime;
+
+//static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct Mutex lwprot_mutex; // !!!! need to be initiated, void Mutex_Init(struct Mutex* mutex);
+
+//static pthread_t lwprot_thread = (pthread_t) 0xDEAD;
+//static struct Kernel_Thread lwprot_thread = (struct Kernel_Thread) 0xDEAD;  //!!!!! how to set it to a NULL thread?
+
+//static int lwprot_count = 0;
+
+static struct sys_sem *sys_sem_new_(u8_t count);
+static void sys_sem_free_(struct sys_sem *sem);
+
+static u32_t cond_wait(struct Condition *cond, struct Mutex *mutex, u32_t timeout);
+
+
+/*-----------------------------------------------------------------------------------*/
+static struct sys_thread * 
+introduce_thread(struct Kernel_Thread *id /*pthread_t id*/)
+{
+  struct sys_thread *thread;
+  
+  thread = (struct sys_thread *)Malloc(sizeof(struct sys_thread)); 
+    
+  if (thread != NULL) {
+    //pthread_mutex_lock(&threads_mutex);
+    Mutex_Lock(&threads_mutex);
+       
+    thread->next = threads;
+    thread->timeouts.next = NULL;
+    thread->pthread = id;
+    threads = thread;
+
+    //pthread_mutex_unlock(&threads_mutex);
+    Mutex_Unlock(&threads_mutex);
+  }
+    
+  return thread;
+}
+
+static int thread_equal(struct Kernel_Thread *kth1, struct Kernel_Thread *kth2){  //added
+
+       return (kth1->pid == kth2->pid);
+
+}
+
+/*-----------------------------------------------------------------------------------*/
+static struct sys_thread *
+current_thread(void)
+{
+  struct sys_thread *st;
+  
+  //pthread_t pt;
+  struct Kernel_Thread *pt;
+  
+  //pt = pthread_self();
+  //!!!!!!!!!!!Do these have the same means? Not sure
+  pt = Get_Current();
+  
+  //pthread_mutex_lock(&threads_mutex);
+  Mutex_Lock(&threads_mutex);
+
+  for(st = threads; st != NULL; st = st->next) {    
+    if (thread_equal(st->pthread, pt)) {
+      //pthread_mutex_unlock(&threads_mutex);
+      Mutex_Unlock(&threads_mutex);
+
+      return st;
+    }
+  }
+
+  //pthread_mutex_unlock(&threads_mutex);
+  Mutex_Unlock(&threads_mutex);
+
+  st = introduce_thread(pt);
+
+  if (!st) {
+    PrintBoth("lwIP error: In current_thread: Can not get current_thread\n");
+    abort();
+  }
+
+  return st;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+sys_thread_t
+sys_thread_new(char *name, void (* function)(void *arg), void *arg, int stacksize, int prio)
+{
+  //int code;
+  //pthread_t tmp;
+  struct Kernel_Thread *tmp;
+  struct sys_thread *st = NULL;
+  
+  //tmp = (struct Kernel_Thread *)Malloc(sizeof(struct Kernel_Thread));
+  
+  /* code = pthread_create(&tmp,
+                        NULL, 
+                        (void *(*)(void *)) 
+                        function, 
+                        arg); */
+                       
+  tmp = Start_Kernel_Thread(function, arg, PRIORITY_NORMAL , false);  //did not consider the priority here
+  
+  if (tmp != NULL) {
+    st = introduce_thread(tmp);
+  }
+  
+  if (NULL == st) {
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create: 0x%x, st = 0x%x",
+                       (int)tmp, (int)st));
+    abort();
+  }
+  return st;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+struct sys_mbox *
+sys_mbox_new(int size)
+{
+  struct sys_mbox *mbox;
+  
+  mbox = (struct sys_mbox *)Malloc(sizeof(struct sys_mbox));
+  if (mbox != NULL) {
+    mbox->first = mbox->last = 0;
+    mbox->mail = sys_sem_new_(0);
+    mbox->mutex = sys_sem_new_(1);
+    mbox->wait_send = 0;
+  
+#if SYS_STATS
+    lwip_stats.sys.mbox.used++;
+    if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max) {
+      lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
+    }
+#endif /* SYS_STATS */
+  }
+  return mbox;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_mbox_free(struct sys_mbox *mbox)
+{
+  if (mbox != SYS_MBOX_NULL) {
+#if SYS_STATS
+    lwip_stats.sys.mbox.used--;
+#endif /* SYS_STATS */
+    sys_sem_wait(mbox->mutex);
+    
+    sys_sem_free_(mbox->mail);
+    sys_sem_free_(mbox->mutex);
+    mbox->mail = mbox->mutex = NULL;
+    /*  LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
+
+    Free(mbox); 
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+err_t
+sys_mbox_trypost(struct sys_mbox *mbox, void *msg)
+{
+  u8_t first;
+  
+  sys_sem_wait(mbox->mutex);
+  
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
+                          (void *)mbox, (void *)msg));
+  
+  if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE))
+    return ERR_MEM;
+
+  mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
+  
+  if (mbox->last == mbox->first) {
+    first = 1;
+  } else {
+    first = 0;
+  }
+  
+  mbox->last++;
+  
+  if (first) {
+    sys_sem_signal(mbox->mail);
+  }
+
+  sys_sem_signal(mbox->mutex);
+
+  return ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_mbox_post(struct sys_mbox *mbox, void *msg)
+{
+  u8_t first;
+  
+  sys_sem_wait(mbox->mutex);
+  
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg));
+  
+  while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
+    mbox->wait_send++;
+    sys_sem_signal(mbox->mutex);
+    sys_arch_sem_wait(mbox->mail, 0);
+    sys_arch_sem_wait(mbox->mutex, 0);
+    mbox->wait_send--;
+  }
+  
+  mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
+  
+  if (mbox->last == mbox->first) {
+    first = 1;
+  } else {
+    first = 0;
+  }
+  
+  mbox->last++;
+  
+  if (first) {
+    sys_sem_signal(mbox->mail);
+  }
+
+  sys_sem_signal(mbox->mutex);
+}
+/*-----------------------------------------------------------------------------------*/
+u32_t
+sys_arch_mbox_tryfetch(struct sys_mbox *mbox, void **msg)
+{
+  sys_arch_sem_wait(mbox->mutex, 0);
+
+  if (mbox->first == mbox->last) {
+    sys_sem_signal(mbox->mutex);
+    return SYS_MBOX_EMPTY;
+  }
+
+  if (msg != NULL) {
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg));
+    *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
+  }
+  else{
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox));
+  }
+
+  mbox->first++;
+  
+  if (mbox->wait_send) {
+    sys_sem_signal(mbox->mail);
+  }
+
+  sys_sem_signal(mbox->mutex);
+
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+u32_t
+sys_arch_mbox_fetch(struct sys_mbox *mbox, void **msg, u32_t timeout)
+{
+  u32_t time = 0;
+  
+  /* The mutex lock is quick so we don't bother with the timeout
+     stuff here. */
+  sys_arch_sem_wait(mbox->mutex, 0);
+
+  while (mbox->first == mbox->last) {
+    sys_sem_signal(mbox->mutex);
+    
+    /* We block while waiting for a mail to arrive in the mailbox. We
+       must be prepared to timeout. */
+    if (timeout != 0) {
+      time = sys_arch_sem_wait(mbox->mail, timeout);
+      
+      if (time == SYS_ARCH_TIMEOUT) {
+        return SYS_ARCH_TIMEOUT;
+      }
+    } else {
+      sys_arch_sem_wait(mbox->mail, 0);
+    }
+    
+    sys_arch_sem_wait(mbox->mutex, 0);
+  }
+
+  if (msg != NULL) {
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg));
+    *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
+  }
+  else{
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox));
+  }
+
+  mbox->first++;
+  
+  if (mbox->wait_send) {
+    sys_sem_signal(mbox->mail);
+  }
+
+  sys_sem_signal(mbox->mutex);
+
+  return time;
+}
+/*-----------------------------------------------------------------------------------*/
+struct sys_sem *
+sys_sem_new(u8_t count)
+{
+#if SYS_STATS
+  lwip_stats.sys.sem.used++;
+  if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max) {
+    lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
+  }
+#endif /* SYS_STATS */
+  return sys_sem_new_(count);
+}
+
+/*-----------------------------------------------------------------------------------*/
+static struct sys_sem *
+sys_sem_new_(u8_t count)
+{
+  struct sys_sem *sem;
+  
+  sem = (struct sys_sem *)Malloc(sizeof(struct sys_sem));
+  if (sem != NULL) {
+    sem->c = count;
+
+    //pthread_cond_init(&(sem->cond), NULL);
+    Cond_Init(&(sem->cond));
+    
+    //pthread_mutex_init(&(sem->mutex), NULL);
+    Mutex_Init(&(sem->mutex));
+  }
+  return sem;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+static u32_t
+cond_wait(struct Condition *cond, struct Mutex *mutex, u32_t timeout /* timeout is in miliseconds *//* pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout */)
+{
+  ulong_t tdiff, msec;
+
+  /*
+  struct timeval rtime1, rtime2;
+  struct timespec ts;
+  struct timezone tz;
+  */
+  int retval;
+
+  if (timeout > 0) {
+
+    /* Get a timestamp and add the timeout value. */
+    /*gettimeofday(&rtime1, &tz);
+    sec = rtime1.tv_sec;
+    usec = rtime1.tv_usec;
+    usec += timeout % 1000 * 1000;
+    sec += (int)(timeout / 1000) + (int)(usec / 1000000);
+    usec = usec % 1000000;
+    ts.tv_nsec = usec * 1000;
+    ts.tv_sec = sec;
+    */
+    msec = clock_time();
+  
+    if (Cond_Wait_Timeout(cond, mutex, timeout) == 1) //return due to timeout
+               retval = ETIMEDOUT;
+       
+    //retval = pthread_cond_timedwait(cond, mutex, &ts);
+    
+    if (retval == ETIMEDOUT) {
+      return SYS_ARCH_TIMEOUT;
+    } else {
+      /* Calculate for how long we waited for the cond. */
+
+      /*
+      gettimeofday(&rtime2, &tz);
+      tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 +
+        (rtime2.tv_usec - rtime1.tv_usec) / 1000;
+      */
+      tdiff = clock_time();
+
+      tdiff -= msec;
+      
+      if (tdiff <= 0) {
+        return 0;
+      }
+      
+      return tdiff;
+    }
+  } else {
+    //pthread_cond_wait(cond, mutex);
+    Cond_Wait(cond, mutex);
+       
+    return SYS_ARCH_TIMEOUT;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+u32_t
+sys_arch_sem_wait(struct sys_sem *sem, u32_t timeout)
+{
+  u32_t time = 0;
+  
+  //pthread_mutex_lock(&(sem->mutex));
+  Mutex_Lock(&(sem->mutex));
+  
+  while (sem->c <= 0) {
+    if (timeout > 0) {
+      time = cond_wait(&(sem->cond), &(sem->mutex), timeout);
+      
+      if (time == SYS_ARCH_TIMEOUT) {
+        //pthread_mutex_unlock(&(sem->mutex));
+        Mutex_Unlock(&(sem->mutex));
+       
+        return SYS_ARCH_TIMEOUT;
+      }
+      /*      pthread_mutex_unlock(&(sem->mutex));
+              return time; */
+    } else {  // if timeout = 0
+      cond_wait(&(sem->cond), &(sem->mutex), 0);
+    }
+  }
+  sem->c--;
+  //pthread_mutex_unlock(&(sem->mutex));
+  Mutex_Unlock(&(sem->mutex));
+  
+  return time;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_sem_signal(struct sys_sem *sem)
+{
+  //pthread_mutex_lock(&(sem->mutex));
+  Mutex_Lock(&(sem->mutex));
+  
+  sem->c++;
+
+  if (sem->c > 1) {
+    sem->c = 1;
+  }
+
+  //pthread_cond_broadcast(&(sem->cond));
+  Cond_Broadcast(&(sem->cond));
+  
+  //pthread_mutex_unlock(&(sem->mutex));
+  Mutex_Unlock(&(sem->mutex));
+  
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_sem_free(struct sys_sem *sem)
+{
+  if (sem != SYS_SEM_NULL) {
+#if SYS_STATS
+    lwip_stats.sys.sem.used--;
+#endif /* SYS_STATS */
+    sys_sem_free_(sem);
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+static void
+sys_sem_free_(struct sys_sem *sem)
+{
+  //pthread_cond_destroy(&(sem->cond));
+  Cond_Destroy(&(sem->cond));
+  
+  //pthread_mutex_destroy(&(sem->mutex));
+  Mutex_Destroy(&(sem->mutex));
+  
+  Free(sem);
+}
+
+#if 0
+//return time, we do not need this
+/*-----------------------------------------------------------------------------------*/
+unsigned long
+sys_unix_now()
+{
+  struct timeval tv;
+  struct timezone tz;
+  long sec, usec;
+  unsigned long msec;
+  gettimeofday(&tv, &tz);
+  
+  sec = tv.tv_sec - starttime.tv_sec;
+  usec = tv.tv_usec - starttime.tv_usec;
+  msec = sec * 1000 + usec / 1000;
+    
+  return msec;
+}
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+void
+sys_init()
+{
+  //struct timezone tz;
+  //gettimeofday(&starttime, &tz);
+
+  Mutex_Init(&threads_mutex);
+  Mutex_Init(&lwprot_mutex);
+  
+}
+/*-----------------------------------------------------------------------------------*/
+struct sys_timeouts *
+sys_arch_timeouts(void)
+{
+  struct sys_thread *thread;
+
+  thread = current_thread();
+  return &thread->timeouts;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+/** sys_prot_t sys_arch_protect(void)
+
+This optional function does a "fast" critical region protection and returns
+the previous protection level. This function is only called during very short
+critical regions. An embedded system which supports ISR-based drivers might
+want to implement this function by disabling interrupts. Task-based systems
+might want to implement this by using a mutex or disabling tasking. This
+function should support recursive calls from the same task or interrupt. In
+other words, sys_arch_protect() could be called while already protected. In
+that case the return value indicates that it is already protected.
+
+sys_arch_protect() is only required if your port is supporting an operating
+system.
+*/
+
+#if 0
+sys_prot_t
+sys_arch_protect(void)
+{
+    /* Note that for the UNIX port, we are using a lightweight mutex, and our
+     * own counter (which is locked by the mutex). The return code is not actually
+     * used. */
+    if (lwprot_thread != current_thread() /*lwprot_thread != pthread_self()*/)
+    {
+        /* We are locking the mutex where it has not been locked before *
+        * or is being locked by another thread */
+        Mutex_Lock(&lwprot_mutex);
+        lwprot_thread = current_thread();
+        lwprot_count = 1;
+    }
+    else
+        /* It is already locked by THIS thread */
+        lwprot_count++;
+    return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/** void sys_arch_unprotect(sys_prot_t pval)
+
+This optional function does a "fast" set of critical region protection to the
+value specified by pval. See the documentation for sys_arch_protect() for
+more information. This function is only required if your port is supporting
+an operating system.
+*/
+void
+sys_arch_unprotect(sys_prot_t pval)
+{
+    if (lwprot_thread == current_thread())
+    {
+        if (--lwprot_count == 0)
+        {
+            lwprot_thread = (struc Kernel_Thread) 0xDEAD;
+            Mutex_Unlock(&lwprot_mutex);
+        }
+    }
+}
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+
+#ifndef MAX_JIFFY_OFFSET
+#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+#endif
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#if 0
+unsigned long
+sys_jiffies(void)
+{
+    struct timeval tv;
+    unsigned long sec = tv.tv_sec;
+    long usec = tv.tv_usec;
+
+    gettimeofday(&tv,NULL);
+
+    if (sec >= (MAX_JIFFY_OFFSET / HZ))
+       return MAX_JIFFY_OFFSET;
+    usec += 1000000L / HZ - 1;
+    usec /= 1000000L / HZ;
+    return HZ * sec + usec;
+}
+#endif
+
+#if PPP_DEBUG
+
+#include <geekos/serial.h>
+
+void ppp_trace(int level, const char *format, ...)
+{
+    va_list args;
+
+    (void)level;
+    va_start(args, format);
+       
+    //vprintf(format, args);
+    PrintDebug(format, args);
+       
+    va_end(args);
+}
+#endif