/* * Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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> * Sub Author: Christopher Olsen <colsen@domaintlantic.com> * * Notes: * Modified to work with the ubix operating system * * $Log$ * Revision 1.6 2004/09/11 21:30:37 apwillia * Fix race conditions in net thread and scheduler * * Revision 1.5 2004/09/07 20:58:35 reddawg * time to roll back i can't think straight by friday * * Revision 1.4 2004/05/25 22:49:29 reddawg * Stupid Old CODE!!! * * Revision 1.3 2004/05/19 04:07:43 reddawg * kmalloc(size,pid) no more it is no kmalloc(size); the way it should of been * * Revision 1.2 2004/05/19 03:35:02 reddawg * Fixed A Few Ordering Issues In The Service Startup Routine * * Revision 1.1.1.1 2004/04/15 12:07:14 reddawg * UbixOS v1.0 * * Revision 1.13 2004/04/13 21:29:53 reddawg * We now have sockets working. Lots of functionality to be added to continually * improve on the existing layers now its clean up time to get things in a better * working order. * * Revision 1.12 2004/04/13 16:08:07 reddawg * Removed all of the old debug code the problem seems to be in ubthreads with * ubthread_mutex_init * * Revision 1.11 2004/04/13 16:05:40 reddawg * Function Renaming * * * * $Id$ */ #include <ubixos/types.h> #include <ubixos/sched.h> #include <ubixos/ubthread.h> #include <ubixos/kpanic.h> #include <lib/kprintf.h> #include <lib/kmalloc.h> #include "net/debug.h" #include "net/sys.h" #include "net/opt.h" #include "net/stats.h" #include <ubixos/spinlock.h> #define UMAX(a, b) ((a) > (b) ? (a) : (b)) static struct sys_thread *threads = 0x0; static spinLock_t netThreadSpinlock; struct sys_mbox_msg { struct sys_mbox_msg *next; void *msg; }; #define SYS_MBOX_SIZE 100 struct sys_mbox { uInt16 first, last; void *msgs[SYS_MBOX_SIZE]; struct sys_sem *mail; struct sys_sem *mutex; }; struct sys_sem { unsigned int c; ubthread_cond_t cond; ubthread_mutex_t mutex; }; struct sys_thread { struct sys_thread *next; struct sys_timeouts timeouts; kTask_t *ubthread; }; static struct timeval starttime; static struct sys_sem *sys_sem_new_(uInt8 count); static void sys_sem_free_(struct sys_sem *sem); static uInt16 cond_wait(ubthread_cond_t *cond, ubthread_mutex_t *mutex, uInt16 timeout); static struct sys_thread *current_thread(void) { struct sys_thread *st; kTask_t *pt; pt = ubthread_self(); spinLock(&netThreadSpinlock); for(st = threads; st != NULL; st = st->next) { if(st->ubthread == pt) { spinUnlock(&netThreadSpinlock); return st; } } spinUnlock(&netThreadSpinlock); kprintf("sys: current_thread: could not find current thread!\n"); kprintf("This is due to a race condition in the LinuxThreads\n"); kprintf("ubthreads implementation. Start the program again.\n"); kpanic("ABORT"); return(0x0); } struct thread_start_param { struct sys_thread *thread; void (* function)(void *); void *arg; }; /* static void *thread_start(void *arg) { struct thread_start_param *tp = arg; tp->thread->ubthread = ubthread_self(); tp->function(tp->arg); kfree(tp); return(NULL); } */ void sys_thread_new(void (* function)(void), void *arg) { struct sys_thread *thread = 0x0; //struct thread_start_param *thread_param; kprintf("sys_thread: [0x%X]\n",sizeof(struct sys_thread)); thread = kmalloc(sizeof(struct sys_thread)); kprintf("THREAD: [0x%X]\n",thread); spinLock(&netThreadSpinlock); thread->next = threads; thread->timeouts.next = NULL; thread->ubthread = 0x0; threads = thread; spinUnlock(&netThreadSpinlock); /* thread_param = kmalloc(sizeof(struct thread_start_param)); thread_param->function = function; thread_param->arg = arg; thread_param->thread = thread; */ //execThread((void *)function,0x0,0x0); kprintf("thread->ubthread: [0x%X]\n",thread->ubthread); if(ubthread_create(&thread->ubthread, 0x0,(void *)(function), arg) != 0x0) { kpanic("sys_thread_new: ubthread_create"); } kprintf("thread->ubthread: [0x%X]\n",thread->ubthread); } struct sys_mbox *sys_mbox_new() { struct sys_mbox *mbox; mbox = kmalloc(sizeof(struct sys_mbox)); mbox->first = mbox->last = 0; mbox->mail = sys_sem_new_(0); mbox->mutex = sys_sem_new_(1); return(mbox); } void sys_mbox_free(struct sys_mbox *mbox) { if (mbox != SYS_MBOX_NULL) { sys_sem_wait(mbox->mutex); sys_sem_free_(mbox->mail); sys_sem_free_(mbox->mutex); mbox->mail = mbox->mutex = NULL; //kprintf("sys_mbox_free: mbox 0x%lx\n", mbox); kfree(mbox); } } void sys_mbox_post(struct sys_mbox *mbox, void *msg) { uInt8 first; sys_sem_wait(mbox->mutex); //kprintf("sys_mbox_post: mbox %p msg %p\n", mbox, msg); mbox->msgs[mbox->last] = msg; if (mbox->last == mbox->first) { first = 1; } else { first = 0; } mbox->last++; if(mbox->last == SYS_MBOX_SIZE) { mbox->last = 0; } if(first) { sys_sem_signal(mbox->mail); } sys_sem_signal(mbox->mutex); } uInt16 sys_arch_mbox_fetch(struct sys_mbox *mbox, void **msg, uInt16 timeout) { uInt16 time = 1; /* 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 == 0, the sem_wait timed out, and we return 0. */ if(time == 0) { return 0; } } else { sys_arch_sem_wait(mbox->mail, 0); } sys_arch_sem_wait(mbox->mutex, 0); } if(msg != NULL) { //kprintf("sys_mbox_fetch: mbox %p msg %p\n", mbox, *msg); *msg = mbox->msgs[mbox->first]; } mbox->first++; if(mbox->first == SYS_MBOX_SIZE) { mbox->first = 0; } sys_sem_signal(mbox->mutex); return(time); } struct sys_sem *sys_sem_new(uInt8 count) { return sys_sem_new_(count); } static struct sys_sem *sys_sem_new_(uInt8 count) { struct sys_sem *sem; sem = kmalloc(sizeof(struct sys_sem)); sem->c = count; ubthread_cond_init(&(sem->cond), NULL); ubthread_mutex_init(&(sem->mutex), NULL); return sem; } static uInt16 cond_wait(ubthread_cond_t *cond, ubthread_mutex_t *mutex, uInt16 timeout) { unsigned int tdiff; unsigned long sec, usec; 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; retval = ubthread_cond_timedwait(cond, mutex, &ts); if (retval == ETIMEDOUT) { return 0; } 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; if (tdiff == 0) { return 1; } return tdiff; } } else { ubthread_cond_wait(cond, mutex); return 0; } } uInt16 sys_arch_sem_wait(struct sys_sem *sem, uInt16 timeout) { uInt16 time = 1; ubthread_mutex_lock(&(sem->mutex)); while(sem->c <= 0) { if(timeout > 0) { time = cond_wait(&(sem->cond), &(sem->mutex), timeout); if(time == 0) { ubthread_mutex_unlock(&(sem->mutex)); return 0; } } else { cond_wait(&(sem->cond), &(sem->mutex), 0); } } sem->c--; ubthread_mutex_unlock(&(sem->mutex)); return(time); } void sys_sem_signal(struct sys_sem *sem) { ubthread_mutex_lock(&(sem->mutex)); sem->c++; if(sem->c > 1) sem->c = 1; ubthread_cond_signal(&(sem->cond)); ubthread_mutex_unlock(&(sem->mutex)); } void sys_sem_free(struct sys_sem *sem) { if(sem != SYS_SEM_NULL) { sys_sem_free_(sem); } } static void sys_sem_free_(struct sys_sem *sem) { ubthread_cond_destroy(&(sem->cond)); ubthread_mutex_destroy(&(sem->mutex)); kfree(sem); } 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; } void sys_init() { struct timezone tz; gettimeofday(&starttime, &tz); } struct sys_timeouts *sys_arch_timeouts(void) { struct sys_thread *thread; thread = current_thread(); return(&thread->timeouts); } /*** END ***/