/* * 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 * */ /* * 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 //#include #include #include #include #include #include #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 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