You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(35) |
Dec
(2) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(37) |
Feb
(10) |
Mar
|
Apr
(2) |
May
(17) |
Jun
(1) |
Jul
(14) |
Aug
(14) |
Sep
(4) |
Oct
|
Nov
(14) |
Dec
(4) |
2005 |
Jan
(6) |
Feb
|
Mar
|
Apr
(6) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
(92) |
Dec
(12) |
2006 |
Jan
(3) |
Feb
(4) |
Mar
|
Apr
(5) |
May
(3) |
Jun
(15) |
Jul
(3) |
Aug
(1) |
Sep
(29) |
Oct
(1) |
Nov
(6) |
Dec
(5) |
2007 |
Jan
(2) |
Feb
(2) |
Mar
|
Apr
(3) |
May
(14) |
Jun
(2) |
Jul
(16) |
Aug
(73) |
Sep
(12) |
Oct
(9) |
Nov
(27) |
Dec
(3) |
2008 |
Jan
(4) |
Feb
(4) |
Mar
(3) |
Apr
(8) |
May
(23) |
Jun
(4) |
Jul
(1) |
Aug
(3) |
Sep
(7) |
Oct
(5) |
Nov
(1) |
Dec
(1) |
2009 |
Jan
|
Feb
(10) |
Mar
|
Apr
(4) |
May
(4) |
Jun
(10) |
Jul
|
Aug
(1) |
Sep
|
Oct
(7) |
Nov
|
Dec
(1) |
2010 |
Jan
|
Feb
(1) |
Mar
|
Apr
(6) |
May
|
Jun
(3) |
Jul
(11) |
Aug
(1) |
Sep
|
Oct
(15) |
Nov
(1) |
Dec
(5) |
2011 |
Jan
(4) |
Feb
(1) |
Mar
(6) |
Apr
|
May
(22) |
Jun
|
Jul
(8) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2012 |
Jan
|
Feb
(10) |
Mar
(1) |
Apr
(6) |
May
(27) |
Jun
(48) |
Jul
(30) |
Aug
(4) |
Sep
|
Oct
(3) |
Nov
(1) |
Dec
(11) |
2013 |
Jan
(4) |
Feb
(7) |
Mar
(6) |
Apr
(18) |
May
(28) |
Jun
(20) |
Jul
|
Aug
(4) |
Sep
(1) |
Oct
(1) |
Nov
(2) |
Dec
(7) |
2014 |
Jan
(3) |
Feb
(2) |
Mar
(4) |
Apr
(9) |
May
(11) |
Jun
(10) |
Jul
|
Aug
(18) |
Sep
(12) |
Oct
(17) |
Nov
(10) |
Dec
(16) |
2015 |
Jan
(5) |
Feb
(1) |
Mar
(5) |
Apr
(4) |
May
(28) |
Jun
(2) |
Jul
|
Aug
|
Sep
(6) |
Oct
|
Nov
(2) |
Dec
(1) |
2016 |
Jan
(14) |
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
(3) |
Jul
(4) |
Aug
(4) |
Sep
(1) |
Oct
(1) |
Nov
|
Dec
(1) |
2017 |
Jan
(11) |
Feb
|
Mar
(21) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
(2) |
Sep
(4) |
Oct
(4) |
Nov
|
Dec
(1) |
2019 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(13) |
Sep
(4) |
Oct
|
Nov
|
Dec
|
2020 |
Jan
(10) |
Feb
(9) |
Mar
(5) |
Apr
(4) |
May
(3) |
Jun
(18) |
Jul
(4) |
Aug
(2) |
Sep
(20) |
Oct
(2) |
Nov
|
Dec
|
2021 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(1) |
Jun
(2) |
Jul
(1) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2022 |
Jan
(1) |
Feb
(2) |
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(5) |
Sep
|
Oct
(1) |
Nov
|
Dec
(1) |
2023 |
Jan
(10) |
Feb
(7) |
Mar
(29) |
Apr
(31) |
May
(29) |
Jun
(34) |
Jul
(3) |
Aug
(24) |
Sep
(22) |
Oct
(10) |
Nov
(38) |
Dec
(27) |
2024 |
Jan
(15) |
Feb
(8) |
Mar
(4) |
Apr
(20) |
May
(33) |
Jun
(18) |
Jul
(15) |
Aug
(23) |
Sep
(26) |
Oct
(32) |
Nov
(6) |
Dec
(4) |
2025 |
Jan
(7) |
Feb
(1) |
Mar
(1) |
Apr
(4) |
May
(46) |
Jun
(19) |
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <ljs...@us...> - 2012-06-12 00:39:51
|
Revision: 817 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=817&view=rev Author: ljsebald Date: 2012-06-12 00:39:45 +0000 (Tue, 12 Jun 2012) Log Message: ----------- Fix a few condvar functions to return int (and report possible errors), like their POSIX friends do. Modified Paths: -------------- kos/include/kos/cond.h kos/kernel/thread/cond.c Modified: kos/include/kos/cond.h =================================================================== --- kos/include/kos/cond.h 2012-06-11 02:50:03 UTC (rev 816) +++ kos/include/kos/cond.h 2012-06-12 00:39:45 UTC (rev 817) @@ -59,7 +59,7 @@ \headerfile kos/cond.h */ typedef struct condvar { - int initted; + int initialized; int dynamic; } condvar_t; @@ -97,8 +97,10 @@ This function frees a condition variable, releasing all memory associated with it (but not with the mutex that is associated with it). This will also wake all threads waiting on the condition. + + \retval 0 On success (no error conditions currently defined) */ -void cond_destroy(condvar_t *cv); +int cond_destroy(condvar_t *cv); /** \brief Wait on a condition variable. @@ -116,8 +118,10 @@ \retval -1 On error, sets errno as appropriate \par Error Conditions: - \em EPERM - Called inside an interrupt \n - \em EINTR - Was interrupted + \em EPERM - called inside an interrupt \n + \em EINVAL - the condvar was not initialized \n + \em EINVAL - the mutex is not initialized or not locked \n + \em ENOTRECOVERABLE - the condvar was destroyed while waiting */ int cond_wait(condvar_t *cv, mutex_t * m); @@ -139,9 +143,11 @@ \retval -1 On error, sets errno as appropriate \par Error Conditions: - \em EPERM - Called inside an interrupt \n - \em EINTR - Was interrupted \n - \em EAGAIN - timed out + \em EPERM - called inside an interrupt \n + \em ETIMEDOUT - timed out \n + \em EINVAL - the condvar was not initialized \n + \em EINVAL - the mutex is not initialized or not locked \n + \em ENOTRECOVERABLE - the condvar was destroyed while waiting */ int cond_wait_timed(condvar_t *cv, mutex_t * m, int timeout); @@ -152,8 +158,13 @@ before calling this to guarantee sane behavior. \param cv The condition to signal + \retval 0 On success + \retval -1 On error, errno will be set as appropriate + + \par Error Conditions: + \em EINVAL - the condvar was not initialized */ -void cond_signal(condvar_t *cv); +int cond_signal(condvar_t *cv); /** \brief Signal all threads waiting on the condition variable. @@ -162,8 +173,13 @@ before calling this to guarantee sane behavior. \param cv The condition to signal + \retval 0 On success + \retval -1 On error, errno will be set as appropriate + + \par Error Conditions: + \em EINVAL - the condvar was not initialized */ -void cond_broadcast(condvar_t *cv); +int cond_broadcast(condvar_t *cv); __END_DECLS Modified: kos/kernel/thread/cond.c =================================================================== --- kos/kernel/thread/cond.c 2012-06-11 02:50:03 UTC (rev 816) +++ kos/kernel/thread/cond.c 2012-06-12 00:39:45 UTC (rev 817) @@ -35,27 +35,30 @@ return NULL; } - cv->initted = 1; + cv->initialized = 1; cv->dynamic = 1; return cv; } int cond_init(condvar_t *cv) { - cv->initted = 1; + cv->initialized = 1; + cv->dynamic = 0; return 0; } /* Free a condvar */ -void cond_destroy(condvar_t *cv) { +int cond_destroy(condvar_t *cv) { /* Give all sleeping threads a timed out error */ - genwait_wake_all_err(cv, ETIMEDOUT); + genwait_wake_all_err(cv, ENOTRECOVERABLE); - cv->initted = 0; + cv->initialized = 0; /* Free the memory */ if(cv->dynamic) free(cv); + + return 0; } int cond_wait_timed(condvar_t *cv, mutex_t *m, int timeout) { @@ -69,14 +72,28 @@ old = irq_disable(); + if(!cv->initialized) { + errno = EINVAL; + irq_restore(old); + return -1; + } + else if(m->type < MUTEX_TYPE_NORMAL || m->type > MUTEX_TYPE_RECURSIVE || + !mutex_is_locked(m)) { + errno = EINVAL; + irq_restore(old); + return -1; + } + /* First of all, release the associated mutex */ - assert(mutex_is_locked(m)); mutex_unlock(m); /* Now block us until we're signaled */ rv = genwait_wait(cv, timeout ? "cond_wait_timed" : "cond_wait", timeout, NULL); + if(rv < 0 && errno == EAGAIN) + errno = ETIMEDOUT; + /* Re-lock our mutex */ mutex_lock(m); @@ -90,24 +107,40 @@ return cond_wait_timed(cv, m, 0); } -void cond_signal(condvar_t *cv) { - int old = 0; +int cond_signal(condvar_t *cv) { + int old, rv = 0; old = irq_disable(); - /* Wake any one thread who's waiting */ - genwait_wake_one(cv); + if(!cv->initialized) { + errno = EINVAL; + rv = -1; + } + else { + /* Wake one thread who's waiting */ + genwait_wake_one(cv); + } irq_restore(old); + + return rv; } -void cond_broadcast(condvar_t *cv) { - int old = 0; +int cond_broadcast(condvar_t *cv) { + int old, rv = 0; old = irq_disable(); - /* Wake all threads who are waiting */ - genwait_wake_all(cv); + if(!cv->initialized) { + errno = EINVAL; + rv = -1; + } + else { + /* Wake all threads who are waiting */ + genwait_wake_all(cv); + } irq_restore(old); + + return rv; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-11 02:50:09
|
Revision: 816 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=816&view=rev Author: ljsebald Date: 2012-06-11 02:50:03 +0000 (Mon, 11 Jun 2012) Log Message: ----------- Fix the environ.sh.sample to more accurately match up with the state of things. Modified Paths: -------------- kos/doc/environ.sh.sample Modified: kos/doc/environ.sh.sample =================================================================== --- kos/doc/environ.sh.sample 2012-06-11 00:23:37 UTC (rev 815) +++ kos/doc/environ.sh.sample 2012-06-11 02:50:03 UTC (rev 816) @@ -46,8 +46,13 @@ #export KOS_CC_PREFIX="arm-elf" # If you are compiling for DC and have an ARM compiler, use these too. -export DC_ARM_BASE="/usr/local/dc/arm-elf" -export DC_ARM_PREFIX="arm-elf" +# If you're using a newer compiler (GCC 4.7.0 and newer), you should probably be +# using arm-eabi as the target, rather than arm-elf. dc-chain now defaults to +# arm-eabi, so that's the default here. +#export DC_ARM_BASE="/usr/local/dc/arm-elf" +#export DC_ARM_PREFIX="arm-elf" +export DC_ARM_BASE="/usr/local/dc/arm-eabi" +export DC_ARM_PREFIX="arm-eabi" # Expand PATH (comment out if you don't want this done here) export PATH="${PATH}:${KOS_CC_BASE}/bin:/usr/local/dc/bin" @@ -66,8 +71,11 @@ # are user specifyable, like optimization level and whether you want stack # traces enabled. Some platforms may have optimization restrictions, # please check README. +# GCC seems to have made -fomit-frame-pointer the default on many targets, so +# hence you may need -fno-omit-frame-pointer to actually have GCC spit out frame +# pointers. It won't hurt to have it in there either way. export KOS_CFLAGS="-O2 -fomit-frame-pointer" -# export KOS_CFLAGS="-O2 -DFRAME_POINTERS" +# export KOS_CFLAGS="-O2 -DFRAME_POINTERS -fno-omit-frame-pointer" # Everything else is pretty much shared. If you want to configure compiler # options or other such things, look at this file. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-11 00:23:44
|
Revision: 815 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=815&view=rev Author: ljsebald Date: 2012-06-11 00:23:37 +0000 (Mon, 11 Jun 2012) Log Message: ----------- Two things: 1. Update semaphores like all the other primitives have been. 2. Fix the GCC 4.5.2 patch so that GCC will actually compile. I don't recommend building a new toolchain at the moment, as the patch is still using deprecated functions. Modified Paths: -------------- kos/examples/dreamcast/basic/threading/general/general_threading_test.c kos/include/kos/sem.h kos/kernel/arch/dreamcast/hardware/network/broadband_adapter.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_dma.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_scene.c kos/kernel/arch/dreamcast/hardware/spudma.c kos/kernel/arch/dreamcast/sound/snd_iface.c kos/kernel/thread/sem.c kos/kernel/thread/thread.c kos/utils/dc-chain/patches/gcc-4.5.2-kos.diff Modified: kos/examples/dreamcast/basic/threading/general/general_threading_test.c =================================================================== --- kos/examples/dreamcast/basic/threading/general/general_threading_test.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/examples/dreamcast/basic/threading/general/general_threading_test.c 2012-06-11 00:23:37 UTC (rev 815) @@ -15,7 +15,7 @@ #include <kos.h> /* Semaphore used for timing below */ -semaphore_t *sem; +semaphore_t sem; /* This routine will be started as thread #0 */ void *thd_0(void *v) { @@ -38,7 +38,7 @@ for(i = 0; i < 30; i++) { printf("Hi from thread 1\n"); thd_sleep(100); - sem_signal(sem); + sem_signal(&sem); } printf("Thread 1 waiting:\n"); @@ -54,20 +54,20 @@ thd_sleep(50); for(i = 0; i < 29; i++) { - sem_wait(sem); + sem_wait(&sem); printf("Hi from thread 2\n"); } - printf("sem_wait_timed returns %d\n", sem_wait_timed(sem, 200)); - printf("sem_wait_timed returns %d\n", sem_wait_timed(sem, 200)); - printf("sem_wait_timed returns %d\n", sem_wait_timed(sem, 200)); + printf("sem_wait_timed returns %d\n", sem_wait_timed(&sem, 200)); + printf("sem_wait_timed returns %d\n", sem_wait_timed(&sem, 200)); + printf("sem_wait_timed returns %d\n", sem_wait_timed(&sem, 200)); printf("Thread 2 exiting\n"); return NULL; } /* Condvar/mutex used for timing below */ mutex_t mut = MUTEX_INITIALIZER; -condvar_t * cv; +condvar_t cv = COND_INITIALIZER; volatile int cv_ready = 0, cv_cnt = 0, cv_quit = 0; /* This routine will be started N times for the condvar testing */ @@ -78,7 +78,7 @@ for(; ;) { while(!cv_ready && !cv_quit) { - cond_wait(cv, &mut); + cond_wait(&cv, &mut); } if(!cv_quit) { @@ -122,7 +122,7 @@ t2 = thd_create(0, thd_2, NULL); /* Create a semaphore for timing purposes */ - sem = sem_create(1); + sem_init(&sem, 1); /* Enabling IRQs starts the thread scheduler */ irq_enable(); @@ -151,7 +151,6 @@ printf("\n\nCondvar test; starting threads\n"); printf("Main thread is %p\n", thd_current); - cv = cond_create(); for(i = 0; i < 10; i++) { t3[i] = thd_create(0, thd_3, (void *)i); @@ -166,7 +165,7 @@ mutex_lock(&mut); cv_ready = 1; printf("Signaling %d:\n", i); - cond_signal(cv); + cond_signal(&cv); mutex_unlock(&mut); thd_sleep(100); } @@ -177,7 +176,7 @@ mutex_lock(&mut); cv_ready = 1; printf("Signaling %d:\n", i); - cond_signal(cv); + cond_signal(&cv); mutex_unlock(&mut); } @@ -187,7 +186,7 @@ printf("\nBroadcast test:\n"); mutex_lock(&mut); cv_ready = 1; - cond_broadcast(cv); + cond_broadcast(&cv); mutex_unlock(&mut); thd_sleep(100); printf(" (only one should have gotten through)\n"); @@ -195,7 +194,7 @@ printf("\nKilling all condvar threads:\n"); mutex_lock(&mut); cv_quit = 1; - cond_broadcast(cv); + cond_broadcast(&cv); mutex_unlock(&mut); for(i = 0; i < 10; i++) Modified: kos/include/kos/sem.h =================================================================== --- kos/include/kos/sem.h 2012-06-10 18:29:40 UTC (rev 814) +++ kos/include/kos/sem.h 2012-06-11 00:23:37 UTC (rev 815) @@ -1,7 +1,8 @@ /* KallistiOS ##version## include/kos/sem.h - Copyright (C)2001,2003 Dan Potter + Copyright (C) 2001, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -14,9 +15,6 @@ predetermined number of resources available, and the semaphore maintains the resources. - A special case of semaphores are mutual exclusion locks. Mutual exclusion - locks are simply semaphores that have a count of 1 initially. - \author Dan Potter \see kos/mutex.h */ @@ -25,12 +23,9 @@ #define __KOS_SEM_H #include <sys/cdefs.h> + __BEGIN_DECLS -#include <arch/types.h> -#include <sys/queue.h> -#include <kos/thread.h> - /** \brief Semaphore type. This structure defines a semaphore. There are no public members of this @@ -39,27 +34,21 @@ \headerfile kos/sem.h */ typedef struct semaphore { - /** \cond */ - /* List entry for the global list of semaphores */ - LIST_ENTRY(semaphore) g_list; - - /* Basic semaphore info */ - int count; /* The semaphore count */ - /** \endcond */ + int initialized; /**< \brief Are we initialized? */ + int count; /**< \brief The semaphore count */ } semaphore_t; -/** \cond */ -LIST_HEAD(semlist, semaphore); -/** \endcond */ - /** \brief Initializer for a transient semaphore. \param value The initial count of the semaphore. */ -#define SEM_INITIALIZER(value) { { 0 }, value } +#define SEM_INITIALIZER(value) { 1, value } /** \brief Allocate a new semaphore. This function allocates and initializes a new semaphore for use. + This function is formally deprecated. Please update your code to use + sem_init() or static initialization with SEM_INITIALIZER instead. + \param value The initial count of the semaphore (the number of threads to allow in the critical section at a time) @@ -67,18 +56,37 @@ on failure and errno is set as appropriate. \par Error Conditions: - \em ENOMEM - out of memory + \em ENOMEM - out of memory \n + \em EINVAL - the semaphore's value is invalid (less than 0) */ -semaphore_t *sem_create(int value); +semaphore_t *sem_create(int value) __attribute__((deprecated)); -/** \brief Free a semaphore. +/** \brief Initialize a semaphore for use. - This function frees a semaphore, releasing all memory associated with it. It - is your responsibility to make sure that all threads waiting on the - semaphore are taken care of before destroying the semaphore. + This function initializes the semaphore passed in with the starting count + value specified. + + \param sm The semaphore to initialize + \param count The initial count of the semaphore + \retval 0 On success + \retval -1 On error, errno will be set as appropriate + + \par Error Conditions: + \em EINVAL - the semaphore's value is invalid (less than 0) */ -void sem_destroy(semaphore_t *sem); +int sem_init(semaphore_t *sm, int count); +/** \brief Destroy a semaphore. + + This function frees a semaphore, releasing any memory associated with it. If + there are any threads currently waiting on the semaphore, they will be woken + with an ENOTRECOVERABLE error. + + \param sm The semaphore to destroy + \retval 0 On success (no error conditions currently defined) +*/ +int sem_destroy(semaphore_t *sem); + /** \brief Wait on a semaphore. This function will decrement the semaphore's count and return, if resources @@ -95,7 +103,7 @@ \par Error Conditions: \em EPERM - called inside an interrupt \n - \em EINTR - was interrupted + \em EINVAL - the semaphore was not initialized */ int sem_wait(semaphore_t *sem); @@ -110,21 +118,19 @@ sem_trywait() for a safe function to call in an interrupt. \param sem The semaphore to wait on - \param timeout The maximum number of milliseconds to block + \param timeout The maximum number of milliseconds to block (a value + of 0 here will block indefinitely) \retval 0 On success \retval -1 On error, sets errno as appropriate \par Error Conditions: \em EPERM - called inside an interrupt \n - \em EINTR - was interrupted \n - \em EAGAIN - timed out while blocking + \em EINVAL - the semaphore was not initialized \n + \em EINVAL - the timeout value was invalid (less than 0) \n + \em ETIMEDOUT - timed out while blocking */ int sem_wait_timed(semaphore_t *sem, int timeout); -/* Attempt to wait on a semaphore. If the semaphore would block, - then return an error instead of actually blocking. Note that this - function, unlike the other waits, DOES work inside an interrupt. - EAGAIN - would block */ /** \brief "Wait" on a semaphore without blocking. This function will decrement the semaphore's count and return, if resources @@ -139,7 +145,8 @@ \retval -1 On error, sets errno as appropriate \par Error Conditions: - \em EAGAIN - resources are not available (sem_wait() would block) + \em EWOULDBLOCK - a call to sem_wait() would block \n + \em EINVAL - the semaphore was not initialized */ int sem_trywait(semaphore_t *sem); @@ -150,8 +157,13 @@ responsibility to make sure you only release resources you have. \param sem The semaphore to signal + \retval 0 On success + \retval -1 On error, sets errno as appropriate + + \par Error Conditions: + \em EINVAL - the semaphore was not initialized */ -void sem_signal(semaphore_t *sem); +int sem_signal(semaphore_t *sem); /** \brief Retrieve the number of available resources. @@ -165,13 +177,6 @@ */ int sem_count(semaphore_t *sem); -/** \cond */ -/* Init / shutdown */ -int sem_init(); -void sem_shutdown(); -/** \endcond */ - __END_DECLS #endif /* __KOS_SEM_H */ - Modified: kos/kernel/arch/dreamcast/hardware/network/broadband_adapter.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/network/broadband_adapter.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/network/broadband_adapter.c 2012-06-11 00:23:37 UTC (rev 815) @@ -479,14 +479,14 @@ static uint32 rx_size; static kthread_t * bba_rx_thread; -static semaphore_t * bba_rx_sema; +static semaphore_t bba_rx_sema; static int bba_rx_exit_thread; -static semaphore_t * bba_rx_sema2; +static semaphore_t bba_rx_sema2; static void bba_rx(); #ifdef TX_SEMA -static semaphore_t * tx_sema; +static semaphore_t tx_sema; #endif static uint8 * next_dst; @@ -500,7 +500,7 @@ if(room > 0 && (((rxin + 1) % MAX_PKTS) != rxout)) { rxin = (rxin + 1) % MAX_PKTS; - sem_signal(bba_rx_sema); + sem_signal(&bba_rx_sema); thd_schedule(1, 0); } else @@ -706,36 +706,36 @@ /* printf("bba_tx called from an irq !\n"); */ /* return 0; */ //return bba_rtx(pkt, len, wait); - if(sem_trywait(tx_sema)) { + if(sem_trywait(&tx_sema)) { //printf("bba_tx called from an irq while a thread was running it !\n"); return BBA_TX_OK; /* sorry guys ... */ } } else - sem_wait(tx_sema); + sem_wait(&tx_sema); res = bba_rtx(pkt, len, wait); - sem_signal(tx_sema); + sem_signal(&tx_sema); return res; } #endif void bba_lock() { - //sem_wait(bba_rx_sema2); + //sem_wait(&bba_rx_sema2); //asic_evt_disable(ASIC_EVT_EXP_PCI, BBA_ASIC_IRQ); } void bba_unlock() { //asic_evt_enable(ASIC_EVT_EXP_PCI, BBA_ASIC_IRQ); - //sem_signal(bba_rx_sema2); + //sem_signal(&bba_rx_sema2); } static int bcolor; static void *bba_rx_threadfunc(void *dummy) { while(!bba_rx_exit_thread) { - //sem_wait_timed(bba_rx_sema, 500); - sem_wait(bba_rx_sema); + //sem_wait_timed(&bba_rx_sema, 500); + sem_wait(&bba_rx_sema); if(bba_rx_exit_thread) break; @@ -963,8 +963,8 @@ // Start the BBA RX thread. assert(bba_rx_thread == NULL); - bba_rx_sema = sem_create(0); - bba_rx_sema2 = sem_create(1); + sem_init(&bba_rx_sema, 0); + sem_init(&bba_rx_sema2, 1); bba_rx_thread = thd_create(0, bba_rx_threadfunc, 0); bba_rx_thread->prio = 1; thd_set_label(bba_rx_thread, "BBA-rx-thd"); @@ -996,13 +996,12 @@ /* VP : Shutdown rx thread */ assert(bba_rx_thread != NULL); bba_rx_exit_thread = 1; - sem_signal(bba_rx_sema); - sem_signal(bba_rx_sema2); + sem_signal(&bba_rx_sema); + sem_signal(&bba_rx_sema2); thd_join(bba_rx_thread, NULL); - sem_destroy(bba_rx_sema); - sem_destroy(bba_rx_sema2); + sem_destroy(&bba_rx_sema); + sem_destroy(&bba_rx_sema2); - bba_rx_sema = bba_rx_sema2 = NULL; bba_rx_thread = NULL; bba_if.flags &= ~NETIF_RUNNING; @@ -1119,14 +1118,13 @@ bba_set_rx_callback(bba_if_netinput); #ifdef TX_SEMA - tx_sema = sem_create(1); + sem_init(&tx_sema, 1); #endif /* VP : Initialize rx thread */ // Note: The thread itself is not created here, but when we actually // activate the adapter. This way we don't have a spare thread // laying around unless it's actually needed. - bba_rx_sema = bba_rx_sema2 = NULL; bba_rx_thread = NULL; /* Setup the structure */ @@ -1198,7 +1196,7 @@ bba_if.if_shutdown(&bba_if); #ifdef TX_SEMA - sem_destroy(tx_sema); + sem_destroy(&tx_sema); #endif return 0; Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_dma.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_dma.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_dma.c 2012-06-11 00:23:37 UTC (rev 815) @@ -18,7 +18,7 @@ /* Modified for inclusion into KOS by Dan Potter */ /* Signaling semaphore */ -static semaphore_t * dma_done; +static semaphore_t dma_done; static int dma_blocking; static pvr_dma_callback_t dma_callback; static ptr_t dma_cbdata; @@ -61,7 +61,7 @@ // Signal the calling thread to continue, if any. if(dma_blocking) { - sem_signal(dma_done); + sem_signal(&dma_done); thd_schedule(1, 0); dma_blocking = 0; } @@ -129,7 +129,7 @@ /* Wait for us to be signaled */ if(block) - sem_wait(dma_done); + sem_wait(&dma_done); return 0; } @@ -150,7 +150,7 @@ void pvr_dma_init() { /* Create an initially blocked semaphore */ - dma_done = sem_create(0); + sem_init(&dma_done, 0); dma_blocking = 0; dma_callback = NULL; dma_cbdata = 0; @@ -169,5 +169,5 @@ /* Clean up */ asic_evt_disable(ASIC_EVT_PVR_DMA, ASIC_IRQ_DEFAULT); asic_evt_set_handler(ASIC_EVT_PVR_DMA, NULL); - sem_destroy(dma_done); + sem_destroy(&dma_done); } Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c 2012-06-11 00:23:37 UTC (rev 815) @@ -174,7 +174,7 @@ pvr_dma_init(); /* Setup our wait-ready semaphore */ - pvr_state.ready_sem = sem_create(0); + sem_init((semaphore_t *)&pvr_state.ready_sem, 0); /* Set us as valid and return success */ pvr_state.valid = 1; @@ -225,7 +225,7 @@ pvr_mem_reset(); /* Destroy the semaphore */ - sem_destroy(pvr_state.ready_sem); + sem_destroy((semaphore_t *)&pvr_state.ready_sem); mutex_destroy((mutex_t *)&pvr_state.dma_lock); /* Clear video memory */ Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h 2012-06-11 00:23:37 UTC (rev 815) @@ -206,7 +206,7 @@ /* Wait-ready semaphore: this will be signaled whenever the pvr_wait_ready() call should be ready to return. */ - semaphore_t * ready_sem; + semaphore_t ready_sem; // Handle for the vblank interrupt int vbl_handle; Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c 2012-06-11 00:23:37 UTC (rev 815) @@ -67,7 +67,7 @@ pvr_state.dma_buffers[pvr_state.ram_target ^ 1].ready = 0; // Signal the client code to continue onwards. - sem_signal(pvr_state.ready_sem); + sem_signal((semaphore_t *)&pvr_state.ready_sem); thd_schedule(1, 0); } } @@ -164,7 +164,7 @@ // If we're not in DMA mode, then signal the client code // to continue onwards. if(!pvr_state.dma_mode) { - sem_signal(pvr_state.ready_sem); + sem_signal((semaphore_t *)&pvr_state.ready_sem); thd_schedule(1, 0); } Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_scene.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_scene.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_scene.c 2012-06-11 00:23:37 UTC (rev 815) @@ -296,7 +296,7 @@ assert(pvr_state.valid); - t = sem_wait_timed(pvr_state.ready_sem, 100); + t = sem_wait_timed((semaphore_t *)&pvr_state.ready_sem, 100); if(t < 0) { #if 0 @@ -320,7 +320,7 @@ int pvr_check_ready() { assert(pvr_state.valid); - if(sem_count(pvr_state.ready_sem) > 0) + if(sem_count((semaphore_t *)&pvr_state.ready_sem) > 0) return 0; else return -1; Modified: kos/kernel/arch/dreamcast/hardware/spudma.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/spudma.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/hardware/spudma.c 2012-06-11 00:23:37 UTC (rev 815) @@ -89,7 +89,7 @@ /* Signaling semaphore */ -static semaphore_t * dma_done[4]; +static semaphore_t dma_done[4]; static int dma_blocking[4]; static g2_dma_callback_t dma_callback[4]; static ptr_t dma_cbdata[4]; @@ -130,7 +130,7 @@ // Signal the calling thread to continue, if any. if(dma_blocking[chn]) { - sem_signal(dma_done[chn]); + sem_signal(&dma_done[chn]); thd_schedule(1, 0); dma_blocking[chn] = 0; } @@ -218,7 +218,7 @@ /* Wait for us to be signaled */ if(block) - sem_wait(dma_done[g2chn]); + sem_wait(&dma_done[g2chn]); return 0; } @@ -243,7 +243,7 @@ for(i = 0; i < 4; i++) { /* Create an initially blocked semaphore */ - dma_done[i] = sem_create(0); + sem_init(&dma_done[i], 0); dma_blocking[i] = 0; dma_callback[i] = NULL; dma_cbdata[i] = 0; @@ -277,7 +277,7 @@ asic_evt_set_handler(ASIC_EVT_SPU_DMA + i, NULL); /* Destroy the semaphore */ - sem_destroy(dma_done[i]); + sem_destroy(&dma_done[i]); /* Turn off any remaining DMA */ dma_disable(i); Modified: kos/kernel/arch/dreamcast/sound/snd_iface.c =================================================================== --- kos/kernel/arch/dreamcast/sound/snd_iface.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/arch/dreamcast/sound/snd_iface.c 2012-06-11 00:23:37 UTC (rev 815) @@ -30,7 +30,7 @@ extern uint8 snd_stream_drv_end[]; /* Thread semaphore */ -static semaphore_t * sem_qram; +static semaphore_t sem_qram; /* Initialize driver; note that this replaces the AICA program so that if you had anything else going on, it's gone now! */ @@ -57,7 +57,7 @@ snd_mem_init(AICA_RAM_START); /* Setup semaphores */ - sem_qram = sem_create(1); + sem_init(&sem_qram, 1); } initted = 1; @@ -69,7 +69,7 @@ void snd_shutdown() { if(initted) { spu_disable(); - sem_destroy(sem_qram); + sem_destroy(&sem_qram); snd_mem_shutdown(); initted = 0; } @@ -80,7 +80,7 @@ uint32 qa, bot, start, top, *pkt32, cnt; assert_msg(size < 256, "SH4->AICA packets may not be >256 uint32's long"); - sem_wait(sem_qram); + sem_wait(&sem_qram); /* Set these up for reference */ qa = SPU_RAM_BASE + AICA_MEM_CMD_QUEUE; @@ -118,7 +118,7 @@ /* We could wait until head == tail here for processing, but there's not really much point; it'll just slow things down. */ - sem_signal(sem_qram); + sem_signal(&sem_qram); return 0; } @@ -140,7 +140,7 @@ int snd_aica_to_sh4(void *packetout) { uint32 bot, start, stop, top, size, cnt, *pkt32; - sem_wait(sem_qram); + sem_wait(&sem_qram); /* Set these up for reference */ bot = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE; @@ -154,7 +154,7 @@ /* Is there anything? */ if(start == stop) { - sem_signal(sem_qram); + sem_signal(&sem_qram); return 0; } @@ -162,7 +162,7 @@ size = g2_read_32(start + offsetof(aica_cmd_t, size)); if(cnt >= AICA_CMD_MAX_SIZE) { - sem_signal(sem_qram); + sem_signal(&sem_qram); dbglog(DBG_ERROR, "snd_aica_to_sh4(): packet larger than %d dwords\n", AICA_CMD_MAX_SIZE); return -1; } @@ -195,7 +195,7 @@ /* Finally, write a new tail value to signify that we've removed a packet */ g2_write_32(bot + offsetof(aica_queue_t, tail), start - (SPU_RAM_BASE + AICA_MEM_RESP_QUEUE)); - sem_signal(sem_qram); + sem_signal(&sem_qram); return 1; } Modified: kos/kernel/thread/sem.c =================================================================== --- kos/kernel/thread/sem.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/thread/sem.c 2012-06-11 00:23:37 UTC (rev 815) @@ -1,7 +1,8 @@ /* KallistiOS ##version## sem.c - Copyright (c)2001,2002,2003 Dan Potter + Copyright (C) 2001, 2002, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ /* Defines semaphores */ @@ -18,98 +19,66 @@ #include <kos/limits.h> #include <kos/sem.h> #include <kos/genwait.h> -#include <sys/queue.h> -#include <arch/spinlock.h> /**************************************/ -/* Semaphore list spinlock */ -static spinlock_t mutex; - -/* Global list of semaphores */ -static struct semlist sem_list; - /* Allocate a new semaphore; the semaphore will be assigned to the calling process and when that process dies, the semaphore will also die. */ semaphore_t *sem_create(int value) { semaphore_t *sm; - /* Create a semaphore structure */ - sm = (semaphore_t*)malloc(sizeof(semaphore_t)); + dbglog(DBG_WARNING, "Creating semaphore with deprecated sem_create(). " + "Please update your code!\n"); - if(!sm) { + if(value < 0) { + errno = EINVAL; + return NULL; + } + + /* Create a semaphore structure */ + if(!(sm = (semaphore_t*)malloc(sizeof(semaphore_t)))) { errno = ENOMEM; return NULL; } sm->count = value; + sm->initialized = 2; - /* Add to the global list */ - spinlock_lock(&mutex); - LIST_INSERT_HEAD(&sem_list, sm, g_list); - spinlock_unlock(&mutex); - return sm; } -/* Take care of destroying a semaphore */ -void sem_destroy(semaphore_t *sm) { - /* XXX Do something with queued threads */ +int sem_init(semaphore_t *sm, int count) { + if(sm->count < 0) { + errno = EINVAL; + return -1; + } - /* Remove it from the global list */ - spinlock_lock(&mutex); - LIST_REMOVE(sm, g_list); - spinlock_unlock(&mutex); - - /* Free the memory */ - free(sm); + sm->count = count; + sm->initialized = 1; + return 0; } -int sem_wait(semaphore_t *sm) { - int old, rv = 0; +/* Take care of destroying a semaphore */ +int sem_destroy(semaphore_t *sm) { + /* Wake up any queued threads with an error */ + genwait_wake_all_err(sm, ENOTRECOVERABLE); - if(irq_inside_int()) { - dbglog(DBG_WARNING, "sem_wait: called inside interrupt\n"); - errno = EPERM; - return -1; + if(sm->initialized == 2) { + /* Free the memory */ + free(sm); } - - old = irq_disable(); - - /* If there's enough count left, then let the thread proceed */ - if(sm->count > 0) { - sm->count--; - } else { - /* Block us until we're signaled */ - sm->count--; - rv = genwait_wait(sm, "sem_wait", 0, NULL); - - /* Did we get interrupted? */ - if(rv < 0) { - assert(errno == EINTR); - rv = -1; - } + sm->count = 0; + sm->initialized = 0; } - irq_restore(old); - - return rv; + return 0; } -/* This function will be called by genwait if we timeout. */ -static void sem_timeout(void * obj) { - /* Convert it back to a semaphore ptr */ - semaphore_t * s = (semaphore_t *)obj; - - /* Release a thread from the count */ - s->count++; -} - /* Wait on a semaphore, with timeout (in milliseconds) */ int sem_wait_timed(semaphore_t *sem, int timeout) { - int old = 0, rv = 0; + int old, rv = 0; /* Make sure we're not inside an interrupt */ if(irq_inside_int()) { @@ -119,22 +88,36 @@ } /* Check for smarty clients */ - if(timeout <= 0) { - return sem_wait(sem); + if(timeout < 0) { + errno = EINVAL; + return -1; } /* Disable interrupts */ old = irq_disable(); + if(sem->initialized != 1 && sem->initialized != 2) { + errno = EINVAL; + rv = -1; + } /* If there's enough count left, then let the thread proceed */ - if(sem->count > 0) { + else if(sem->count > 0) { sem->count--; - rv = 0; } else { /* Block us until we're signaled */ sem->count--; - rv = genwait_wait(sem, "sem_wait_timed", timeout, sem_timeout); + rv = genwait_wait(sem, timeout ? "sem_wait_timed" : "sem_wait", timeout, + NULL); + + /* Did we fail to get the lock? */ + if(rv < 0) { + rv = -1; + ++sem->count; + + if(errno == EAGAIN) + errno = ETIMEDOUT; + } } irq_restore(old); @@ -142,38 +125,48 @@ return rv; } +int sem_wait(semaphore_t *sm) { + return sem_wait_timed(sm, 0); +} + /* Attempt to wait on a semaphore. If the semaphore would block, then return an error instead of actually blocking. */ int sem_trywait(semaphore_t *sm) { - int old = 0; - int succeeded; + int old, rv = 0; old = irq_disable(); + if(sm->initialized != 1 && sm->initialized != 2) { + errno = EINVAL; + rv = -1; + } /* Is there enough count left? */ - if(sm->count > 0) { + else if(sm->count > 0) { sm->count--; - succeeded = 0; } else { - succeeded = -1; - errno = EAGAIN; + rv = -1; + errno = EWOULDBLOCK; } /* Restore interrupts */ irq_restore(old); - return succeeded; + return rv; } /* Signal a semaphore */ -void sem_signal(semaphore_t *sm) { - int old = 0, woken; +int sem_signal(semaphore_t *sm) { + int old, woken, rv = 0; old = irq_disable(); + if(sm->initialized != 1 && sm->initialized != 2) { + errno = EINVAL; + rv = -1; + } /* Is there anyone waiting? If so, pass off to them */ - if(sm->count < 0) { + else if(sm->count < 0) { woken = genwait_wake_cnt(sm, 1, 0); assert(woken == 1); sm->count++; @@ -184,6 +177,8 @@ } irq_restore(old); + + return rv; } /* Return the semaphore count */ @@ -191,15 +186,3 @@ /* Look for the semaphore */ return sm->count; } - -/* Initialize semaphore structures */ -int sem_init() { - LIST_INIT(&sem_list); - spinlock_init(&mutex); - return 0; -} - -/* Shut down semaphore structures */ -void sem_shutdown() { } - - Modified: kos/kernel/thread/thread.c =================================================================== --- kos/kernel/thread/thread.c 2012-06-10 18:29:40 UTC (rev 814) +++ kos/kernel/thread/thread.c 2012-06-11 00:23:37 UTC (rev 815) @@ -61,7 +61,7 @@ int thd_mode = THD_MODE_NONE; /* Reaper semaphore. Counts the number of threads waiting to be reaped. */ -static semaphore_t *thd_reap_sem; +static semaphore_t thd_reap_sem; /* Number of threads active in the system. */ static uint32 thd_count = 0; @@ -194,7 +194,7 @@ for(;;) { /* Wait til we have something to reap */ - sem_wait(thd_reap_sem); + sem_wait(&thd_reap_sem); /* Find the first zombie thread and reap it (only do one at a time so that the semaphore stays current) */ @@ -238,7 +238,7 @@ /* Call Dr. Kevorkian; after this executes we could be killed at any time. */ thd_current->state = STATE_ZOMBIE; - sem_signal(thd_reap_sem); + sem_signal(&thd_reap_sem); } else { /* Mark the thread as finished and wake up anyone that has tried to join @@ -545,7 +545,7 @@ /* Unfortunately we have to take care of this here */ if(thd_current->state == STATE_ZOMBIE) { - sem_signal(thd_reap_sem); + sem_signal(&thd_reap_sem); } else if(thd_current->state == STATE_RUNNING) { thd_current->state = STATE_READY; @@ -855,7 +855,7 @@ idle->state = STATE_READY; /* Set up a thread to reap old zombies */ - thd_reap_sem = sem_create(0); + sem_init(&thd_reap_sem, 0); reaper = thd_create(0, thd_reaper, NULL); strcpy(reaper->label, "[reaper]"); thd_set_prio(reaper, 1); @@ -869,7 +869,6 @@ /* Initialize thread sync primitives */ genwait_init(); - sem_init(); /* Setup our pre-emption handler */ timer_primary_set_callback(thd_timer_hnd); @@ -906,8 +905,9 @@ n1 = n2; } + sem_destroy(&thd_reap_sem); + /* Shutdown thread sync primitives */ - sem_shutdown(); genwait_shutdown(); kthread_tls_shutdown(); Modified: kos/utils/dc-chain/patches/gcc-4.5.2-kos.diff =================================================================== --- kos/utils/dc-chain/patches/gcc-4.5.2-kos.diff 2012-06-10 18:29:40 UTC (rev 814) +++ kos/utils/dc-chain/patches/gcc-4.5.2-kos.diff 2012-06-11 00:23:37 UTC (rev 815) @@ -1879,7 +1879,7 @@ +static inline int __gthread_cond_wait_recursive(__gthread_cond_t *cond, + __gthread_recursive_mutex_t *mutex) { + assert(cond); -+ return cond_wait_recursive(*cond, *mutex); ++ return cond_wait(*cond, *mutex); +} + +/* C++0x support functions */ @@ -1947,7 +1947,7 @@ + const __gthread_time_t *timeout) { + int t = (int)(timeout->tv_sec + (timeout->tv_nsec / 1000)); + assert(cond); -+ return cond_wait_timed_recursive(*cond, *l, t); ++ return cond_wait_timed(*cond, *l, t); +} + +#endif /* _LIBOBJC */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-10 18:29:47
|
Revision: 814 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=814&view=rev Author: ljsebald Date: 2012-06-10 18:29:40 +0000 (Sun, 10 Jun 2012) Log Message: ----------- Update reader/writer semaphores a bit (adding a few new functions and such). Modified Paths: -------------- kos/examples/dreamcast/basic/threading/rwsem/rwsem_test.c kos/include/kos/rwsem.h kos/kernel/net/net_tcp.c kos/kernel/thread/rwsem.c kos/kernel/thread/thread.c Modified: kos/examples/dreamcast/basic/threading/rwsem/rwsem_test.c =================================================================== --- kos/examples/dreamcast/basic/threading/rwsem/rwsem_test.c 2012-06-10 18:28:57 UTC (rev 813) +++ kos/examples/dreamcast/basic/threading/rwsem/rwsem_test.c 2012-06-10 18:29:40 UTC (rev 814) @@ -22,21 +22,22 @@ #define UNUSED __attribute__((unused)) -rw_semaphore_t *s = NULL; +rw_semaphore_t s = RWSEM_INITIALIZER; uint32 number = 0; void *writer0(void *param UNUSED) { int i; for(i = 0; i < 20; ++i) { - if(rwsem_write_lock(s)) { + if(rwsem_write_lock(&s)) { printf("Writer 0 could not obtain write lock!\n"); + perror("rwsem_write_lock"); return NULL; } printf("Writer 0 obtained write lock\n"); number += 8; - rwsem_write_unlock(s); + rwsem_write_unlock(&s); thd_sleep(10); } @@ -49,14 +50,15 @@ int i; for(i = 0; i < 17; ++i) { - if(rwsem_write_lock(s)) { + if(rwsem_write_lock(&s)) { printf("Writer 1 could not obtain write lock!\n"); + perror("rwsem_write_lock"); return NULL; } printf("Writer 1 obtained write lock\n"); number *= 3; - rwsem_write_unlock(s); + rwsem_write_unlock(&s); thd_sleep(5); } @@ -69,14 +71,15 @@ int i; for(i = 0; i < 12; ++i) { - if(rwsem_read_lock(s)) { + if(rwsem_read_lock(&s)) { printf("Reader 0 could not obtain read lock!\n"); + perror("rwsem_read_lock"); return NULL; } printf("Reader 0 obtained read lock\n"); printf("Number: %lu\n", number); - rwsem_read_unlock(s); + rwsem_read_unlock(&s); thd_sleep(20); } @@ -89,14 +92,15 @@ int i; for(i = 0; i < 23; ++i) { - if(rwsem_read_lock(s)) { + if(rwsem_read_lock(&s)) { printf("Reader 1 could not obtain read lock!\n"); + perror("rwsem_read_lock"); return NULL; } printf("Reader 1 obtained read lock\n"); printf("Number * 2: %lu\n", number * 2); - rwsem_read_unlock(s); + rwsem_read_unlock(&s); thd_sleep(16); } @@ -115,14 +119,6 @@ printf("KallistiOS Reader/Writer Semaphore test program\n"); - /* Create the reader/writer semaphore that will be used. */ - s = rwsem_create(); - - if(!s) { - printf("Could not create RW semaphore, bailing out!\n"); - arch_exit(); - } - printf("About to create threads\n"); w0 = thd_create(0, writer0, NULL); w1 = thd_create(0, writer1, NULL); @@ -135,15 +131,16 @@ thd_join(r0, NULL); thd_join(r1, NULL); - if(rwsem_read_lock(s)) { + if(rwsem_read_lock(&s)) { printf("Could not obtain final read lock!\n"); + perror("rwsem_read_lock"); arch_exit(); } printf("Final number: %lu\n", number); - rwsem_read_unlock(s); - rwsem_destroy(s); + rwsem_read_unlock(&s); + rwsem_destroy(&s); printf("Reader/Writer semaphore tests completed successfully!\n"); return 0; Modified: kos/include/kos/rwsem.h =================================================================== --- kos/include/kos/rwsem.h 2012-06-10 18:28:57 UTC (rev 813) +++ kos/include/kos/rwsem.h 2012-06-10 18:29:40 UTC (rev 814) @@ -1,7 +1,7 @@ /* KallistiOS ##version## include/kos/rwsem.h - Copyright (C) 2008, 2010 Lawrence Sebald + Copyright (C) 2008, 2010, 2012 Lawrence Sebald */ @@ -29,7 +29,8 @@ __BEGIN_DECLS -#include <sys/queue.h> +#include <stddef.h> +#include <kos/thread.h> /** \brief Reader/writer semaphore structure. @@ -39,42 +40,80 @@ \headerfile kos/rwsem.h */ typedef struct rw_semaphore { - /** \cond */ - /* Entry into the global list of r/w semaphores. */ - LIST_ENTRY(rw_semaphore) list; - /** \endcond */ + /** \brief Are we initialized? */ + int initialized; /** \brief The number of readers that are currently holding the lock. */ int read_count; - /* \brief The state of the write lock. */ - int write_lock; + /** \brief The thread holding the write lock. */ + kthread_t *write_lock; + + /** \brief Space for one reader who's trying to upgrade to a writer. */ + kthread_t *reader_waiting; } rw_semaphore_t; -/** \cond */ -LIST_HEAD(rwsemlist, rw_semaphore); -/** \endcond */ +/** \brief Initializer for a transient reader/writer semaphore */ +#define RWSEM_INITIALIZER { 1, 0, NULL, NULL } /** \brief Allocate a reader/writer semaphore. This function allocates a new reader/writer lock that is initially not locked either for reading or writing. - \return The created semaphore, or NULL on failure (errno will be set to - ENOMEM to indicate that the system is out of memory). + This function is formally deprecated, and should not be used in newly + written code. Instead, please use rwsem_init(). + + \return The created semaphore, or NULL on failure (errno will be set as + appropriate). + + \par Error Conditions: + \em ENOMEM - out of memory */ -rw_semaphore_t *rwsem_create(); +rw_semaphore_t *rwsem_create() __attribute__((deprecated)); +/** \brief Initialize a reader/writer semaphore. + + This function initializes a new reader/writer semaphore for use. + + \retval 0 On success (no error conditions currently defined). +*/ +int rwsem_init(rw_semaphore_t *s); + /** \brief Destroy a reader/writer semaphore. This function cleans up a reader/writer semaphore. It is an error to attempt to destroy a r/w semaphore that is locked either for reading or writing. - \param s The r/w semaphore to destroy. It must be completely - unlocked. + \param s The r/w semaphore to destroy. + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EBUSY - the semaphore is still locked */ -void rwsem_destroy(rw_semaphore_t *s); +int rwsem_destroy(rw_semaphore_t *s); +/** \brief Lock a reader/writer semaphore for reading (with a timeout). + + This function attempts to lock the r/w semaphore for reading. If the + semaphore is locked for writing, this function will block until it is + possible to obtain the lock for reading or the timeout expires. This + function is <b>NOT</b> safe to call inside of an interrupt. + + \param s The r/w semaphore to lock. + \param timeout The maximum time to wait (in milliseconds). + \retval 0 On success + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - called inside an interrupt \n + \em ETIMEDOUT - the timeout expires before the lock can be acquired \n + \em EINVAL - the timeout value is invalid \n + \em EINVAL - the semaphore is not initialized +*/ +int rwsem_read_lock_timed(rw_semaphore_t *s, int timeout); + /** \brief Lock a reader/writer semaphore for reading. This function attempts to lock the r/w semaphore for reading. If the @@ -83,14 +122,35 @@ call inside of an interrupt. \param s The r/w semaphore to lock. - \retval -1 On error, errno will be set to EPERM if this function is - called inside an interrupt or EINTR if it is interrupted. - \retval 0 On success. - \sa rwsem_write_lock - \sa rwsem_read_trylock + \retval 0 On success + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - called inside an interrupt \n + \em EINVAL - the semaphore is not initialized */ int rwsem_read_lock(rw_semaphore_t *s); +/** \brief Lock a reader/writer semaphore for writing (with a timeout). + + This function attempts to lock the r/w semaphore for writing. If the + semaphore is locked for reading or writing, this function will block until + it is possible to obtain the lock for writing or the timeout expires. This + function is <b>NOT</b> safe to call inside of an interrupt. + + \param s The r/w semaphore to lock. + \param timeout The maximum time to wait (in milliseconds). + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - called inside an interrupt \n + \em ETIMEDOUT - the timeout expires before the lock can be acquired \n + \em EINVAL - the timeout value is invalid \n + \em EINVAL - the semaphore is not initialized +*/ +int rwsem_write_lock_timed(rw_semaphore_t *s, int timeout); + /** \brief Lock a reader/writer semaphore for writing. This function attempts to lock the r/w semaphore for writing. If the @@ -99,11 +159,12 @@ safe to call inside of an interrupt. \param s The r/w semaphore to lock. - \retval -1 On error, errno will be set to EPERM if this function is - called inside an interrupt or EINTR if it is interrupted. \retval 0 On success. - \sa rwsem_read_lock - \sa rwsem_write_trylock + \retval -1 On error, errno will be set as appropriate. + + \par Error conditions: + \em EPERM - called inside an interrupt \n + \em EINVAL - the semaphore is not initialized */ int rwsem_write_lock(rw_semaphore_t *s); @@ -112,8 +173,12 @@ This function releases one instance of the read lock on the r/w semaphore. \param s The r/w semaphore to release the read lock on. - \retval 0 On success (no error conditions defined). - \sa rwsem_write_unlock + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - the read lock is not currently held \n + \em EINVAL - the semaphore is not initialized */ int rwsem_read_unlock(rw_semaphore_t *s); @@ -122,11 +187,35 @@ This function releases one instance of the write lock on the r/w semaphore. \param s The r/w semaphore to release the write lock on. - \retval 0 On success (no error conditions defined). - \sa rwsem_read_unlock + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - the write lock is not currently held by the calling + thread \n + \em EINVAL - the semaphore is not initialized */ int rwsem_write_unlock(rw_semaphore_t *s); +/** \brief Unlock a reader/writer semaphore. + + This function releases the lock held by the current thread on the specified + reader/writer semaphore. This function will automatically determine which + lock is held by the calling thread and release it as appropriate. + + This function is <b>NOT</b> safe to call (in general) if you do not hold the + lock! + + \param s The r/w semaphore to release the lock on. + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - the lock is not currently held by the calling thread \n + \em EINVAL - the semaphore is not initialized +*/ +int rwsem_unlock(rw_semaphore_t *s); + /** \brief Attempt to lock a reader/writer semaphore for reading. This function attempts to lock the r/w semaphore for reading. If for any @@ -134,11 +223,12 @@ error. This function is safe to call inside an interrupt. \param s The r/w semaphore to attempt to lock. - \retval -1 On error, errno will be set to EWOULDBLOCK if a call to - rwsem_read_lock would normally block. \retval 0 On success. - \sa rwsem_write_trylock - \sa rwsem_read_lock + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EWOULDBLOCK - a call to rwsem_read_lock would block \n + \em EINVAL - the semaphore is not initialized */ int rwsem_read_trylock(rw_semaphore_t *s); @@ -149,14 +239,44 @@ error. This function is safe to call inside an interrupt. \param s The r/w semaphore to attempt to lock. - \retval -1 On error, errno will be set to EWOULDBLOCK if a call to - rwsem_write_lock would normally block. \retval 0 On success. - \sa rwsem_read_trylock - \sa rwsem_write_lock + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EWOULDBLOCK - a call to rwsem_write_lock would block \n + \em EINVAL - the semaphore is not initialized */ int rwsem_write_trylock(rw_semaphore_t *s); +/** \brief Upgrade a thread from reader status to writer status (with a + timeout). + + This function will upgrade the lock on the calling thread from a reader + state to a writer state. If it cannot do this at the moment, it will block + until it is possible. This function is <b>NOT</b> safe to call inside an + interrupt. + + You can only have one reader waiting to upgrade at a time, otherwise the + state would potentially become corrupted between when this is called and + when you get the lock. If you get -1 back from this, you must not assume + that you can write safely! On error, the calling thread will still hold a + read lock. + + \param s The r/w semaphore to upgrade. + \param timeout The maximum time to wait (in milliseconds). + \retval 0 On success. + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - called inside an interrupt \n + \em EINVAL - the semaphore is not initialized \n + \em EINVAL - the timeout value is invalid \n + \em EBUSY - another reader has already requested an upgrade \n + \em ETIMEDOUT - the timeout expired before the write lock could be + acquired +*/ +int rwsem_read_upgrade_timed(rw_semaphore_t *s, int timeout); + /** \brief Upgrade a thread from reader status to writer status. This function will upgrade the lock on the calling thread from a reader @@ -164,11 +284,20 @@ until it is possible. This function is <b>NOT</b> safe to call inside an interrupt. + You can only have one reader waiting to upgrade at a time, otherwise the + state would potentially become corrupted between when this is called and + when you get the lock. If you get -1 back from this, you must not assume + that you can write safely! On error, the calling thread will still hold a + read lock. + \param s The r/w semaphore to upgrade. - \retval -1 On error, errno will be set to EPERM if called inside an - interrupt or EINTR if interrupted. \retval 0 On success. - \sa rwsem_read_tryupgrade + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - called inside an interrupt \n + \em EINVAL - the semaphore is not initialized \n + \em EBUSY - another reader has already requested an upgrade */ int rwsem_read_upgrade(rw_semaphore_t *s); @@ -180,10 +309,13 @@ interrupt. Note that on error, the read lock is still held! \param s The r/w semaphore to upgrade. - \retval -1 On error, errno will be set to EWOULDBLOCK if a call to - rwsem_read_upgrade would normally block. \retval 0 On success. - \sa rwsem_read_upgrade + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EWOULDBLOCK - a call to rwsem_read_upgrade would block \n + \em EBUSY - another reader has already requested an upgrade \n + \em EINVAL - the sempahore is not initialized */ int rwsem_read_tryupgrade(rw_semaphore_t *s); @@ -208,12 +340,6 @@ */ int rwsem_write_locked(rw_semaphore_t *s); -/* Init / shutdown */ -/** \cond */ -int rwsem_init(); -void rwsem_shutdown(); -/** \endcond */ - __END_DECLS #endif /* __KOS_RWSEM_H */ Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-10 18:28:57 UTC (rev 813) +++ kos/kernel/net/net_tcp.c 2012-06-10 18:29:40 UTC (rev 814) @@ -178,7 +178,7 @@ LIST_HEAD(tcp_sock_list, tcp_sock); static struct tcp_sock_list tcp_socks = LIST_HEAD_INITIALIZER(0); -static rw_semaphore_t *tcp_sem = NULL; +static rw_semaphore_t tcp_sem = RWSEM_INITIALIZER; static int thd_cb_id = 0; /* Default starting window size for connections. This should be big enough as a @@ -276,20 +276,20 @@ sock->sndbuf_sz = TCP_DEFAULT_WINDOW; if(irq_inside_int()) { - if(rwsem_write_trylock(tcp_sem)) { + if(rwsem_write_trylock(&tcp_sem)) { free(sock); errno = EWOULDBLOCK; return -1; } } else { - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); } hnd->data = sock; LIST_INSERT_HEAD(&tcp_socks, sock, sock_list); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return 0; } @@ -302,17 +302,17 @@ retry: if(irq_inside_int()) { - if(rwsem_write_trylock(tcp_sem)) { + if(rwsem_write_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return; } } else { - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EBADF; return; } @@ -320,7 +320,7 @@ if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { errno = EWOULDBLOCK; - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return; } } @@ -333,7 +333,7 @@ happening if you're sane... */ if(sock->state == (TCP_STATE_LISTEN | TCP_STATE_ACCEPTING)) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); if(irq_inside_int()) { errno = EWOULDBLOCK; @@ -427,11 +427,10 @@ mutex_destroy(&sock->mutex); free(sock); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return; ret_no_remove: - if(sock->state != TCP_STATE_LISTEN) sock->intflags = TCP_IFLAG_CANBEDEL; @@ -444,7 +443,7 @@ /* Don't free anything here, it will be dealt with later on in the net_thd callback. */ mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return; } @@ -462,20 +461,20 @@ } if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } /* Lock the mutex on the socket itself first. We need to pull some data from it that doesn't affect the rest of the list, so let's start there... */ if(!(sock = (struct tcp_sock *)hnd->data)) { errno = EBADF; - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return -1; } @@ -484,7 +483,7 @@ if(mutex_trylock(&sock->mutex)) { errno = EWOULDBLOCK; - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return -1; } } @@ -493,7 +492,7 @@ canblock = !(sock->flags & FS_SOCKET_NONBLOCK); } - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); /* Make sure the socket is listening... */ if(sock->state != TCP_STATE_LISTEN) { @@ -520,7 +519,7 @@ graceful fashion. */ if(sock->state == TCP_STATE_CLOSED) { mutex_unlock(&sock->mutex); - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); mutex_lock(&sock->mutex); free(sock->listen.queue); cond_destroy(&sock->listen.cv); @@ -529,7 +528,7 @@ mutex_destroy(&sock->mutex); free(sock); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EINTR; /* Close enough, I suppose. */ return -1; @@ -659,7 +658,7 @@ } if(irq_inside_int()) { - if(rwsem_write_trylock(tcp_sem)) { + if(rwsem_write_trylock(&tcp_sem)) { /* Kabuki dance to clean things up... */ mutex_unlock(&sock->mutex); @@ -704,7 +703,7 @@ else { sock->state |= TCP_STATE_ACCEPTING; mutex_unlock(&sock->mutex); - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); mutex_lock(&sock->mutex); } @@ -733,7 +732,7 @@ sock->state &= ~TCP_STATE_ACCEPTING; mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return fd; } @@ -791,23 +790,24 @@ } if(irq_inside_int()) { - if(rwsem_write_trylock(tcp_sem)) { + if(rwsem_write_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EBADF; return -1; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { + rwsem_write_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -820,19 +820,19 @@ bound. */ if(sock->state == TCP_STATE_LISTEN) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EINVAL; return -1; } else if(sock->state != TCP_STATE_CLOSED) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EISCONN; return -1; } else if(sock->local_addr.sin6_port) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EINVAL; return -1; } @@ -841,7 +841,7 @@ on the socket itself */ if(addr->sa_family != sock->domain) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EINVAL; return -1; } @@ -857,7 +857,7 @@ if(irq_inside_int()) { if(mutex_trylock(&iter->mutex)) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -869,7 +869,7 @@ if(iter->local_addr.sin6_port == realaddr6.sin6_port) { mutex_unlock(&iter->mutex); mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EADDRINUSE; return -1; } @@ -893,7 +893,7 @@ if(irq_inside_int()) { if(mutex_trylock(&iter->mutex)) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -917,7 +917,7 @@ /* Release the locks, we're done */ mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return 0; } @@ -978,23 +978,24 @@ } if(irq_inside_int()) { - if(rwsem_write_trylock(tcp_sem)) { + if(rwsem_write_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EBADF; return -1; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { + rwsem_write_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1016,7 +1017,7 @@ } mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return -1; } @@ -1024,7 +1025,7 @@ on the socket itself */ if(addr->sa_family != sock->domain) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EINVAL; return -1; } @@ -1033,7 +1034,7 @@ if(IN6_IS_ADDR_UNSPECIFIED(&realaddr6.sin6_addr) || realaddr6.sin6_port == 0) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EADDRNOTAVAIL; return -1; } @@ -1053,7 +1054,7 @@ if(irq_inside_int()) { if(mutex_trylock(&iter->mutex)) { mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1087,14 +1088,14 @@ if(!(sock->data.rcvbuf = (uint8_t *)malloc(sock->rcvbuf_sz))) { errno = ENOBUFS; mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); return -1; } if(!(sock->data.sndbuf = (uint8_t *)malloc(sock->sndbuf_sz))) { errno = ENOBUFS; mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); free(sock->data.rcvbuf); return -1; } @@ -1102,7 +1103,7 @@ if(cond_init(&sock->data.send_cv)) { errno = ENOBUFS; mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); free(sock->data.sndbuf); free(sock->data.rcvbuf); return -1; @@ -1111,7 +1112,7 @@ if(cond_init(&sock->data.recv_cv)) { errno = ENOBUFS; mutex_unlock(&sock->mutex); - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); cond_destroy(&sock->data.send_cv); free(sock->data.sndbuf); free(sock->data.rcvbuf); @@ -1128,13 +1129,13 @@ /* Send a <SYN> packet */ if(tcp_send_syn(sock, 0) == -1) { - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); mutex_unlock(&sock->mutex); return -1; } /* Release the write lock... */ - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); /* Now, lets see if this is socket is non-blocking... */ if(sock->flags & FS_SOCKET_NONBLOCK || irq_inside_int()) { @@ -1174,17 +1175,17 @@ backlog = 1; if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } @@ -1193,7 +1194,7 @@ in here... */ if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1206,7 +1207,7 @@ actually move it to the listening state */ if(sock->state != TCP_STATE_CLOSED) { mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EINVAL; return -1; } @@ -1214,7 +1215,7 @@ /* Make sure the socket has been bound */ if(!sock->local_addr.sin6_port) { mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EDESTADDRREQ; return -1; } @@ -1224,7 +1225,7 @@ if(!sock->listen.queue) { mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = ENOBUFS; return -1; } @@ -1233,7 +1234,7 @@ free(sock->listen.queue); sock->listen.queue = NULL; mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = ENOBUFS; return -1; } @@ -1244,7 +1245,7 @@ /* We're done now, clean up the locks */ mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } @@ -1265,17 +1266,17 @@ } if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } @@ -1284,7 +1285,7 @@ in here... */ if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1293,7 +1294,7 @@ mutex_lock(&sock->mutex); } - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); /* Make sure they haven't shut down the socket... */ if(sock->flags & (SHUT_RD << 24)) { @@ -1424,17 +1425,17 @@ } if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } @@ -1443,7 +1444,7 @@ in here... */ if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1452,7 +1453,7 @@ mutex_lock(&sock->mutex); } - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); /* Check if the socket has been shut down for writing. */ if(sock->flags & (SHUT_WR << 24)) { @@ -1560,24 +1561,24 @@ struct tcp_sock *sock; if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1588,7 +1589,7 @@ if(how & 0xFFFFFFFC) { mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EINVAL; return -1; } @@ -1596,7 +1597,7 @@ sock->flags |= (how << 24); mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } @@ -1612,24 +1613,24 @@ } if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1692,18 +1693,17 @@ /* If it wasn't handled, return that error. */ mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = ENOPROTOOPT; return -1; ret_inval: mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EINVAL; return -1; copy_int: - if(*option_len >= sizeof(int)) { memcpy(option_value, &tmp, sizeof(int)); *option_len = sizeof(int); @@ -1713,7 +1713,7 @@ } mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } @@ -1728,24 +1728,24 @@ } if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1833,19 +1833,19 @@ /* If it wasn't handled, return that error. */ mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = ENOPROTOOPT; return -1; ret_inval: mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EINVAL; return -1; ret_success: mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } @@ -1856,17 +1856,17 @@ long val; if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { errno = EWOULDBLOCK; return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EBADF; return -1; } @@ -1875,7 +1875,7 @@ in here... */ if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); errno = EWOULDBLOCK; return -1; } @@ -1914,7 +1914,7 @@ out: mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return rv; } @@ -1923,24 +1923,24 @@ short rv = 0; if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { return 0; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } /* Lock the mutex on the socket itself first. We need to pull some data from it that doesn't affect the rest of the list, so let's start there... */ if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return POLLNVAL; } if(irq_inside_int()) { if(mutex_trylock(&sock->mutex)) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } } @@ -1990,7 +1990,7 @@ } mutex_unlock(&sock->mutex); - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return rv & (events | POLLHUP | POLLERR); } @@ -2785,19 +2785,19 @@ flags = ntohs(tcp->off_flags); if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { + if(rwsem_read_trylock(&tcp_sem)) { return -1; } } else { - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); } /* Find a matching socket */ if((s = find_sock(&srca, &dsta, tcp->src_port, tcp->dst_port, domain))) { /* Make sure we take care of busy sockets... */ if(s == (struct tcp_sock *) - 1) { - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); return 0; } @@ -2832,7 +2832,7 @@ mutex_unlock(&s->mutex); } - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); /* If we get in here, something went wrong... Send a RST. */ if(rv && !(flags & TCP_FLAG_RST)) { @@ -2846,7 +2846,7 @@ struct tcp_sock *i, *tmp; uint64_t timer; - rwsem_read_lock(tcp_sem); + rwsem_read_lock(&tcp_sem); LIST_FOREACH(i, &tcp_socks, sock_list) { mutex_lock(&i->mutex); @@ -2916,10 +2916,10 @@ mutex_unlock(&i->mutex); } - rwsem_read_unlock(tcp_sem); + rwsem_read_unlock(&tcp_sem); /* Go through and clean up any sockets that need to be destroyed. */ - rwsem_write_lock(tcp_sem); + rwsem_write_lock(&tcp_sem); i = LIST_FIRST(&tcp_socks); @@ -2940,7 +2940,7 @@ i = tmp; } - rwsem_write_unlock(tcp_sem); + rwsem_write_unlock(&tcp_sem); } /* Protocol handler for fs_socket. */ @@ -2966,14 +2966,9 @@ }; int net_tcp_init() { - if(!(tcp_sem = rwsem_create())) + if((thd_cb_id = net_thd_add_callback(tcp_thd_cb, NULL, 50)) < 0) return -1; - if((thd_cb_id = net_thd_add_callback(tcp_thd_cb, NULL, 50)) < 0) { - rwsem_destroy(tcp_sem); - return -1; - } - return fs_socket_proto_add(&proto); } @@ -3015,10 +3010,5 @@ /* Remove us from fs_socket and clean up the semaphore */ fs_socket_proto_remove(&proto); - if(tcp_sem) { - rwsem_destroy(tcp_sem); - tcp_sem = NULL; - } - irq_restore(old); } Modified: kos/kernel/thread/rwsem.c =================================================================== --- kos/kernel/thread/rwsem.c 2012-06-10 18:28:57 UTC (rev 813) +++ kos/kernel/thread/rwsem.c 2012-06-10 18:29:40 UTC (rev 814) @@ -1,82 +1,104 @@ /* KallistiOS ##version## rwsem.c - Copyright (C) 2008 Lawrence Sebald + Copyright (C) 2008, 2012 Lawrence Sebald */ /* Defines reader/writer semaphores */ -#include <malloc.h> #include <stdio.h> -#include <assert.h> +#include <stdlib.h> #include <errno.h> -#include <sys/queue.h> #include <kos/rwsem.h> #include <kos/genwait.h> -#include <arch/spinlock.h> -/* Reader/writer semaphore list spinlock */ -static spinlock_t mutex; - -/* Global list of reader/writer semaphores */ -static struct rwsemlist rwsem_list; - /* Allocate a new reader/writer semaphore */ rw_semaphore_t *rwsem_create() { rw_semaphore_t *s; - s = (rw_semaphore_t *)malloc(sizeof(rw_semaphore_t)); + dbglog(DBG_WARNING, "Creating reader/writer semaphore with deprecated " + "rwsem_create(). Please update your code!\n"); - if(!s) { + if(!(s = (rw_semaphore_t *)malloc(sizeof(rw_semaphore_t)))) { errno = ENOMEM; return NULL; } + s->initialized = 2; s->read_count = 0; - s->write_lock = 0; + s->write_lock = NULL; + s->reader_waiting = NULL; - spinlock_lock(&mutex); - LIST_INSERT_HEAD(&rwsem_list, s, list); - spinlock_unlock(&mutex); - return s; } +int rwsem_init(rw_semaphore_t *s) { + s->initialized = 1; + s->read_count = 0; + s->write_lock = NULL; + s->reader_waiting = NULL; + + return 0; +} + /* Destroy a reader/writer semaphore */ -void rwsem_destroy(rw_semaphore_t *s) { - /* XXXX: Should really cause anyone waiting to get an error back on their - wait... hmm. */ - spinlock_lock(&mutex); - LIST_REMOVE(s, list); - spinlock_unlock(&mutex); +int rwsem_destroy(rw_semaphore_t *s) { + int rv = 0, old; - free(s); + old = irq_disable(); + + if(s->read_count || s->write_lock) { + errno = EBUSY; + rv = -1; + } + else if(s->initialized == 2) { + free(s); + } + else { + s->initialized = 0; + } + + irq_restore(old); + return rv; } /* Lock a reader/writer semaphore for reading */ -int rwsem_read_lock(rw_semaphore_t *s) { +int rwsem_read_lock_timed(rw_semaphore_t *s, int timeout) { int old, rv = 0; if(irq_inside_int()) { - dbglog(DBG_WARNING, "rwsem_read_lock: called inside interrupt\n"); + dbglog(DBG_WARNING, "rwsem_read_lock_timed: called inside interrupt\n"); errno = EPERM; return -1; } + if(timeout < 0) { + errno = EINVAL; + return -1; + } + old = irq_disable(); + if(s->initialized != 1 && s->initialized != 2) { + irq_restore(old); + errno = EINVAL; + return -1; + } + /* If the write lock is not held, let the thread proceed */ if(!s->write_lock) { ++s->read_count; } else { /* Block until the write lock is not held any more */ - rv = genwait_wait(s, "rwsem_read_lock", 0, NULL); + rv = genwait_wait(s, timeout ? "rwsem_read_lock_timed" : + "rwsem_read_lock", timeout, NULL); if(rv < 0) { - assert(errno == EINTR); rv = -1; + if(errno == EAGAIN) + errno = ETIMEDOUT; } else { ++s->read_count; @@ -87,34 +109,52 @@ return rv; } +int rwsem_read_lock(rw_semaphore_t *s) { + return rwsem_read_lock_timed(s, 0); +} + /* Lock a reader/writer semaphore for writing */ -int rwsem_write_lock(rw_semaphore_t *s) { +int rwsem_write_lock_timed(rw_semaphore_t *s, int timeout) { int old, rv = 0; if(irq_inside_int()) { - dbglog(DBG_WARNING, "rwsem_write_lock: called inside interrupt\n"); + dbglog(DBG_WARNING, "rwsem_write_lock_timed: called inside " + "interrupt\n"); errno = EPERM; return -1; } + if(timeout < 0) { + errno = EINVAL; + return -1; + } + old = irq_disable(); + if(s->initialized != 1 && s->initialized != 2) { + irq_restore(old); + errno = EINVAL; + return -1; + } + /* If the write lock is not held and there are no readers in their critical sections, let the thread proceed. */ if(!s->write_lock && !s->read_count) { - s->write_lock = 1; + s->write_lock = thd_current; } else { /* Block until the write lock is not held and there are no readers inside their critical sections */ - rv = genwait_wait(&s->write_lock, "rwsem_write_lock", 0, NULL); + rv = genwait_wait(&s->write_lock, timeout ? "rwsem_write_lock_timed" : + "rwsem_write_lock", timeout, NULL); if(rv < 0) { - assert(errno == EINTR); rv = -1; + if(errno == EAGAIN) + errno = ETIMEDOUT; } else { - s->write_lock = 1; + s->write_lock = thd_current; } } @@ -122,17 +162,39 @@ return rv; } +int rwsem_write_lock(rw_semaphore_t *s) { + return rwsem_write_lock_timed(s, 0); +} + /* Unlock a reader/writer semaphore from a read lock. */ int rwsem_read_unlock(rw_semaphore_t *s) { int old; old = irq_disable(); + if(s->initialized != 1 && s->initialized != 2) { + irq_restore(old); + errno = EINVAL; + return -1; + } + + if(!s->read_count) { + irq_restore(old); + errno = EPERM; + return -1; + } + --s->read_count; /* If this was the last reader, attempt to wake any writers waiting. */ if(!s->read_count) { - genwait_wake_one(&s->write_lock); + if(s->reader_waiting) { + genwait_wake_thd(&s->write_lock, s->reader_waiting, 0); + s->reader_waiting = NULL; + } + else { + genwait_wake_one(&s->write_lock); + } } irq_restore(old); @@ -146,8 +208,20 @@ old = irq_disable(); - s->write_lock = 0; + if(s->initialized != 1 && s->initialized != 2) { + irq_restore(old); + errno = EINVAL; + return -1; + } + if(s->write_lock != thd_current) { + irq_restore(old); + errno = EPERM; + return -1; + } + + s->write_lock = NULL; + /* Give writers priority, attempt to wake any writers first. */ woken = genwait_wake_cnt(&s->write_lock, 1, 0); @@ -161,14 +235,44 @@ return 0; } +int rwsem_unlock(rw_semaphore_t *s) { + int old, rv; + + old = irq_disable(); + + if(s->initialized != 1 && s->initialized != 2) { + errno = EINVAL; + rv = -1; + } + else if(!s->write_lock && !s->read_count) { + errno = EPERM; + rv = -1; + } + /* Is this thread holding the write lock? */ + else if(s->write_lock == thd_current) { + rv = rwsem_write_unlock(s); + } + /* Not holding the write lock, assume its holding the read lock... */ + else { + rv = rwsem_read_unlock(s); + } + + irq_restore(old); + return rv; +} + /* Attempt to lock a reader/writer semaphore for reading, but do not block. */ int rwsem_read_trylock(rw_semaphore_t *s) { int old, rv; old = irq_disable(); - + + if(s->initialized != 1 && s->initialized != 2) { + rv = -1; + errno = EINVAL; + } /* Is the write lock held? */ - if(s->write_lock) { + else if(s->write_lock) { rv = -1; errno = EWOULDBLOCK; } @@ -187,15 +291,19 @@ old = irq_disable(); + if(s->initialized != 1 && s->initialized != 2) { + rv = -1; + errno = EINVAL; + } /* Are there any readers in their critical sections, or is the write lock already held, if so we can't do anything about that now. */ - if(s->read_count || s->write_lock) { + else if(s->read_count || s->write_lock) { rv = -1; errno = EWOULDBLOCK; } else { rv = 0; - s->write_lock = 1; + s->write_lock = thd_current; } irq_restore(old); @@ -203,53 +311,92 @@ } /* "Upgrade" a read lock to a write lock. */ -int rwsem_read_upgrade(rw_semaphore_t *s) { +int rwsem_read_upgrade_timed(rw_semaphore_t *s, int timeout) { int old, rv = 0; if(irq_inside_int()) { - dbglog(DBG_WARNING, "rwsem_read_upgrade: called inside interrupt\n"); + dbglog(DBG_WARNING, "rwsem_read_upgrade_timed: called inside " + "interrupt\n"); errno = EPERM; return -1; } + if(timeout < 0) { + errno = EINVAL; + return -1; + } + old = irq_disable(); - --s->read_count; - - /* If there are still other readers, wait patiently for our turn. */ - if(s->read_count) { - rv = genwait_wait(&s->write_lock, "rwsem_read_upgrade", 0, NULL); - - if(rv < 0) { - assert(errno == EINTR); + if(s->initialized != 1 && s->initialized != 2) { + rv = -1; + errno = EINVAL; + } + /* If there are still other readers, see if any other readers have tried to + upgrade or not... */ + else if(s->read_count > 1) { + if(s->reader_waiting) { + /* We've got someone ahead of us, so there's really not anything + that can be done at this point... */ rv = -1; + errno = EBUSY; } else { - s->write_lock = 1; + --s->read_count; + s->reader_waiting = thd_current; + rv = genwait_wait(&s->write_lock, timeout ? + "rwsem_read_upgrade_timed" : "rwsem_read_upgrade", + timeout, NULL); + + if(rv < 0) { + /* The only way we can error out is if there are still readers + with the lock, so we can safely re-grab the lock here. */ + ++s->read_count; + rv = -1; + + if(errno == EAGAIN) + errno = ETIMEDOUT; + } + else { + s->write_lock = thd_current; + } } } else { - s->write_lock = 1; + s->read_count = 0; + s->write_lock = thd_current; } irq_restore(old); return rv; } +int rwsem_read_upgrade(rw_semaphore_t *s) { + return rwsem_read_upgrade_timed(s, 0); +} + /* Attempt to upgrade a read lock to a write lock, but do not block. */ int rwsem_read_tryupgrade(rw_semaphore_t *s) { int old, rv; old = irq_disable(); - if(s->read_count != 1) { + if(s->initialized != 1 && s->initialized != 2) { rv = -1; + errno = EINVAL; + } + else if(s->reader_waiting) { + rv = -1; + errno = EBUSY; + } + else if(s->read_count != 1) { + rv = -1; errno = EWOULDBLOCK; } else { rv = 0; s->read_count = 0; - s->write_lock = 1; + s->write_lock = thd_current; } irq_restore(old); @@ -263,17 +410,5 @@ /* Return the current status of the write lock */ int rwsem_write_locked(rw_semaphore_t *s) { - return s->write_lock; + return !!s->write_lock; } - -/* Initialize reader/writer semaphores */ -int rwsem_init() { - LIST_INIT(&rwsem_list); - spinlock_init(&mutex); - return 0; -} - -/* Shut down reader/writer semaphores */ -void rwsem_shutdown() { - /* XXXX: Do something useful */ -} Modified: kos/kernel/thread/thread.c =================================================================== --- kos/kernel/thread/thread.c 2012-06-10 18:28:57 UTC (rev 813) +++ kos/kernel/thread/thread.c 2012-06-10 18:29:40 UTC (rev 814) @@ -869,7 +869,6 @@ /* Initialize thread sync primitives */ genwait_init(); - rwsem_init(); sem_init(); /* Setup our pre-emption handler */ @@ -908,7 +907,6 @@ } /* Shutdown thread sync primitives */ - rwsem_shutdown(); sem_shutdown(); genwait_shutdown(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-10 18:29:04
|
Revision: 813 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=813&view=rev Author: ljsebald Date: 2012-06-10 18:28:57 +0000 (Sun, 10 Jun 2012) Log Message: ----------- Actually document the select() function. Modified Paths: -------------- kos/include/sys/select.h Modified: kos/include/sys/select.h =================================================================== --- kos/include/sys/select.h 2012-06-10 15:46:05 UTC (rev 812) +++ kos/include/sys/select.h 2012-06-10 18:28:57 UTC (rev 813) @@ -37,6 +37,26 @@ suseconds_t tv_usec; /**< \brief Microseconds */ }; +/** \brief Wait for activity on a group of file descriptors. + + This function will check the specfied group of file descriptors for activity + and wait for activity (up to the timeout specified) if there is not any + pending events already. + + \param nfds The maximum fd specified in any of the sets, plus 1. + \param readfds File descriptors to check for the ability to read + without blocking. + \param writefds File descriptors to check for the ability to write + without blocking. + \param errorfds File descriptors to check for error/exceptional + conditions. + \param timeout Maximum amount of time to block. Passing a 0 timeout + will make the funciton not block, Passing NULL here will + make the function block indefinitely. + \return -1 on error (sets errno as appropriate), or the number + of bits set in the fd sets on success (this may be 0 if + the timeout expires). +*/ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-10 15:46:11
|
Revision: 812 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=812&view=rev Author: ljsebald Date: 2012-06-10 15:46:05 +0000 (Sun, 10 Jun 2012) Log Message: ----------- Check the timeout value in mutex_lock_timed(), as the documentation implies we do. Modified Paths: -------------- kos/kernel/thread/mutex.c Modified: kos/kernel/thread/mutex.c =================================================================== --- kos/kernel/thread/mutex.c 2012-06-10 15:44:49 UTC (rev 811) +++ kos/kernel/thread/mutex.c 2012-06-10 15:46:05 UTC (rev 812) @@ -91,6 +91,11 @@ return -1; } + if(timeout < 0) { + errno = EINVAL; + return -1; + } + old = irq_disable(); if(m->type < MUTEX_TYPE_NORMAL || m->type > MUTEX_TYPE_RECURSIVE) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-10 15:44:55
|
Revision: 811 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=811&view=rev Author: ljsebald Date: 2012-06-10 15:44:49 +0000 (Sun, 10 Jun 2012) Log Message: ----------- Add genwait_wake_thd() function. Modified Paths: -------------- kos/include/kos/genwait.h kos/kernel/thread/genwait.c Modified: kos/include/kos/genwait.h =================================================================== --- kos/include/kos/genwait.h 2012-06-09 23:16:30 UTC (rev 810) +++ kos/include/kos/genwait.h 2012-06-10 15:44:49 UTC (rev 811) @@ -25,7 +25,6 @@ #include <sys/cdefs.h> __BEGIN_DECLS -#include <sys/queue.h> #include <kos/thread.h> /** \brief Sleep on an object. @@ -106,6 +105,25 @@ */ void genwait_wake_one_err(void *obj, int err); +/** \brief Wake up a specific thread that is sleeping on an object. + + This function wakes up the specfied thread, assuming it is sleeping on the + specified object. + + \param obj The object to wake the thread from + \param thd The specific thread to wake + \param err The errno code to set as the errno value on the + woken thread. If this is 0 (EOK), then the thread's + errno will not be changed, and the thread will get a + return value of 0 from the genwait_wait(). If it is + non-zero, the thread will get a return value of -1 + and errno will be set to this value for the woken + threads. + \return The number of threads woken, which should be 1 on + success. +*/ +int genwait_wake_thd(void *obj, kthread_t *thd, int err); + /** \brief Look for timed out genwait_wait() calls. There should be no reason you need to call this function, it is called Modified: kos/kernel/thread/genwait.c =================================================================== --- kos/kernel/thread/genwait.c 2012-06-09 23:16:30 UTC (rev 810) +++ kos/kernel/thread/genwait.c 2012-06-10 15:44:49 UTC (rev 811) @@ -191,6 +191,48 @@ genwait_wake_cnt(obj, -1, err); } +int genwait_wake_thd(void *obj, kthread_t *thd, int err) { + kthread_t *t, *nt; + struct slpquehead *qp; + int old, rv = 0; + + /* Twiddle interrupt state */ + old = irq_disable(); + + /* Find the queue */ + qp = &slpque[LOOKUP(obj)]; + + /* Go through and find any matching entries */ + for(t = TAILQ_FIRST(qp); t != NULL; t = nt) { + /* Get the next thread up front */ + nt = TAILQ_NEXT(t, thdq); + + /* Is this thread a match? */ + if(t->wait_obj == obj && t == thd) { + /* Yes, remove it from the wait queue */ + genwait_unqueue(t); + + /* Set the wake return value */ + if(err) { + CONTEXT_RET(t->context) = -1; + t->thd_errno = err; + } + else { + CONTEXT_RET(t->context) = 0; + } + + /* We found it, so we're done... */ + rv = 1; + break; + } + } + + /* Re-fix IRQs */ + irq_restore(old); + + return rv; +} + void genwait_check_timeouts(uint64 tm) { kthread_t *t; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-09 23:16:38
|
Revision: 810 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=810&view=rev Author: ljsebald Date: 2012-06-09 23:16:30 +0000 (Sat, 09 Jun 2012) Log Message: ----------- Revert to GCC 4.5.2 for now, due to issue with GCC 4.7.0 and frame pointers on sh-elf. See GCC bug for more info: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53621 Modified Paths: -------------- kos/utils/dc-chain/Makefile kos/utils/dc-chain/download.sh kos/utils/dc-chain/unpack.sh Modified: kos/utils/dc-chain/Makefile =================================================================== --- kos/utils/dc-chain/Makefile 2012-06-09 04:29:38 UTC (rev 809) +++ kos/utils/dc-chain/Makefile 2012-06-09 23:16:30 UTC (rev 810) @@ -29,7 +29,7 @@ # kos_base: equivalent of KOS_BASE (contains include/ and kernel/) kos_base=$(kos_root)/kos binutils_ver=2.22 -gcc_ver=4.7.0 +gcc_ver=4.5.2 newlib_ver=1.20.0 gdb_ver=6.7.1 insight_ver=6.7.1 Modified: kos/utils/dc-chain/download.sh =================================================================== --- kos/utils/dc-chain/download.sh 2012-06-09 04:29:38 UTC (rev 809) +++ kos/utils/dc-chain/download.sh 2012-06-09 23:16:30 UTC (rev 810) @@ -1,5 +1,5 @@ #!/bin/sh wget -c ftp://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 || exit 1 -wget -c ftp://ftp.gnu.org/gnu/gcc/gcc-4.7.0/gcc-4.7.0.tar.bz2 || exit 1 +wget -c ftp://ftp.gnu.org/gnu/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2 || exit 1 wget -c ftp://sources.redhat.com/pub/newlib/newlib-1.20.0.tar.gz || exit 1 Modified: kos/utils/dc-chain/unpack.sh =================================================================== --- kos/utils/dc-chain/unpack.sh 2012-06-09 04:29:38 UTC (rev 809) +++ kos/utils/dc-chain/unpack.sh 2012-06-09 23:16:30 UTC (rev 810) @@ -1,7 +1,7 @@ #!/bin/sh -rm -rf binutils-2.22 gcc-4.7.0 newlib-1.20.0 +rm -rf binutils-2.22 gcc-4.5.2 newlib-1.20.0 tar jxf binutils-2.22.tar.bz2 || exit 1 -tar jxf gcc-4.7.0.tar.bz2 || exit 1 +tar jxf gcc-4.5.2.tar.bz2 || exit 1 tar zxf newlib-1.20.0.tar.gz || exit 1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-09 04:29:44
|
Revision: 809 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=809&view=rev Author: ljsebald Date: 2012-06-09 04:29:38 +0000 (Sat, 09 Jun 2012) Log Message: ----------- Update kos-ports for the updated condvar stuff. Modified Paths: -------------- kos-ports/lwip/kos/sockets.c kos-ports/lwip/kos/sys_arch.c Modified: kos-ports/lwip/kos/sockets.c =================================================================== --- kos-ports/lwip/kos/sockets.c 2012-06-09 04:18:22 UTC (rev 808) +++ kos-ports/lwip/kos/sockets.c 2012-06-09 04:29:38 UTC (rev 809) @@ -25,9 +25,9 @@ // Sync variables mutex_t mutex; // For the condvars - condvar_t * connect; // A connection was received on a listen() - condvar_t * recv_avail; // Received data is available - condvar_t * send_avail; // Send buffer space is available + condvar_t connect; // A connection was received on a listen() + condvar_t recv_avail; // Received data is available + condvar_t send_avail; // Send buffer space is available // Counters int conncnt; // Number of connections waiting @@ -79,9 +79,9 @@ // Setup some basic stuff mutex_init(&fds[i].mutex, MUTEX_TYPE_NORMAL); - fds[i].connect = cond_create(); - fds[i].recv_avail = cond_create(); - fds[i].send_avail = cond_create(); + cond_init(&fds[i].connect); + cond_init(&fds[i].recv_avail); + cond_init(&fds[i].send_avail); fds[i].connmax = 0; fds[i].conncnt = -1; @@ -99,9 +99,9 @@ } // Destroy all the sync objects - cond_destroy(fds[fd].connect); - cond_destroy(fds[fd].recv_avail); - cond_destroy(fds[fd].send_avail); + cond_destroy(&fds[fd].connect); + cond_destroy(&fds[fd].recv_avail); + cond_destroy(&fds[fd].send_avail); mutex_destroy(&fds[fd].mutex); fds[fd].inuse = 0; @@ -165,8 +165,8 @@ fd->recv = fd->send = -1; // Wake up anyone who was waiting - cond_broadcast(fd->recv_avail); - cond_broadcast(fd->send_avail); + cond_broadcast(&fd->recv_avail); + cond_broadcast(&fd->send_avail); mutex_unlock(&fd->mutex); @@ -200,7 +200,7 @@ // Here would be the place we'd want to implement TCP_NODELAY (or the lack // thereof) but for now we'll just send it all through... - cond_signal(fd->recv_avail); + cond_signal(&fd->recv_avail); // Note that we DON'T ACK the data until after a client has received // it using recv(). Otherwise the peer could send and send and send... @@ -242,7 +242,7 @@ // packet syndrome). rdy = fd->send >= 256; if (rdy) - cond_signal(fd->send_avail); + cond_signal(&fd->send_avail); mutex_unlock(&fd->mutex); @@ -335,7 +335,7 @@ fd->conncnt++; // Signal any thread waiting on accept() - cond_signal(fd->connect); + cond_signal(&fd->connect); out: mutex_unlock(&fd->mutex); @@ -364,7 +364,7 @@ fd->connerr = err; // Signal to proceed - cond_signal(fd->connect); + cond_signal(&fd->connect); mutex_unlock(&fd->mutex); @@ -535,7 +535,7 @@ // Wait for the result fd->connerr = 10; while (fd->connerr > 0) { - cond_wait(fd->connect, &fd->mutex); + cond_wait(&fd->connect, &fd->mutex); } // Convert error codes @@ -738,7 +738,7 @@ // Wait for a connection // printf("lwip_accept(%d): waiting\n", s); - cond_wait(fd->connect, &fd->mutex); + cond_wait(&fd->connect, &fd->mutex); } // Ok, we've got a connection. Find the first available one @@ -806,7 +806,7 @@ // Wait for more data to be available //printf("cond_wait for more data\n"); - cond_wait(fd->recv_avail, &fd->mutex); + cond_wait(&fd->recv_avail, &fd->mutex); //printf("woken\n"); } @@ -886,7 +886,7 @@ rv = 0; goto out; } - cond_wait(fd->send_avail, &fd->mutex); + cond_wait(&fd->send_avail, &fd->mutex); } // Send as much as we can. Modified: kos-ports/lwip/kos/sys_arch.c =================================================================== --- kos-ports/lwip/kos/sys_arch.c 2012-06-09 04:18:22 UTC (rev 808) +++ kos-ports/lwip/kos/sys_arch.c 2012-06-09 04:29:38 UTC (rev 809) @@ -126,10 +126,10 @@ mutex_t mutex; // Signaled whenever mail is available - condvar_t * mail; + condvar_t mail; // Signaled whenever a message is removed - condvar_t * avail; + condvar_t avail; }; @@ -140,8 +140,8 @@ mbox->head = mbox->tail = mbox->cnt = 0; mutex_init(&mbox->mutex, MUTEX_TYPE_NORMAL); - mbox->mail = cond_create(); - mbox->avail = cond_create(); + cond_init(&mbox->mail); + cond_init(&mbox->avail); #ifdef SYS_STATS lwip_stats.sys.mbox.used++; @@ -159,9 +159,8 @@ lwip_stats.sys.mbox.used--; #endif /* SYS_STATS */ mutex_destroy(&mbox->mutex); - cond_destroy(mbox->mail); - cond_destroy(mbox->avail); - mbox->mail = mbox->avail = NULL; + cond_destroy(&mbox->mail); + cond_destroy(&mbox->avail); /* DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox);*/ free(mbox); } @@ -173,14 +172,14 @@ DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", mbox, msg)); while (mbox->cnt >= SYS_MBOX_SIZE) { - cond_wait(mbox->avail, &mbox->mutex); + cond_wait(&mbox->avail, &mbox->mutex); } mbox->msgs[mbox->tail] = msg; mbox->cnt++; mbox->tail = (mbox->tail + 1) % SYS_MBOX_SIZE; - cond_signal(mbox->mail); + cond_signal(&mbox->mail); mutex_unlock(&mbox->mutex); } @@ -192,13 +191,13 @@ while (!mbox->cnt) { if (timeout) { - int foo = cond_wait_timed(mbox->mail, &mbox->mutex, timeout); + int foo = cond_wait_timed(&mbox->mail, &mbox->mutex, timeout); if (foo < 0) { time = SYS_ARCH_TIMEOUT; break; } } else - cond_wait(mbox->mail, &mbox->mutex); + cond_wait(&mbox->mail, &mbox->mutex); } if (mbox->cnt) { @@ -209,7 +208,7 @@ mbox->head = (mbox->head + 1) % SYS_MBOX_SIZE; mbox->cnt--; - cond_signal(mbox->avail); + cond_signal(&mbox->avail); } mutex_unlock(&mbox->mutex); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-09 04:18:29
|
Revision: 808 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=808&view=rev Author: ljsebald Date: 2012-06-09 04:18:22 +0000 (Sat, 09 Jun 2012) Log Message: ----------- A few new things in here: 1. Add functionality to genwait to wake threads with a specified error value. 2. Update condvars, like was done for mutexes earlier. Modified Paths: -------------- kos/include/kos/cond.h kos/include/kos/genwait.h kos/include/pthread.h kos/include/sys/sched.h kos/kernel/fs/fs_pty.c kos/kernel/libc/pthreads/pthread_cond.c kos/kernel/net/net_tcp.c kos/kernel/thread/cond.c kos/kernel/thread/genwait.c kos/kernel/thread/rwsem.c kos/kernel/thread/sem.c kos/kernel/thread/thread.c Modified: kos/include/kos/cond.h =================================================================== --- kos/include/kos/cond.h 2012-06-09 04:17:01 UTC (rev 807) +++ kos/include/kos/cond.h 2012-06-09 04:18:22 UTC (rev 808) @@ -48,7 +48,6 @@ __BEGIN_DECLS #include <arch/types.h> -#include <sys/queue.h> #include <kos/thread.h> #include <kos/mutex.h> @@ -60,31 +59,39 @@ \headerfile kos/cond.h */ typedef struct condvar { - /** \cond */ - /* List entry for the global list of condvars */ - LIST_ENTRY(condvar) g_list; - /** \endcond */ + int initted; + int dynamic; } condvar_t; -/* \cond */ -LIST_HEAD(condlist, condvar); -/* \endcond */ - /** \brief Initializer for a transient condvar. */ -#define COND_INITIALIZER { { 0 } } +#define COND_INITIALIZER { 1, 0 } /** \brief Allocate a new condition variable. This function allocates and initializes a new condition variable for use. + This function is formally deprecated and should not be used in new code. + Instead you should use either the static initializer or the cond_init() + function. + \return The created condvar on success. NULL is returned on failure and errno is set as appropriate. \par Error Conditions: \em ENOMEM - out of memory */ -condvar_t *cond_create(); +condvar_t *cond_create() __attribute__((deprecated)); +/** \brief Initialize a condition variable. + + This function initializes a new condition variable for use. + + \param cv The condition variable to initialize + \retval 0 On success + \retval -1 On error, sets errno as appropriate +*/ +int cond_init(condvar_t *cv); + /** \brief Free a condition variable. This function frees a condition variable, releasing all memory associated @@ -100,6 +107,9 @@ this function has no timeout, and will sleep forever if the condition is not signalled. + The mutex will be locked and owned by the calling thread on return, + regardless of whether it is a successful or error return. + \param cv The condition to wait on \param m The associated mutex \retval 0 On success @@ -119,6 +129,9 @@ If a timeout of 0 is given, the call is equivalent to cond_wait() (there is no timeout). + The mutex will be locked and owned by the calling thread on return, + regardless of whether it is a successful or error return. + \param cv The condition to wait on \param m The associated mutex \param timeout The number of milliseconds before timeout @@ -152,12 +165,6 @@ */ void cond_broadcast(condvar_t *cv); -/* Init / shutdown */ -/** \cond */ -int cond_init(); -void cond_shutdown(); -/** \endcond */ - __END_DECLS #endif /* __KOS_COND_H */ Modified: kos/include/kos/genwait.h =================================================================== --- kos/include/kos/genwait.h 2012-06-09 04:17:01 UTC (rev 807) +++ kos/include/kos/genwait.h 2012-06-09 04:18:22 UTC (rev 808) @@ -1,7 +1,8 @@ /* KallistiOS ##version## include/kos/genwait.h - Copyright (c)2003 Dan Potter + Copyright (C) 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -15,6 +16,7 @@ it can be used for some fairly useful things. \author Dan Potter + \author Lawrence Sebald */ #ifndef __KOS_GENWAIT_H @@ -55,28 +57,55 @@ \param obj The object to wake threads that are sleeping on it \param cnt The number of threads to wake, if <= 0, wake all + \param err The errno code to set as the errno value on the + woken threads. If this is 0 (EOK), then the thread's + errno will not be changed, and the thread will get a + return value of 0 from the genwait_wait(). If it is + non-zero, the thread will get a return value of -1 + and errno will be set to this value for the woken + threads. \return The number of threads woken */ -int genwait_wake_cnt(void * obj, int cnt); +int genwait_wake_cnt(void * obj, int cnt, int err); /** \brief Wake up all threads sleeping on an object. - This function simply calls genwait_wake_cnt(obj, -1). + This function simply calls genwait_wake_cnt(obj, -1, 0). - \param obj The thread to wake threads that are sleeping on it + \param obj The object to wake threads that are sleeping on it \see genwait_wake_cnt() */ void genwait_wake_all(void * obj); /** \brief Wake up one thread sleeping on an object. - This function simply calls genwait_wake_cnt(obj, 1). + This function simply calls genwait_wake_cnt(obj, 1, 0). - \param obj The thread to wake threads that are sleeping on it + \param obj The object to wake threads that are sleeping on it \see genwait_wake_cnt() */ void genwait_wake_one(void * obj); +/** \brief Wake up all threads sleeping on an object, with an error. + + This function simply calls genwait_wake_cnt(obj, -1, err). + + \param obj The object to wake threads that are sleeping on it + \param err The value to set in the threads' errno values + \see genwait_wake_cnt() +*/ +void genwait_wake_all_err(void *obj, int err); + +/** \brief Wake up one thread sleeping on an object, with an error. + + This function simply calls genwait_wake_cnt(obj, 1, err). + + \param obj The object to wake threads that are sleeping on it + \param err The value to set in the threads' errno values + \see genwait_wake_cnt() +*/ +void genwait_wake_one_err(void *obj, int err); + /** \brief Look for timed out genwait_wait() calls. There should be no reason you need to call this function, it is called Modified: kos/include/pthread.h =================================================================== --- kos/include/pthread.h 2012-06-09 04:17:01 UTC (rev 807) +++ kos/include/pthread.h 2012-06-09 04:18:22 UTC (rev 808) @@ -120,7 +120,7 @@ pthread_cond_t cond = PTHREAD_COND_INITIALIZER; */ -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) 0xFFFFFFFF) +#define PTHREAD_COND_INITIALIZER COND_INITIALIZER /* Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101 */ Modified: kos/include/sys/sched.h =================================================================== --- kos/include/sys/sched.h 2012-06-09 04:17:01 UTC (rev 807) +++ kos/include/sys/sched.h 2012-06-09 04:18:22 UTC (rev 808) @@ -67,7 +67,7 @@ // because we allow _INIT #defines to work. typedef kthread_t * pthread_t; /**< \brief POSIX thread type */ typedef mutex_t pthread_mutex_t; /**< \brief POSIX mutex type */ -typedef condvar_t * pthread_cond_t; /**< \brief POSIX condition type */ +typedef condvar_t pthread_cond_t; /**< \brief POSIX condition type */ // These, on the other hand, map right over. typedef kthread_once_t pthread_once_t; /**< \brief POSIX once control */ Modified: kos/kernel/fs/fs_pty.c =================================================================== --- kos/kernel/fs/fs_pty.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/fs/fs_pty.c 2012-06-09 04:18:22 UTC (rev 808) @@ -60,7 +60,7 @@ int id; mutex_t mutex; - condvar_t * ready_read, * ready_write; + condvar_t ready_read, ready_write; } ptyhalf_t; /* Our global pty list */ @@ -149,11 +149,11 @@ /* Allocate a mutex for each for multiple readers or writers */ mutex_init(&master->mutex, MUTEX_TYPE_NORMAL); - master->ready_read = cond_create(); - master->ready_write = cond_create(); + cond_init(&master->ready_read); + cond_init(&master->ready_write); mutex_init(&slave->mutex, MUTEX_TYPE_NORMAL); - slave->ready_read = cond_create(); - slave->ready_write = cond_create(); + cond_init(&slave->ready_read); + cond_init(&slave->ready_write); /* Add it to the list */ mutex_lock(&list_mutex); @@ -209,16 +209,16 @@ goto next; /* Free all our structs */ - cond_destroy(c->ready_read); - cond_destroy(c->ready_write); + cond_destroy(&c->ready_read); + cond_destroy(&c->ready_write); mutex_destroy(&c->mutex); /* Remove us from the list */ LIST_REMOVE(c, list); /* Now to deal with our partner... */ - cond_destroy(c->other->ready_read); - cond_destroy(c->other->ready_write); + cond_destroy(&c->other->ready_read); + cond_destroy(&c->other->ready_write); mutex_destroy(&c->other->mutex); /* Remove it from the list */ @@ -399,8 +399,8 @@ if(fdobj->d.p->refcnt <= 0) { /* Unblock anyone who might be waiting on the other end */ - cond_broadcast(fdobj->d.p->other->ready_read); - cond_broadcast(fdobj->d.p->ready_write); + cond_broadcast(&fdobj->d.p->other->ready_read); + cond_broadcast(&fdobj->d.p->ready_write); } mutex_unlock(&fdobj->d.p->mutex); @@ -490,7 +490,7 @@ goto done; } - cond_wait(ph->ready_read, &ph->mutex); + cond_wait(&ph->ready_read, &ph->mutex); } /* Figure out how much to read */ @@ -513,7 +513,7 @@ assert(ph->cnt >= 0); /* Wake anyone waiting for write space */ - cond_broadcast(ph->ready_write); + cond_broadcast(&ph->ready_write); done: mutex_unlock(&ph->mutex); @@ -557,7 +557,7 @@ goto done; } - cond_wait(ph->ready_write, &ph->mutex); + cond_wait(&ph->ready_write, &ph->mutex); } /* Figure out how much to write */ @@ -580,7 +580,7 @@ assert(ph->cnt <= PTY_BUFFER_SIZE); /* Wake anyone waiting on read */ - cond_broadcast(ph->ready_read); + cond_broadcast(&ph->ready_read); done: mutex_unlock(&ph->mutex); @@ -749,8 +749,8 @@ while(c != NULL) { n = LIST_NEXT(c, list); - cond_destroy(c->ready_read); - cond_destroy(c->ready_write); + cond_destroy(&c->ready_read); + cond_destroy(&c->ready_write); mutex_destroy(&c->mutex); free(c); Modified: kos/kernel/libc/pthreads/pthread_cond.c =================================================================== --- kos/kernel/libc/pthreads/pthread_cond.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/libc/pthreads/pthread_cond.c 2012-06-09 04:18:22 UTC (rev 808) @@ -26,80 +26,51 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { assert(cond); - *cond = cond_create(); - - if(*cond) - return 0; - else - return EAGAIN; + return cond_init(cond); } int pthread_cond_destroy(pthread_cond_t * cond) { assert(cond); - cond_destroy(*cond); + cond_destroy(cond); return 0; } -// XXX condvars made this way should probably be nuked at shutdown -#define CHK_AND_CREATE \ - if (*cond == PTHREAD_COND_INITIALIZER) { \ - int rv = pthread_cond_init(cond, NULL); \ - if (rv != 0) \ - return rv; \ - } - /* Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101 */ int pthread_cond_signal(pthread_cond_t *cond) { assert(cond); - CHK_AND_CREATE; - - cond_signal(*cond); + cond_signal(cond); return 0; } int pthread_cond_broadcast(pthread_cond_t *cond) { assert(cond); - CHK_AND_CREATE; - - cond_broadcast(*cond); + cond_broadcast(cond); return 0; } /* Waiting on a Condition, P1003.1c/Draft 10, p. 105 */ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - int rv; - assert(cond); assert(mutex); - CHK_AND_CREATE; - - rv = cond_wait(*cond, mutex); - - // XXX this probably isn't proper - if(rv) - return EINVAL; - else - return 0; + return cond_wait(cond, mutex); } int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - int rv, tmo; + int tmo; struct timeval ctv; assert(cond); assert(mutex); assert(abstime); - CHK_AND_CREATE; - // We have to calculate this... gettimeofday(&ctv, NULL); @@ -111,14 +82,5 @@ if(tmo == 0) return ETIMEDOUT; - rv = cond_wait_timed(*cond, mutex, tmo); - - if(rv >= 0) - return 0; - - // XXX this probably isn't proper - if(errno == EAGAIN) - return ETIMEDOUT; - else - return EINVAL; + return cond_wait_timed(cond, mutex, tmo); } Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/net/net_tcp.c 2012-06-09 04:18:22 UTC (rev 808) @@ -153,7 +153,7 @@ int tail; int count; struct lsock *queue; - condvar_t *cv; + condvar_t cv; } listen; struct { netif_t *net; @@ -169,8 +169,8 @@ uint32_t sndbuf_acked; uint32_t sndbuf_tail; uint64_t timer; - condvar_t *send_cv; - condvar_t *recv_cv; + condvar_t send_cv; + condvar_t recv_cv; } data; }; }; @@ -367,14 +367,14 @@ } free(sock->listen.queue); - cond_destroy(sock->listen.cv); + cond_destroy(&sock->listen.cv); goto ret_remove; case TCP_STATE_SYN_SENT: free(sock->data.rcvbuf); free(sock->data.sndbuf); - cond_destroy(sock->data.send_cv); - cond_destroy(sock->data.recv_cv); + cond_destroy(&sock->data.send_cv); + cond_destroy(&sock->data.recv_cv); goto ret_remove; case TCP_STATE_ESTABLISHED: @@ -513,7 +513,7 @@ /* There are no waiting connections and we can block, so block while we wait for an incoming connection. */ sock->intflags |= TCP_IFLAG_ACCEPTWAIT; - cond_wait(sock->listen.cv, &sock->mutex); + cond_wait(&sock->listen.cv, &sock->mutex); /* If we come out of the wait in the closed state, that means that the user has run a close() on the socket in another thread. Bail out in a @@ -523,7 +523,7 @@ rwsem_write_lock(tcp_sem); mutex_lock(&sock->mutex); free(sock->listen.queue); - cond_destroy(sock->listen.cv); + cond_destroy(&sock->listen.cv); LIST_REMOVE(sock, sock_list); mutex_unlock(&sock->mutex); mutex_destroy(&sock->mutex); @@ -577,7 +577,7 @@ return -1; } - if(!(sock2->data.send_cv = cond_create())) { + if(cond_init(&sock2->data.send_cv)) { errno = ENOMEM; mutex_unlock(&sock->mutex); free(sock2->data.sndbuf); @@ -587,10 +587,10 @@ return -1; } - if(!(sock2->data.recv_cv = cond_create())) { + if(cond_init(&sock2->data.recv_cv)) { errno = ENOMEM; mutex_unlock(&sock->mutex); - cond_destroy(sock2->data.send_cv); + cond_destroy(&sock2->data.send_cv); free(sock2->data.sndbuf); free(sock2->data.rcvbuf); mutex_destroy(&sock2->mutex); @@ -601,8 +601,8 @@ /* Create a partial socket */ if(!(newhnd = fs_socket_open_sock(&proto))) { mutex_unlock(&sock->mutex); - cond_destroy(sock2->data.recv_cv); - cond_destroy(sock2->data.send_cv); + cond_destroy(&sock2->data.recv_cv); + cond_destroy(&sock2->data.send_cv); free(sock2->data.sndbuf); free(sock2->data.rcvbuf); mutex_destroy(&sock2->mutex); @@ -665,8 +665,8 @@ newhnd->protocol = NULL; fs_close(sock2->sock); - cond_destroy(sock2->data.recv_cv); - cond_destroy(sock2->data.send_cv); + cond_destroy(&sock2->data.recv_cv); + cond_destroy(&sock2->data.send_cv); free(sock2->data.sndbuf); free(sock2->data.rcvbuf); mutex_destroy(&sock2->mutex); @@ -1099,7 +1099,7 @@ return -1; } - if(!(sock->data.send_cv = cond_create())) { + if(cond_init(&sock->data.send_cv)) { errno = ENOBUFS; mutex_unlock(&sock->mutex); rwsem_write_unlock(tcp_sem); @@ -1108,11 +1108,11 @@ return -1; } - if(!(sock->data.recv_cv = cond_create())) { + if(cond_init(&sock->data.recv_cv)) { errno = ENOBUFS; mutex_unlock(&sock->mutex); rwsem_write_unlock(tcp_sem); - cond_destroy(sock->data.send_cv); + cond_destroy(&sock->data.send_cv); free(sock->data.sndbuf); free(sock->data.rcvbuf); return -1; @@ -1146,7 +1146,8 @@ } /* Block until the connection can be established... */ - if(cond_wait_timed(sock->data.send_cv, &sock->mutex, 2 * TCP_DEFAULT_MSL)) { + if(cond_wait_timed(&sock->data.send_cv, &sock->mutex, + 2 * TCP_DEFAULT_MSL)) { errno = ETIMEDOUT; sock->state = TCP_STATE_CLOSED; mutex_unlock(&sock->mutex); @@ -1228,7 +1229,7 @@ return -1; } - if(!(sock->listen.cv = cond_create())) { + if(cond_init(&sock->listen.cv)) { free(sock->listen.queue); sock->listen.queue = NULL; mutex_unlock(&sock->mutex); @@ -1324,7 +1325,7 @@ goto out; } - cond_wait(sock->data.recv_cv, &sock->mutex); + cond_wait(&sock->data.recv_cv, &sock->mutex); } /* Once we get here, we should have data, unless the other side has closed @@ -1499,7 +1500,7 @@ goto out; } - cond_wait(sock->data.send_cv, &sock->mutex); + cond_wait(&sock->data.send_cv, &sock->mutex); /* If we still don't have any buffer space, its because the connection has either been closed or reset by the other side... */ @@ -2378,7 +2379,7 @@ /* Signal the condvar, in case anyone's waiting */ __poll_event_trigger(s->sock, POLLRDNORM); - cond_signal(s->listen.cv); + cond_signal(&s->listen.cv); /* We're done, return success. */ return 0; @@ -2412,8 +2413,8 @@ if(gotack) { s->state = TCP_STATE_CLOSED | TCP_STATE_RESET; __poll_event_trigger(s->sock, POLLHUP); - cond_signal(s->data.recv_cv); - cond_signal(s->data.send_cv); + cond_signal(&s->data.recv_cv); + cond_signal(&s->data.send_cv); return 0; } } @@ -2469,14 +2470,14 @@ s->state = TCP_STATE_ESTABLISHED; tcp_send_ack(s); __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); - cond_signal(s->data.send_cv); + cond_signal(&s->data.send_cv); } } else { s->state = TCP_STATE_SYN_RECEIVED; tcp_send_syn(s, 1); __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); - cond_signal(s->data.send_cv); + cond_signal(&s->data.send_cv); } } @@ -2546,8 +2547,8 @@ else { s->state = TCP_STATE_RESET | TCP_STATE_CLOSED; __poll_event_trigger(s->sock, POLLHUP); - cond_signal(s->data.recv_cv); - cond_signal(s->data.send_cv); + cond_signal(&s->data.recv_cv); + cond_signal(&s->data.send_cv); return 0; } } @@ -2585,7 +2586,7 @@ s->data.sndbuf_cur_sz -= (int32_t)(ack - s->data.snd.una - acksyn); s->data.snd.una = ack; __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); - cond_signal(s->data.send_cv); + cond_signal(&s->data.send_cv); if(s->data.sndbuf_acked >= s->sndbuf_sz) s->data.sndbuf_acked -= s->sndbuf_sz; @@ -2685,7 +2686,7 @@ /* Signal any waiting thread and send an ack for what we read */ __poll_event_trigger(s->sock, POLLRDNORM); - cond_signal(s->data.recv_cv); + cond_signal(&s->data.recv_cv); tcp_send_ack(s); } } @@ -2702,7 +2703,7 @@ ++s->data.rcv.nxt; tcp_send_ack(s); __poll_event_trigger(s->sock, POLLRDNORM); - cond_signal(s->data.recv_cv); + cond_signal(&s->data.recv_cv); /* Do the various processing that needs to be done based on our state */ switch(s->state) { @@ -2928,8 +2929,8 @@ if((i->intflags & TCP_IFLAG_CANBEDEL) && (i->state & 0x0F) == TCP_STATE_CLOSED) { LIST_REMOVE(i, sock_list); - cond_destroy(i->data.send_cv); - cond_destroy(i->data.recv_cv); + cond_destroy(&i->data.send_cv); + cond_destroy(&i->data.recv_cv); mutex_destroy(&i->mutex); free(i->data.sndbuf); free(i->data.rcvbuf); @@ -2998,8 +2999,8 @@ } else { LIST_REMOVE(i, sock_list); - cond_destroy(i->data.send_cv); - cond_destroy(i->data.recv_cv); + cond_destroy(&i->data.send_cv); + cond_destroy(&i->data.recv_cv); mutex_destroy(&i->mutex); free(i->data.sndbuf); free(i->data.rcvbuf); Modified: kos/kernel/thread/cond.c =================================================================== --- kos/kernel/thread/cond.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/thread/cond.c 2012-06-09 04:18:22 UTC (rev 808) @@ -1,14 +1,14 @@ /* KallistiOS ##version## cond.c - Copyright (c)2001,2003 Dan Potter + Copyright (C) 2001, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ /* Defines condition variables, which are like semaphores that automatically signal all waiting processes when a signal() is called. */ -#include <string.h> -#include <malloc.h> +#include <stdlib.h> #include <stdio.h> #include <assert.h> #include <errno.h> @@ -17,50 +17,45 @@ #include <kos/limits.h> #include <kos/cond.h> #include <kos/genwait.h> -#include <sys/queue.h> +#include <kos/dbglog.h> + /**************************************/ -/* Global list of condvars */ -static struct condlist cond_list; - -/* Allocate a new condvar; the condvar will be assigned - to the calling process and when that process dies, the condvar - will also die. */ +/* Allocate a new condvar */ condvar_t *cond_create() { - condvar_t *cv; - int old = 0; + condvar_t *cv; - /* Create a condvar structure */ - cv = (condvar_t*)malloc(sizeof(condvar_t)); + dbglog(DBG_WARNING, "Creating condvar with deprecated cond_create(). " + "Please update your code!\n"); - if(!cv) { + /* Create a condvar structure */ + if(!(cv = (condvar_t *)malloc(sizeof(condvar_t)))) { errno = ENOMEM; return NULL; } - /* Add to the global list */ - old = irq_disable(); - LIST_INSERT_HEAD(&cond_list, cv, g_list); - irq_restore(old); + cv->initted = 1; + cv->dynamic = 1; return cv; } +int cond_init(condvar_t *cv) { + cv->initted = 1; + return 0; +} + /* Free a condvar */ void cond_destroy(condvar_t *cv) { - int old = 0; + /* Give all sleeping threads a timed out error */ + genwait_wake_all_err(cv, ETIMEDOUT); - /* XXX Do something better with queued threads */ - genwait_wake_all(cv); + cv->initted = 0; - /* Remove it from the global list */ - old = irq_disable(); - LIST_REMOVE(cv, g_list); - irq_restore(old); - /* Free the memory */ - free(cv); + if(cv->dynamic) + free(cv); } int cond_wait_timed(condvar_t *cv, mutex_t *m, int timeout) { @@ -79,12 +74,11 @@ mutex_unlock(m); /* Now block us until we're signaled */ - rv = genwait_wait(cv, timeout ? "cond_wait_timed" : "cond_wait", timeout, NULL); + rv = genwait_wait(cv, timeout ? "cond_wait_timed" : "cond_wait", timeout, + NULL); /* Re-lock our mutex */ - if(rv >= 0 || errno == EAGAIN) { - mutex_lock(m); - } + mutex_lock(m); /* Ok, ready to return */ irq_restore(old); @@ -117,14 +111,3 @@ irq_restore(old); } - -/* Initialize condvar structures */ -int cond_init() { - LIST_INIT(&cond_list); - return 0; -} - -/* Shut down condvar structures */ -void cond_shutdown() { - /* XXX Destroy all condvars here */ -} Modified: kos/kernel/thread/genwait.c =================================================================== --- kos/kernel/thread/genwait.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/thread/genwait.c 2012-06-09 04:18:22 UTC (rev 808) @@ -1,7 +1,8 @@ /* KallistiOS ##version## genwait.c - Copyright (c)2002,2003 Dan Potter + Copyright (C) 2002, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ /* This is a generic wait system, much like that used in the BSD kernel. @@ -128,7 +129,7 @@ } } -int genwait_wake_cnt(void * obj, int cntmax) { +int genwait_wake_cnt(void * obj, int cntmax, int err) { kthread_t * t, * nt; struct slpquehead * qp; int cnt, old; @@ -149,8 +150,14 @@ /* Yes, remove it from the wait queue */ genwait_unqueue(t); - /* Set a successful wake return value */ - CONTEXT_RET(t->context) = 0; + /* Set the wake return value */ + if(err) { + CONTEXT_RET(t->context) = -1; + t->thd_errno = err; + } + else { + CONTEXT_RET(t->context) = 0; + } /* Check to see if we've filled our quota */ if(cntmax > 0) { @@ -169,13 +176,21 @@ } void genwait_wake_all(void * obj) { - genwait_wake_cnt(obj, -1); + genwait_wake_cnt(obj, -1, 0); } void genwait_wake_one(void * obj) { - genwait_wake_cnt(obj, 1); + genwait_wake_cnt(obj, 1, 0); } +void genwait_wake_one_err(void *obj, int err) { + genwait_wake_cnt(obj, 1, err); +} + +void genwait_wake_all_err(void *obj, int err) { + genwait_wake_cnt(obj, -1, err); +} + void genwait_check_timeouts(uint64 tm) { kthread_t *t; Modified: kos/kernel/thread/rwsem.c =================================================================== --- kos/kernel/thread/rwsem.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/thread/rwsem.c 2012-06-09 04:18:22 UTC (rev 808) @@ -149,7 +149,7 @@ s->write_lock = 0; /* Give writers priority, attempt to wake any writers first. */ - woken = genwait_wake_cnt(&s->write_lock, 1); + woken = genwait_wake_cnt(&s->write_lock, 1, 0); if(!woken) { /* No writers were waiting, wake up any readers. */ Modified: kos/kernel/thread/sem.c =================================================================== --- kos/kernel/thread/sem.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/thread/sem.c 2012-06-09 04:18:22 UTC (rev 808) @@ -174,7 +174,7 @@ /* Is there anyone waiting? If so, pass off to them */ if(sm->count < 0) { - woken = genwait_wake_cnt(sm, 1); + woken = genwait_wake_cnt(sm, 1, 0); assert(woken == 1); sm->count++; } Modified: kos/kernel/thread/thread.c =================================================================== --- kos/kernel/thread/thread.c 2012-06-09 04:17:01 UTC (rev 807) +++ kos/kernel/thread/thread.c 2012-06-09 04:18:22 UTC (rev 808) @@ -871,7 +871,6 @@ genwait_init(); rwsem_init(); sem_init(); - cond_init(); /* Setup our pre-emption handler */ timer_primary_set_callback(thd_timer_hnd); @@ -911,7 +910,6 @@ /* Shutdown thread sync primitives */ rwsem_shutdown(); sem_shutdown(); - cond_shutdown(); genwait_shutdown(); kthread_tls_shutdown(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-09 04:17:07
|
Revision: 807 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=807&view=rev Author: ljsebald Date: 2012-06-09 04:17:01 +0000 (Sat, 09 Jun 2012) Log Message: ----------- A few documentation fixups... Modified Paths: -------------- kos/include/kos/fs_socket.h kos/include/kos/mutex.h kos/include/kos/thread.h kos/include/sys/socket.h Modified: kos/include/kos/fs_socket.h =================================================================== --- kos/include/kos/fs_socket.h 2012-06-08 20:33:34 UTC (rev 806) +++ kos/include/kos/fs_socket.h 2012-06-09 04:17:01 UTC (rev 807) @@ -311,7 +311,7 @@ /** \brief Manipulate file options. - This function should implement the ::fcntl() system call for the given + This function should implement the fcntl() system call for the given protocol. The semantics are exactly as defined for that function. \param s The socket to manipulate. Modified: kos/include/kos/mutex.h =================================================================== --- kos/include/kos/mutex.h 2012-06-08 20:33:34 UTC (rev 806) +++ kos/include/kos/mutex.h 2012-06-09 04:17:01 UTC (rev 807) @@ -68,17 +68,15 @@ \headerfile kos/mutex.h */ typedef struct kos_mutex { - /** \cond */ int type; int dynamic; kthread_t *holder; int count; - /** \endcond */ } mutex_t; /** \defgroup mutex_types Mutex types - The types defined in here are the various types of mutexes that KallistiOS + The values defined in here are the various types of mutexes that KallistiOS supports. @{ @@ -126,6 +124,8 @@ \par Error Conditions: \em EINVAL - an invalid type of mutex was specified + + \sa mutex_types */ int mutex_init(mutex_t *m, int mtype); @@ -215,7 +215,7 @@ \retval -1 If the mutex cannot be acquired without blocking \par Error Conditions: - \em EAGAIN - the mutex is already locked (mutex_lock() would block) + \em EAGAIN - the mutex is already locked (mutex_lock() would block) \n \em EINVAL - the mutex has not been initialized properly \n \em EAGAIN - lock has been acquired too many times (recursive) \n \em EDEADLK - would deadlock (error-checking) Modified: kos/include/kos/thread.h =================================================================== --- kos/include/kos/thread.h 2012-06-08 20:33:34 UTC (rev 806) +++ kos/include/kos/thread.h 2012-06-09 04:17:01 UTC (rev 807) @@ -85,7 +85,7 @@ data associated with the thread. There are various functions to manipulate the data in here, so you shouldn't generally do so manually. - \headerfile dc/thread.h + \headerfile kos/thread.h */ typedef struct kthread { /** \brief Thread list handle. Not a function. */ Modified: kos/include/sys/socket.h =================================================================== --- kos/include/sys/socket.h 2012-06-08 20:33:34 UTC (rev 806) +++ kos/include/sys/socket.h 2012-06-09 04:17:01 UTC (rev 807) @@ -316,7 +316,7 @@ shall attempt to retrieve the specified option (at the specified level) from the given socket. - \param sock The socket to get options for. + \param socket The socket to get options for. \param level The protocol level to get options at. \param option_name The option to look up. \param option_value Storage for the value of the option. @@ -337,7 +337,7 @@ attempt to set the specified option (at the specified level) from the given socket. - \param sock The socket to set options for. + \param socket The socket to set options for. \param level The protocol level to set options at. \param option_name The option to set. \param option_value The value to set for the option. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-08 20:33:41
|
Revision: 806 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=806&view=rev Author: ljsebald Date: 2012-06-08 20:33:34 +0000 (Fri, 08 Jun 2012) Log Message: ----------- Fixup kos-ports for the mutex update. Modified Paths: -------------- kos-ports/lwip/kos/sockets.c kos-ports/lwip/kos/sys_arch.c Modified: kos-ports/lwip/kos/sockets.c =================================================================== --- kos-ports/lwip/kos/sockets.c 2012-06-08 20:32:15 UTC (rev 805) +++ kos-ports/lwip/kos/sockets.c 2012-06-08 20:33:34 UTC (rev 806) @@ -24,7 +24,7 @@ struct udp_pcb * udppcb; // Used if SOCK_DGRAM // Sync variables - mutex_t * mutex; // For the condvars + mutex_t mutex; // For the condvars condvar_t * connect; // A connection was received on a listen() condvar_t * recv_avail; // Received data is available condvar_t * send_avail; // Send buffer space is available @@ -50,7 +50,7 @@ #define SOCKFD_CNT 32 static sockfd_t fds[SOCKFD_CNT] = { {0} }; -static mutex_t * fd_mutex; +static mutex_t fd_mutex = MUTEX_INITIALIZER; // We'll genwait on this for select static int select_wait = 0; @@ -62,7 +62,7 @@ static int sock_open() { int i; - mutex_lock(fd_mutex); + mutex_lock(&fd_mutex); for (i=0; i<SOCKFD_CNT; i++) if (!fds[i].inuse) break; @@ -75,10 +75,10 @@ fds[i].inuse = 1; } - mutex_unlock(fd_mutex); + mutex_unlock(&fd_mutex); // Setup some basic stuff - fds[i].mutex = mutex_create(); + mutex_init(&fds[i].mutex, MUTEX_TYPE_NORMAL); fds[i].connect = cond_create(); fds[i].recv_avail = cond_create(); fds[i].send_avail = cond_create(); @@ -102,7 +102,7 @@ cond_destroy(fds[fd].connect); cond_destroy(fds[fd].recv_avail); cond_destroy(fds[fd].send_avail); - mutex_destroy(fds[fd].mutex); + mutex_destroy(&fds[fd].mutex); fds[fd].inuse = 0; } @@ -159,7 +159,7 @@ fd = fds + s; // Get access. - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Make sure no more reads/writes go through. fd->recv = fd->send = -1; @@ -168,7 +168,7 @@ cond_broadcast(fd->recv_avail); cond_broadcast(fd->send_avail); - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); genwait_wake_all(&select_wait); } @@ -186,7 +186,7 @@ fd = fds + s; // Get access. - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Do we already have some data chained up in pbufs? if (fd->recv_buf) { @@ -205,7 +205,7 @@ // Note that we DON'T ACK the data until after a client has received // it using recv(). Otherwise the peer could send and send and send... - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); genwait_wake_all(&select_wait); @@ -233,7 +233,7 @@ fd = fds + s; // Get access. - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Add more buffer space available. fd->send += len; @@ -244,7 +244,7 @@ if (rdy) cond_signal(fd->send_avail); - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); if (rdy) genwait_wake_all(&select_wait); @@ -278,7 +278,7 @@ fd = fds + s; // Get access. - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Do we have enough space? if (fd->conncnt >= fd->connmax) { @@ -307,7 +307,7 @@ // need to get things into it. To make sure nothing weird happens // here, we'll lock first. nsd = fds + ns; - mutex_lock(nsd->mutex); + mutex_lock(&nsd->mutex); nsd->tcppcb = pcb; @@ -328,7 +328,7 @@ nsd->name.sin_port = htons(nsd->tcppcb->remote_port); nsd->name.sin_addr.s_addr = nsd->tcppcb->remote_ip.addr; - mutex_unlock(nsd->mutex); + mutex_unlock(&nsd->mutex); fd->conns[i] = ns; @@ -338,7 +338,7 @@ cond_signal(fd->connect); out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); if (rv == ERR_OK) genwait_wake_all(&select_wait); return rv; @@ -358,7 +358,7 @@ fd = fds + s; // Get access. - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Set the result error code fd->connerr = err; @@ -366,7 +366,7 @@ // Signal to proceed cond_signal(fd->connect); - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -416,7 +416,7 @@ // expects a socket #, not a VFS fd. static int close_common(int s) { // Make sure we have access - mutex_lock(fds[s].mutex); + mutex_lock(&fds[s].mutex); // Close off any lwIP hooks if (fds[s].tcppcb) { @@ -486,7 +486,7 @@ } // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Copy it over memcpy(&fd->name, name, namelen); @@ -535,7 +535,7 @@ // Wait for the result fd->connerr = 10; while (fd->connerr > 0) { - cond_wait(fd->connect, fd->mutex); + cond_wait(fd->connect, &fd->mutex); } // Convert error codes @@ -578,7 +578,7 @@ } out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -601,7 +601,7 @@ } // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Copy it over memcpy(&fd->name, name, namelen); @@ -639,7 +639,7 @@ } out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -656,7 +656,7 @@ fd = fds + s; // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Is it the right type? if (fd->type != SOCK_STREAM) { @@ -698,7 +698,7 @@ tcp_accept(fd->tcppcb, accept_tcp); out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -720,7 +720,7 @@ } // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Is it the right type? if (fd->type != SOCK_STREAM) { @@ -738,7 +738,7 @@ // Wait for a connection // printf("lwip_accept(%d): waiting\n", s); - cond_wait(fd->connect, fd->mutex); + cond_wait(fd->connect, &fd->mutex); } // Ok, we've got a connection. Find the first available one @@ -770,7 +770,7 @@ } out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -795,7 +795,7 @@ // printf("lwip_recv(%d): want %d bytes\n", s, len); // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Is there data available now? while (fd->recv <= 0) { @@ -806,7 +806,7 @@ // Wait for more data to be available //printf("cond_wait for more data\n"); - cond_wait(fd->recv_avail, fd->mutex); + cond_wait(fd->recv_avail, &fd->mutex); //printf("woken\n"); } @@ -859,7 +859,7 @@ //printf("returning\n"); out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -876,7 +876,7 @@ fd = fds + s; // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Is there space available now? while (fd->send <= 0) { @@ -886,7 +886,7 @@ rv = 0; goto out; } - cond_wait(fd->send_avail, fd->mutex); + cond_wait(fd->send_avail, &fd->mutex); } // Send as much as we can. @@ -918,7 +918,7 @@ fd->send -= size; out: - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -976,7 +976,7 @@ if (s < 0) continue; // Don't screw with things that are locked - if (mutex_is_locked(fds[s].mutex)) + if (mutex_is_locked(&fds[s].mutex)) continue; // If it's a listen socket, look for used connections. @@ -1000,7 +1000,7 @@ if (s < 0) continue; // Don't screw with things that are locked - if (mutex_is_locked(fds[s].mutex)) + if (mutex_is_locked(&fds[s].mutex)) continue; // Any buffer space available? Or socket dead? @@ -1135,7 +1135,7 @@ fd = fds + s; // Get access - mutex_lock(fd->mutex); + mutex_lock(&fd->mutex); // Make sure we're doing UDP here... we don't support sendto for TCP. if (fd->tcppcb) { @@ -1197,7 +1197,7 @@ out: if (pbuf) pbuf_free(pbuf); - mutex_unlock(fd->mutex); + mutex_unlock(&fd->mutex); return rv; } @@ -1236,6 +1236,5 @@ } int kti_init() { - fd_mutex = mutex_create(); return 0; } Modified: kos-ports/lwip/kos/sys_arch.c =================================================================== --- kos-ports/lwip/kos/sys_arch.c 2012-06-08 20:32:15 UTC (rev 805) +++ kos-ports/lwip/kos/sys_arch.c 2012-06-08 20:33:34 UTC (rev 806) @@ -34,7 +34,7 @@ /* Our thread list */ static TAILQ_HEAD(sys_thread_list, sys_thread) threads; -static mutex_t * threads_mutex; +static mutex_t threads_mutex = MUTEX_INITIALIZER; /* This thread will be used as a default when an unknown thread calls back into lwIP for something. */ @@ -45,7 +45,7 @@ struct sys_thread * st; kthread_t * pt; - mutex_lock(threads_mutex); + mutex_lock(&threads_mutex); pt = thd_get_current(); TAILQ_FOREACH(st, &threads, list) { @@ -55,7 +55,7 @@ if (!st) st = &thread_default; - mutex_unlock(threads_mutex); + mutex_unlock(&threads_mutex); return st; } @@ -66,9 +66,9 @@ tp->function(tp->arg); - mutex_lock(threads_mutex); + mutex_lock(&threads_mutex); TAILQ_REMOVE(&threads, tp, list); - mutex_unlock(threads_mutex); + mutex_unlock(&threads_mutex); free(tp); return NULL; @@ -83,9 +83,9 @@ thread->timeouts.next = NULL; thread->thd = NULL; - mutex_lock(threads_mutex); + mutex_lock(&threads_mutex); TAILQ_INSERT_TAIL(&threads, thread, list); - mutex_unlock(threads_mutex); + mutex_unlock(&threads_mutex); thread->function = function; thread->arg = arg; @@ -103,7 +103,6 @@ /* Setup thread list */ TAILQ_INIT(&threads); - threads_mutex = mutex_create(); } void sys_thread_shutdown() { @@ -124,7 +123,7 @@ void *msgs[SYS_MBOX_SIZE]; // Access mutex - mutex_t * mutex; + mutex_t mutex; // Signaled whenever mail is available condvar_t * mail; @@ -140,7 +139,7 @@ mbox = calloc(1, sizeof(struct sys_mbox)); mbox->head = mbox->tail = mbox->cnt = 0; - mbox->mutex = mutex_create(); + mutex_init(&mbox->mutex, MUTEX_TYPE_NORMAL); mbox->mail = cond_create(); mbox->avail = cond_create(); @@ -159,25 +158,22 @@ #ifdef SYS_STATS lwip_stats.sys.mbox.used--; #endif /* SYS_STATS */ - mutex_lock(mbox->mutex); - - mutex_destroy(mbox->mutex); + mutex_destroy(&mbox->mutex); cond_destroy(mbox->mail); cond_destroy(mbox->avail); mbox->mail = mbox->avail = NULL; - mbox->mutex = NULL; /* DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox);*/ free(mbox); } } void sys_mbox_post(struct sys_mbox *mbox, void *msg) { - mutex_lock(mbox->mutex); + mutex_lock(&mbox->mutex); DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", mbox, msg)); while (mbox->cnt >= SYS_MBOX_SIZE) { - cond_wait(mbox->avail, mbox->mutex); + cond_wait(mbox->avail, &mbox->mutex); } mbox->msgs[mbox->tail] = msg; @@ -185,24 +181,24 @@ mbox->tail = (mbox->tail + 1) % SYS_MBOX_SIZE; cond_signal(mbox->mail); - mutex_unlock(mbox->mutex); + mutex_unlock(&mbox->mutex); } // The timeout stuff is a little bit loose, but that's ok... u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) { u32_t time = 0; - mutex_lock(mbox->mutex); + mutex_lock(&mbox->mutex); while (!mbox->cnt) { if (timeout) { - int foo = cond_wait_timed(mbox->mail, mbox->mutex, timeout); + int foo = cond_wait_timed(mbox->mail, &mbox->mutex, timeout); if (foo < 0) { time = SYS_ARCH_TIMEOUT; break; } } else - cond_wait(mbox->mail, mbox->mutex); + cond_wait(mbox->mail, &mbox->mutex); } if (mbox->cnt) { @@ -216,7 +212,7 @@ cond_signal(mbox->avail); } - mutex_unlock(mbox->mutex); + mutex_unlock(&mbox->mutex); return time; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-08 20:32:24
|
Revision: 805 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=805&view=rev Author: ljsebald Date: 2012-06-08 20:32:15 +0000 (Fri, 08 Jun 2012) Log Message: ----------- Change around how mutexes work. Old code should continue to work just fine, but should be updated to not use mutex_create() anymore. Also, if you were using the recursive lock stuff, update it to use a mutex of type MUTEX_TYPE_RECURSIVE. Modified Paths: -------------- kos/examples/dreamcast/basic/threading/general/general_threading_test.c kos/examples/dreamcast/basic/threading/recursive_lock/rlock_test.c kos/include/kos/cond.h kos/include/kos/mutex.h kos/include/kos/recursive_lock.h kos/include/kos.h kos/include/pthread.h kos/include/sys/sched.h kos/kernel/arch/dreamcast/fs/fs_dclsocket.c kos/kernel/arch/dreamcast/fs/fs_iso9660.c kos/kernel/arch/dreamcast/fs/fs_vmu.c kos/kernel/arch/dreamcast/fs/vmufs.c kos/kernel/arch/dreamcast/hardware/cdrom.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_texture.c kos/kernel/exports/nmmgr.c kos/kernel/fs/fs_pty.c kos/kernel/fs/fs_ramdisk.c kos/kernel/fs/fs_romdisk.c kos/kernel/fs/fs_socket.c kos/kernel/libc/pthreads/pthread_cond.c kos/kernel/libc/pthreads/pthread_mutex.c kos/kernel/net/net_dhcp.c kos/kernel/net/net_ipv4_frag.c kos/kernel/net/net_multicast.c kos/kernel/net/net_tcp.c kos/kernel/net/net_udp.c kos/kernel/thread/cond.c kos/kernel/thread/mutex.c kos/kernel/thread/once.c kos/kernel/thread/recursive_lock.c kos/kernel/thread/thread.c Modified: kos/examples/dreamcast/basic/threading/general/general_threading_test.c =================================================================== --- kos/examples/dreamcast/basic/threading/general/general_threading_test.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/examples/dreamcast/basic/threading/general/general_threading_test.c 2012-06-08 20:32:15 UTC (rev 805) @@ -66,7 +66,7 @@ } /* Condvar/mutex used for timing below */ -mutex_t * mut; +mutex_t mut = MUTEX_INITIALIZER; condvar_t * cv; volatile int cv_ready = 0, cv_cnt = 0, cv_quit = 0; @@ -74,11 +74,11 @@ void *thd_3(void *v) { printf("Thread %d started\n", (int)v); - mutex_lock(mut); + mutex_lock(&mut); for(; ;) { while(!cv_ready && !cv_quit) { - cond_wait(cv, mut); + cond_wait(cv, &mut); } if(!cv_quit) { @@ -91,7 +91,7 @@ } - mutex_unlock(mut); + mutex_unlock(&mut); printf("Thread %d exiting\n", (int)v); return NULL; @@ -151,7 +151,6 @@ printf("\n\nCondvar test; starting threads\n"); printf("Main thread is %p\n", thd_current); - mut = mutex_create(); cv = cond_create(); for(i = 0; i < 10; i++) { @@ -164,40 +163,40 @@ printf("\nOne-by-one test:\n"); for(i = 0; i < 10; i++) { - mutex_lock(mut); + mutex_lock(&mut); cv_ready = 1; printf("Signaling %d:\n", i); cond_signal(cv); - mutex_unlock(mut); + mutex_unlock(&mut); thd_sleep(100); } printf("\nAgain, without waiting:\n"); for(i = 0; i < 10; i++) { - mutex_lock(mut); + mutex_lock(&mut); cv_ready = 1; printf("Signaling %d:\n", i); cond_signal(cv); - mutex_unlock(mut); + mutex_unlock(&mut); } thd_sleep(100); printf(" (might not be the full 10)\n"); printf("\nBroadcast test:\n"); - mutex_lock(mut); + mutex_lock(&mut); cv_ready = 1; cond_broadcast(cv); - mutex_unlock(mut); + mutex_unlock(&mut); thd_sleep(100); printf(" (only one should have gotten through)\n"); printf("\nKilling all condvar threads:\n"); - mutex_lock(mut); + mutex_lock(&mut); cv_quit = 1; cond_broadcast(cv); - mutex_unlock(mut); + mutex_unlock(&mut); for(i = 0; i < 10; i++) thd_join(t3[i], NULL); Modified: kos/examples/dreamcast/basic/threading/recursive_lock/rlock_test.c =================================================================== --- kos/examples/dreamcast/basic/threading/recursive_lock/rlock_test.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/examples/dreamcast/basic/threading/recursive_lock/rlock_test.c 2012-06-08 20:32:15 UTC (rev 805) @@ -5,14 +5,17 @@ */ -/* This program is a test for the recursive locks added in KOS 1.3.0. This +/* This program is a test for the recursive locks added in KOS 2.0.0. This synchronization primitive works essentially the same as a mutex, but allows - the thread that owns the lock to acquire it as many times as it wants. */ + the thread that owns the lock to acquire it as many times as it wants. + Note that during the development of KOS 2.0.0, the recursive lock type got + merged into the mutex type (when it was rewritten). */ + #include <stdio.h> #include <kos/thread.h> -#include <kos/recursive_lock.h> +#include <kos/mutex.h> #include <arch/arch.h> #include <dc/maple.h> @@ -20,7 +23,7 @@ #define UNUSED __attribute__((unused)) -recursive_lock_t *l = NULL; +mutex_t l = RECURSIVE_MUTEX_INITIALIZER; void *thd0(void *param UNUSED) { int i; @@ -28,45 +31,45 @@ printf("Thd 0: About to obtain lock 10 times\n"); for(i = 0; i < 10; ++i) { - rlock_lock(l); + mutex_lock(&l); } - printf("Thd 0: Lock acquired %d times\n", l->count); + printf("Thd 0: Lock acquired %d times\n", l.count); printf("Thd 0: About to sleep\n"); thd_sleep(100); printf("Thd 0: Awake, about to release lock 9 times\n"); for(i = 0; i < 9; ++i) { - rlock_unlock(l); + mutex_unlock(&l); } printf("Thd 0: About to sleep again\n"); thd_sleep(10); printf("Thd 0: Awake, about to release lock\n"); - rlock_unlock(l); + mutex_unlock(&l); printf("Thd 0: done\n"); return NULL; } void *thd1(void *param UNUSED) { printf("Thd 1: About to obtain lock 2 times\n"); - rlock_lock(l); - rlock_lock(l); + mutex_lock(&l); + mutex_lock(&l); printf("Thd 1: About to pass timeslice\n"); thd_pass(); printf("Thd 1: Awake, going to release lock 2 times\n"); - rlock_unlock(l); - rlock_unlock(l); + mutex_unlock(&l); + mutex_unlock(&l); printf("Thd 1: About to obtain lock 1 time\n"); - rlock_lock(l); + mutex_lock(&l); printf("Thd 1: About to release lock\n"); - rlock_unlock(l); + mutex_unlock(&l); printf("Thd 1: done\n"); return NULL; } @@ -77,13 +80,13 @@ printf("Thd 2: About to obtain lock 200 times\n"); for(i = 0; i < 200; ++i) { - rlock_lock(l); + mutex_lock(&l); } printf("Thd 2: About to release lock 200 times\n"); for(i = 0; i < 200; ++i) { - rlock_unlock(l); + mutex_unlock(&l); } printf("Thd 2: done\n"); @@ -101,14 +104,6 @@ printf("KallistiOS Recursive Lock test program\n"); - /* Create the recursive lock */ - l = rlock_create(); - - if(!l) { - printf("Could not create recursive lock, bailing out!\n"); - arch_exit(); - } - printf("About to create threads\n"); t0 = thd_create(0, thd0, NULL); t1 = thd_create(0, thd1, NULL); @@ -119,12 +114,12 @@ thd_join(t1, NULL); thd_join(t2, NULL); - if(rlock_is_locked(l)) { + if(mutex_is_locked(&l)) { printf("Lock is still locked!\n"); arch_exit(); } - rlock_destroy(l); + mutex_destroy(&l); printf("Recursive lock tests completed successfully!\n"); return 0; Modified: kos/include/kos/cond.h =================================================================== --- kos/include/kos/cond.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/kos/cond.h 2012-06-08 20:32:15 UTC (rev 805) @@ -33,6 +33,11 @@ Condition variables can be quite useful when used properly, and provide a fairly easy way to wait for work to be ready to be done. + Condition variables should never be used with mutexes that are of the type + MUTEX_TYPE_RECURSIVE. The lock will only be released once by the wait + function, and thus you will end up deadlocking if you use a recursive mutex + that has been locked more than once. + \author Dan Potter */ @@ -46,7 +51,6 @@ #include <sys/queue.h> #include <kos/thread.h> #include <kos/mutex.h> -#include <kos/recursive_lock.h> /** \brief Condition variable. @@ -107,27 +111,6 @@ */ int cond_wait(condvar_t *cv, mutex_t * m); -/** \brief Wait on a condition variable, using a recursive_lock_t. - - This function acts exactly like the cond_wait() function, except instead of - a mutex_t as its lock, it uses a recursive_lock_t. Generally, this should - not be preferred, as deadlock may occur if the calling thread has locked - the lock more than once (since this function only unlocks it once). This was - added specifically because it was required for GCC's C++0x threading code. - - \param cv The condition to wait on - \param l The associated lock - \retval 0 On success - \retval -1 On error, sets errno as appropriate - - \par Error Conditions: - \em EPERM - Called inside an interrupt \n - \em EINTR - Was interrupted - - \author Lawrence Sebald -*/ -int cond_wait_recursive(condvar_t *cv, recursive_lock_t *l); - /** \brief Wait on a condition variable with a timeout. This function will wait on the condition variable, unlocking the mutex and @@ -149,30 +132,6 @@ */ int cond_wait_timed(condvar_t *cv, mutex_t * m, int timeout); -/** \brief Wait on a condition variable with a timeout, using a recursive lock. - - This function will wait on the condition variable, unlocking the lock and - putting the calling thread to sleep as one atomic operation. If the timeout - elapses before the condition is signalled, this function will return error. - If a timeout of 0 is given, the call is equivalent to cond_wait() (there is - no timeout). The rant about cond_wait_recursive() being evil applies here - as well. - - \param cv The condition to wait on - \param l The associated recursive lock. - \param timeout The number of milliseconds before timeout - \retval 0 On success - \retval -1 On error, sets errno as appropriate - - \par Error Conditions: - \em EPERM - Called inside an interrupt \n - \em EINTR - Was interrupted \n - \em EAGAIN - timed out - - \author Lawrence Sebald -*/ -int cond_wait_timed_recursive(condvar_t *cv, recursive_lock_t *l, int timeout); - /** \brief Signal a single thread waiting on the condition variable. This function will wake up a single thread that is waiting on the condition. Modified: kos/include/kos/mutex.h =================================================================== --- kos/include/kos/mutex.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/kos/mutex.h 2012-06-08 20:32:15 UTC (rev 805) @@ -1,10 +1,14 @@ /* KallistiOS ##version## include/kos/mutex.h - Copyright (C)2001,2003 Dan Potter + Copyright (C) 2001, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ +/* Other than the old function names, there's basically nothing left of the old + version of mutexes... */ + /** \file kos/mutex.h \brief Mutual exclusion locks. @@ -15,10 +19,35 @@ a block of code to prevent two threads from interfereing with one another when only one would be appropriate to be in the block at a time. - KallistiOS simply implements its mutexes as a wrapper around semaphores with - an initial count of 1. + KallistiOS implments 3 types of mutexes, to bring it roughly in-line with + POSIX. The types of mutexes that can be made are normal, error-checking, and + recursive. Each has its own strengths and weaknesses, which are briefly + discussed below. - \author Dan Potter + A normal mutex (MUTEX_TYPE_NORMAL) is the fastest and simplest mutex of the + bunch. This is roughly equivalent to a semaphore that has been initialized + with a count of 1. There is no protection against threads unlocking normal + mutexes they didn't lock, nor is there any protection against deadlocks that + would arise from locking the mutex twice. + + An error-checking mutex (MUTEX_TYPE_ERRORCHECK) adds a small amount of error + checking on top of a normal mutex. This type will not allow you to lock the + mutex twice (it will return an error if the same thread tries to lock it two + times so it will not deadlock), and it will not allow a different thread to + unlock the mutex if it isn't the one holding the lock. + + A recursive mutex (MUTEX_TYPE_RECURSIVE) extends the error checking mutex + by allowing you to lock the mutex twice in the same thread, but you must + also unlock it twice (this works for any number of locks -- lock it n times, + you must unlock it n times). Still only one thread can hold the lock, but it + may hold it as many times as it needs to. This is equivalent to the + recursive_lock_t type that was available in KallistiOS for a while (before + it was basically merged back into a normal mutex). + + There is a fourth type of mutex defined (MUTEX_TYPE_DEFAULT), which maps to + the MUTEX_TYPE_NORMAL type. This is simply for alignment with POSIX. + + \author Lawrence Sebald \see kos/sem.h */ @@ -26,41 +55,96 @@ #define __KOS_MUTEX_H #include <sys/cdefs.h> + __BEGIN_DECLS -/* These are just wrappers around semaphores */ -#include <kos/sem.h> +#include <kos/thread.h> /** \brief Mutual exclusion lock type. - KOS mutexes are just wrappers around semaphores. + All members of this structure should be considered to be private. It is + unsafe to change anything in here yourself. \headerfile kos/mutex.h */ -typedef semaphore_t mutex_t; +typedef struct kos_mutex { + /** \cond */ + int type; + int dynamic; + kthread_t *holder; + int count; + /** \endcond */ +} mutex_t; +/** \defgroup mutex_types Mutex types + + The types defined in here are the various types of mutexes that KallistiOS + supports. + + @{ +*/ +#define MUTEX_TYPE_NORMAL 1 /**< \brief Normal mutex type */ +#define MUTEX_TYPE_ERRORCHECK 2 /**< \brief Error-checking mutex type */ +#define MUTEX_TYPE_RECURSIVE 3 /**< \brief Recursive mutex type */ + +/** \brief Default mutex type */ +#define MUTEX_TYPE_DEFAULT MUTEX_TYPE_NORMAL +/** @} */ + /** \brief Initializer for a transient mutex. */ -#define MUTEX_INITIALIZER SEM_INITIALIZER(1) +#define MUTEX_INITIALIZER { MUTEX_TYPE_NORMAL, 0, NULL, 0 } +/** \brief Initializer for a transient error-checking mutex. */ +#define ERRORCHECK_MUTEX_INITIALIZER { MUTEX_TYPE_ERRORCHECK, 0, NULL, 0 } + +/** \brief Initializer for a transient recursive mutex. */ +#define RECURSIVE_MUTEX_INITIALIZER { MUTEX_TYPE_RECURSIVE, 0, NULL, 0 } + /** \brief Allocate a new mutex. - This function allocates and initializes a new mutex for use. + This function allocates and initializes a new mutex for use. This function + will always create mutexes of the type MUTEX_TYPE_NORMAL. - \return The created mutex on success. NULL is returned on - failure and errno is set as appropriate. + \return The newly created mutex on success, or NULL on + failure (errno will be set as appropriate). + \note This function is formally deprecated. It should not + be used in any future code, and may be removed in + the future. You should instead use mutex_init(). +*/ +mutex_t *mutex_create() __attribute__((deprecated)); + +/** \brief Initialize a new mutex. + + This function initializes a new mutex for use. + + \param m The mutex to initialize + \param mtype The type of the mutex to initialize it to + + \retval 0 On success + \retval -1 On error, errno will be set as appropriate + \par Error Conditions: - \em ENOMEM - out of memory + \em EINVAL - an invalid type of mutex was specified */ -mutex_t * mutex_create(); +int mutex_init(mutex_t *m, int mtype); -/** \brief Free a mutex. +/** \brief Destroy a mutex. - This function frees a mutex, releasing all memory associated with it. It is - your responsibility to make sure that all threads waiting on the mutex are - taken care of before destroying the mutex. + This function destroys a mutex, releasing any memory that may have been + allocated internally for it. It is your responsibility to make sure that all + threads waiting on the mutex are taken care of before destroying the mutex. + + This function can be called on statically initialized, as well as + dynamically initialized ones. + + \retval 0 On success + \retval -1 On error, errno will be set as appropriate + + \par Error Conditions: + \em EBUSY - the mutex is currently locked */ -void mutex_destroy(mutex_t * m); +int mutex_destroy(mutex_t *m); /** \brief Lock a mutex. @@ -68,9 +152,7 @@ thread. If it is locked by another thread already, this function will block until the mutex has been acquired for the calling thread. - This does not protect against a thread obtaining the same mutex twice or any - other deadlock conditions. Also, this function is not safe to call inside an - interrupt. For mutex locks inside interrupts, use mutex_trylock(). + The semantics of this function depend on the type of mutex that is used. \param m The mutex to acquire \retval 0 On success @@ -78,9 +160,11 @@ \par Error Conditions: \em EPERM - called inside an interrupt \n - \em EINTR - was interrupted + \em EINVAL - the mutex has not been initialized properly \n + \em EAGAIN - lock has been acquired too many times (recursive) \n + \em EDEADLK - would deadlock (error-checking) */ -int mutex_lock(mutex_t * m); +int mutex_lock(mutex_t *m); /** \brief Lock a mutex (with a timeout). @@ -90,9 +174,6 @@ If the lock cannot be acquired in this timeframe, this function will return an error. - Much like mutex_lock(), this function does not protect against deadlocks - and is not safe to call in an interrupt. - \param m The mutex to acquire \param timeout The number of milliseconds to wait for the lock \retval 0 On success @@ -100,10 +181,13 @@ \par Error Conditions: \em EPERM - called inside an interrupt \n - \em EINTR - was interrupted \n - \em EAGAIN - timed out while blocking + \em EINVAL - the mutex has not been initialized properly \n + \em EINVAL - the timeout value was invalid (less than 0) \n + \em ETIMEDOUT - the timeout expired \n + \em EAGAIN - lock has been acquired too many times (recursive) \n + \em EDEADLK - would deadlock (error-checking) */ -int mutex_lock_timed(mutex_t * m, int timeout); +int mutex_lock_timed(mutex_t *m, int timeout); /** \brief Check if a mutex is locked. @@ -116,7 +200,7 @@ \retval 0 If the mutex is not currently locked \retval 1 If the mutex is currently locked */ -int mutex_is_locked(mutex_t * m); +int mutex_is_locked(mutex_t *m); /** \brief Attempt to lock a mutex. @@ -132,19 +216,26 @@ \par Error Conditions: \em EAGAIN - the mutex is already locked (mutex_lock() would block) + \em EINVAL - the mutex has not been initialized properly \n + \em EAGAIN - lock has been acquired too many times (recursive) \n + \em EDEADLK - would deadlock (error-checking) */ -int mutex_trylock(mutex_t * m); +int mutex_trylock(mutex_t *m); /** \brief Unlock a mutex. This function will unlock a mutex, allowing other threads to acquire it. - This function does not check if the thread that is calling it holds the - mutex. It is your responsibility to make sure you only unlock mutexes that - you have locked. + The semantics of this operation depend on the mutex type in use. \param m The mutex to unlock + \retval 0 On success + \retval -1 On error, errno will be set as appropriate. + + \par Error Conditions: + \em EPERM - the current thread does not own the mutex (error-checking or + recursive) */ -void mutex_unlock(mutex_t * m); +int mutex_unlock(mutex_t *m); __END_DECLS Modified: kos/include/kos/recursive_lock.h =================================================================== --- kos/include/kos/recursive_lock.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/kos/recursive_lock.h 2012-06-08 20:32:15 UTC (rev 805) @@ -1,7 +1,7 @@ /* KallistiOS ##version## include/kos/recursive_lock.h - Copyright (C) 2008, 2010 Lawrence Sebald + Copyright (C) 2008, 2010, 2012 Lawrence Sebald */ @@ -13,6 +13,10 @@ limited to holding the lock at a time, but it can hold it an "unlimited" number of times (actually limited to INT_MAX, but who's counting). + These are now just wrappers around the MUTEX_TYPE_RECURSIVE that is now + provided and will be removed at some point in the future. Please update your + code to use that type instead. + \author Lawrence Sebald */ @@ -23,24 +27,17 @@ __BEGIN_DECLS -#include <sys/queue.h> -#include <kos/thread.h> +#include <kos/mutex.h> /** \brief Recursive lock structure. - All members of this structure should be considered to be private, it is not - safe to change anything in here yourself. + Recursive locks are just a simple wrapper around mutexes at this point. You + should not use this type in any new code. \headerfile kos/recursive_lock.h */ -typedef struct recursive_lock { - /** \brief The thread that currently holds the lock, if any. */ - kthread_t *holder; +typedef mutex_t recursive_lock_t; - /** \brief The number of times the holding thread has locked this lock. */ - int count; -} recursive_lock_t; - /** \brief Allocate a new recursive lock. This function allocates a new recurisve lock that is initially not locked. @@ -48,7 +45,7 @@ \return The created lock, or NULL on failure (errno will be set to ENOMEM to indicate that the system appears to be out of memory). */ -recursive_lock_t *rlock_create(); +recursive_lock_t *rlock_create() __attribute__((deprecated)); /** \brief Destroy a recursive lock. @@ -57,7 +54,7 @@ \param l The recursive lock to destroy. It must be unlocked. */ -void rlock_destroy(recursive_lock_t *l); +void rlock_destroy(recursive_lock_t *l) __attribute__((deprecated)); /** \brief Lock a recursive lock. @@ -71,7 +68,7 @@ \sa rlock_trylock \sa rlock_lock_timed */ -int rlock_lock(recursive_lock_t *l); +int rlock_lock(recursive_lock_t *l) __attribute__((deprecated)); /** \brief Lock a recursive lock (with a timeout). @@ -89,7 +86,8 @@ \sa rlock_trylock \sa rlock_lock_timed */ -int rlock_lock_timed(recursive_lock_t *l, int timeout); +int rlock_lock_timed(recursive_lock_t *l, int timeout) + __attribute__((deprecated)); /** \brief Unlock a recursive lock. @@ -100,7 +98,7 @@ by the calling thread. \retval 0 On success. */ -int rlock_unlock(recursive_lock_t *l); +int rlock_unlock(recursive_lock_t *l) __attribute__((deprecated)); /** \brief Attempt to lock a recursive lock without blocking. @@ -115,7 +113,7 @@ \sa rlock_lock \sa rlock_lock_timed */ -int rlock_trylock(recursive_lock_t *l); +int rlock_trylock(recursive_lock_t *l) __attribute__((deprecated)); /** \brief Check if a recursive lock is currently held by any thread. @@ -127,14 +125,8 @@ \retval TRUE If the lock is held by any thread. \retval FALSE If the lock is not currently held by any thread. */ -int rlock_is_locked(recursive_lock_t *l); +int rlock_is_locked(recursive_lock_t *l) __attribute__((deprecated)); -/* Init / shutdown */ -/** \cond */ -int rlock_init(); -void rlock_shutdown(); -/** \endcond */ - __END_DECLS #endif /* !__KOS_RECURSIVE_LOCK_H */ Modified: kos/include/kos.h =================================================================== --- kos/include/kos.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/kos.h 2012-06-08 20:32:15 UTC (rev 805) @@ -40,7 +40,6 @@ #include <kos/thread.h> #include <kos/sem.h> #include <kos/rwsem.h> -#include <kos/recursive_lock.h> #include <kos/once.h> #include <kos/tls.h> #include <kos/mutex.h> Modified: kos/include/pthread.h =================================================================== --- kos/include/pthread.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/pthread.h 2012-06-08 20:32:15 UTC (rev 805) @@ -84,7 +84,7 @@ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF) +#define PTHREAD_MUTEX_INITIALIZER MUTEX_INITIALIZER /* Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ Modified: kos/include/sys/sched.h =================================================================== --- kos/include/sys/sched.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/include/sys/sched.h 2012-06-08 20:32:15 UTC (rev 805) @@ -66,7 +66,7 @@ // Map over KOS types. The mutex/condvar maps have to be pointers // because we allow _INIT #defines to work. typedef kthread_t * pthread_t; /**< \brief POSIX thread type */ -typedef mutex_t * pthread_mutex_t; /**< \brief POSIX mutex type */ +typedef mutex_t pthread_mutex_t; /**< \brief POSIX mutex type */ typedef condvar_t * pthread_cond_t; /**< \brief POSIX condition type */ // These, on the other hand, map right over. Modified: kos/kernel/arch/dreamcast/fs/fs_dclsocket.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_dclsocket.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/fs/fs_dclsocket.c 2012-06-08 20:32:15 UTC (rev 805) @@ -70,7 +70,7 @@ static int initted = 0; static int escape = 0; static int retval = 0; -static mutex_t *mutex; +static mutex_t mutex; static char *dcload_path = NULL; static uint8 pktbuf[1024 + sizeof(command_t)]; @@ -210,14 +210,14 @@ int dcload_mode = 0; command_t *cmd = (command_t *)pktbuf; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return 0; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } if(mode & O_DIR) { @@ -276,7 +276,7 @@ hnd = retval + 1; } - mutex_unlock(mutex); + mutex_unlock(&mutex); return (void *)hnd; } @@ -285,14 +285,14 @@ int fd = (int) hnd, locked; command_int_t *cmd = (command_int_t *)pktbuf; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } if(fd > 100) { @@ -312,7 +312,7 @@ dcls_recv_loop(); } - mutex_unlock(mutex); + mutex_unlock(&mutex); } static ssize_t dcls_read(void *hnd, void *buf, size_t cnt) { @@ -323,14 +323,14 @@ if(!fd) return -1; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } --fd; @@ -343,7 +343,7 @@ send(dcls_socket, cmd, sizeof(command_3int_t), 0); dcls_recv_loop(); - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -356,14 +356,14 @@ if(!fd) return -1; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } --fd; @@ -376,7 +376,7 @@ send(dcls_socket, cmd, sizeof(command_3int_t), 0); dcls_recv_loop(); - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -388,14 +388,14 @@ if(!hnd) return -1; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } --hnd; @@ -408,7 +408,7 @@ send(dcls_socket, command, sizeof(command_3int_t), 0); dcls_recv_loop(); - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -438,14 +438,14 @@ if(fd < 100) return NULL; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return NULL; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } memcpy(cmd->id, "DC18", 4); @@ -490,25 +490,25 @@ their_dir.time = filestat.st_mtime; } - mutex_unlock(mutex); + mutex_unlock(&mutex); return &their_dir; } - mutex_unlock(mutex); + mutex_unlock(&mutex); return NULL; } static int dcls_rename(vfs_handler_t *vfs, const char *fn1, const char *fn2) { int len1 = strlen(fn1), len2 = strlen(fn2), locked; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } memcpy(pktbuf, "DC07", 4); @@ -528,7 +528,7 @@ dcls_recv_loop(); } - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -536,14 +536,14 @@ static int dcls_unlink(vfs_handler_t *vfs, const char *fn) { int len = strlen(fn) + 5, locked; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } memcpy(pktbuf, "DC08", 4); @@ -553,7 +553,7 @@ dcls_recv_loop(); - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -567,14 +567,14 @@ return -1; } - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } memcpy(cmd->id, "DC13", 4); @@ -601,11 +601,11 @@ rv->time = filestat.st_mtime; - mutex_unlock(mutex); + mutex_unlock(&mutex); return 0; } - mutex_unlock(mutex); + mutex_unlock(&mutex); return -1; } @@ -629,14 +629,14 @@ if(initted < 2) return -1; - locked = mutex_trylock(mutex); + locked = mutex_trylock(&mutex); if(locked == -1 && irq_inside_int()) { errno = EAGAIN; return -1; } else if(locked == -1) { - mutex_lock(mutex); + mutex_lock(&mutex); } memcpy(cmd.id, "DD02", 4); @@ -648,7 +648,7 @@ dcls_recv_loop(); - mutex_unlock(mutex); + mutex_unlock(&mutex); return retval; } @@ -793,9 +793,7 @@ if(err == -1) goto error; - mutex = mutex_create(); - - if(!mutex) + if(mutex_init(&mutex, MUTEX_TYPE_NORMAL)) goto error; initted = 2; @@ -831,7 +829,7 @@ old = irq_disable(); /* Destroy our mutex, and set us as uninitted */ - mutex_destroy(mutex); + mutex_destroy(&mutex); initted = 0; irq_enable(old); Modified: kos/kernel/arch/dreamcast/fs/fs_iso9660.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_iso9660.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/fs/fs_iso9660.c 2012-06-08 20:32:15 UTC (rev 805) @@ -205,18 +205,18 @@ static cache_block_t *dcache[NUM_CACHE_BLOCKS]; /* data cache */ /* Cache modification mutex */ -static mutex_t * cache_mutex; +static mutex_t cache_mutex; /* Clears all cache blocks */ static void bclear_cache(cache_block_t **cache) { int i; - mutex_lock(cache_mutex); + mutex_lock(&cache_mutex); for(i = 0; i < NUM_CACHE_BLOCKS; i++) cache[i]->sector = -1; - mutex_unlock(cache_mutex); + mutex_unlock(&cache_mutex); } /* Graduate a block from its current position to the MRU end of the cache */ @@ -244,7 +244,7 @@ int i, j, rv; rv = -1; - mutex_lock(cache_mutex); + mutex_lock(&cache_mutex); /* Look for a pre-existing cache block */ for(i = NUM_CACHE_BLOCKS - 1; i >= 0; i--) { @@ -287,7 +287,7 @@ /* Return the new cache block index */ bread_exit: - mutex_unlock(cache_mutex); + mutex_unlock(&cache_mutex); return rv; } @@ -576,7 +576,7 @@ } fh[MAX_ISO_FILES]; /* Mutex for file handles */ -static mutex_t * fh_mutex; +static mutex_t fh_mutex; /* Break all of our open file descriptor. This is necessary when the disc is changed so that we don't accidentally try to keep on doing stuff @@ -585,12 +585,12 @@ static void iso_break_all() { int i; - mutex_lock(fh_mutex); + mutex_lock(&fh_mutex); for(i = 0; i < MAX_ISO_FILES; i++) fh[i].broken = 1; - mutex_unlock(fh_mutex); + mutex_unlock(&fh_mutex); } /* Open a file or directory */ @@ -614,7 +614,7 @@ if(!de) return 0; /* Find a free file handle */ - mutex_lock(fh_mutex); + mutex_lock(&fh_mutex); for(fd = 0; fd < MAX_ISO_FILES; fd++) if(fh[fd].first_extent == 0) { @@ -622,7 +622,7 @@ break; } - mutex_unlock(fh_mutex); + mutex_unlock(&fh_mutex); if(fd >= MAX_ISO_FILES) return 0; @@ -986,8 +986,8 @@ fh[0].first_extent = -1; /* Init thread mutexes */ - cache_mutex = mutex_create(); - fh_mutex = mutex_create(); + mutex_init(&cache_mutex, MUTEX_TYPE_NORMAL); + mutex_init(&fh_mutex, MUTEX_TYPE_NORMAL); /* Allocate cache block space */ for(i = 0; i < NUM_CACHE_BLOCKS; i++) { @@ -1021,13 +1021,8 @@ } /* Free muteces */ - if(cache_mutex != NULL) - mutex_destroy(cache_mutex); + mutex_destroy(&cache_mutex); + mutex_destroy(&fh_mutex); - if(fh_mutex != NULL) - mutex_destroy(fh_mutex); - - cache_mutex = fh_mutex = NULL; - return nmmgr_handler_remove(&vh.nmmgr); } Modified: kos/kernel/arch/dreamcast/fs/fs_vmu.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_vmu.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/fs/fs_vmu.c 2012-06-08 20:32:15 UTC (rev 805) @@ -79,7 +79,7 @@ TAILQ_HEAD(vmu_fh_list, vmu_fh_str) vmu_fh; /* Thread mutex for vmu_fh access */ -static mutex_t * fh_mutex; +static mutex_t fh_mutex; /* Take a VMUFS path and return the requested address */ @@ -264,9 +264,9 @@ if(fh == NULL) return 0; /* link the fh onto the top of the list */ - mutex_lock(fh_mutex); + mutex_lock(&fh_mutex); TAILQ_INSERT_TAIL(&vmu_fh, fh, listent); - mutex_unlock(fh_mutex); + mutex_unlock(&fh_mutex); return (void *)fh; } @@ -278,14 +278,14 @@ rv = 0; - mutex_lock(fh_mutex); + mutex_lock(&fh_mutex); TAILQ_FOREACH(cur, &vmu_fh, listent) { if((void *)cur == hnd) { rv = 1; break; } } - mutex_unlock(fh_mutex); + mutex_unlock(&fh_mutex); if(rv) return type == VMU_ANY ? 1 : (cur->strtype == type); @@ -334,9 +334,9 @@ } /* Look for the one to get rid of */ - mutex_lock(fh_mutex); + mutex_lock(&fh_mutex); TAILQ_REMOVE(&vmu_fh, fh, listent); - mutex_unlock(fh_mutex); + mutex_unlock(&fh_mutex); free(fh); } @@ -644,7 +644,7 @@ int fs_vmu_init() { TAILQ_INIT(&vmu_fh); - fh_mutex = mutex_create(); + mutex_init(&fh_mutex, MUTEX_TYPE_NORMAL); return nmmgr_handler_add(&vh.nmmgr); } @@ -678,11 +678,7 @@ c = n; } - if(fh_mutex != NULL) - mutex_destroy(fh_mutex); + mutex_destroy(&fh_mutex); - fh_mutex = NULL; - return nmmgr_handler_remove(&vh.nmmgr); } - Modified: kos/kernel/arch/dreamcast/fs/vmufs.c =================================================================== --- kos/kernel/arch/dreamcast/fs/vmufs.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/fs/vmufs.c 2012-06-08 20:32:15 UTC (rev 805) @@ -44,7 +44,7 @@ /* We need some sort of access control here for threads. This is somewhat less than optimal (one mutex for all VMUs) but I doubt it'll really be much of an issue :) */ -static mutex_t * mutex; +static mutex_t mutex; /* Convert a decimal number to BCD; max of two digits */ static uint8 dec_to_bcd(int dec) { @@ -485,17 +485,13 @@ } int vmufs_mutex_lock() { - mutex_lock(mutex); - return 0; + return mutex_lock(&mutex); } int vmufs_mutex_unlock() { - mutex_unlock(mutex); - return 0; + return mutex_unlock(&mutex); } - - /* ****************** Higher level functions ******************** */ /* Internal function gets everything setup for you */ @@ -836,18 +832,11 @@ int vmufs_init() { - if(!mutex) - mutex = mutex_create(); - + mutex_init(&mutex, MUTEX_TYPE_NORMAL); return 0; } int vmufs_shutdown() { - if(mutex) { - mutex_destroy(mutex); - mutex = NULL; - } - + mutex_destroy(&mutex); return 0; } - Modified: kos/kernel/arch/dreamcast/hardware/cdrom.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/cdrom.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/hardware/cdrom.c 2012-06-08 20:32:15 UTC (rev 805) @@ -86,7 +86,8 @@ #endif /* The CD access mutex */ -static mutex_t * mutex = NULL; +static mutex_t mutex; +static int initted = 0; static int sector_size = 2048; /*default 2048, 2352 for raw data reading*/ void cdrom_set_sector_size(int size) { @@ -138,11 +139,11 @@ flushing, so make sure we're not interrupting something already in progress. */ if(irq_inside_int()) { - if(mutex_is_locked(mutex)) + if(mutex_is_locked(&mutex)) return -1; } else { - mutex_lock(mutex); + mutex_lock(&mutex); } rv = gdc_get_drv_stat(params); @@ -163,7 +164,7 @@ } if(!irq_inside_int()) - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -175,7 +176,7 @@ uint32 params[4]; int timeout; - mutex_lock(mutex); + mutex_lock(&mutex); /* Try a few times; it might be busy. If it's still busy after this loop then it's probably really dead. */ @@ -219,7 +220,7 @@ } exit: - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -231,13 +232,13 @@ } params; int rv; - mutex_lock(mutex); + mutex_lock(&mutex); params.session = session; params.buffer = toc_buffer; rv = cdrom_exec_cmd(CMD_GETTOC2, ¶ms); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -250,7 +251,7 @@ } params; int rv; - mutex_lock(mutex); + mutex_lock(&mutex); params.sec = sector; /* Starting sector */ params.num = cnt; /* Number of sectors */ @@ -258,7 +259,7 @@ params.dunno = 0; /* ? */ rv = cdrom_exec_cmd(CMD_PIOREAD, ¶ms); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -303,14 +304,14 @@ params.end = end; params.repeat = repeat; - mutex_lock(mutex); + mutex_lock(&mutex); if(mode == CDDA_TRACKS) rv = cdrom_exec_cmd(CMD_PLAY, ¶ms); else rv = cdrom_exec_cmd(CMD_PLAY2, ¶ms); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -319,9 +320,9 @@ int cdrom_cdda_pause() { int rv; - mutex_lock(mutex); + mutex_lock(&mutex); rv = cdrom_exec_cmd(CMD_PAUSE, NULL); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -330,9 +331,9 @@ int cdrom_cdda_resume() { int rv; - mutex_lock(mutex); + mutex_lock(&mutex); rv = cdrom_exec_cmd(CMD_RELEASE, NULL); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -341,9 +342,9 @@ int cdrom_spin_down() { int rv; - mutex_lock(mutex); + mutex_lock(&mutex); rv = cdrom_exec_cmd(CMD_STOP, NULL); - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -354,7 +355,7 @@ volatile uint32 *react = (uint32*)0xa05f74e4, *bios = (uint32*)0xa0000000; - if(mutex != NULL) + if(initted) return -1; /* Reactivate drive: send the BIOS size and then read each @@ -369,7 +370,7 @@ gdc_init_system(); /* Initialize mutex */ - mutex = mutex_create(); + mutex_init(&mutex, MUTEX_TYPE_NORMAL); /* Do an initial initialization */ cdrom_reinit(); @@ -378,10 +379,10 @@ } void cdrom_shutdown() { - if(mutex == NULL) + if(!initted) return; - mutex_destroy(mutex); - mutex = NULL; + mutex_destroy(&mutex); + initted = 0; } Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c 2012-06-08 20:32:15 UTC (rev 805) @@ -170,7 +170,7 @@ PVR_SET(PVR_UNK_0118, 0x00008040); /* M */ /* Initialize PVR DMA */ - pvr_state.dma_lock = mutex_create(); + mutex_init((mutex_t *)&pvr_state.dma_lock, MUTEX_TYPE_NORMAL); pvr_dma_init(); /* Setup our wait-ready semaphore */ @@ -226,7 +226,7 @@ /* Destroy the semaphore */ sem_destroy(pvr_state.ready_sem); - mutex_destroy(pvr_state.dma_lock); + mutex_destroy((mutex_t *)&pvr_state.dma_lock); /* Clear video memory */ vid_empty(); Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h 2012-06-08 20:32:15 UTC (rev 805) @@ -113,27 +113,27 @@ /* Note that these must match the list types in pvr.h; these are here mainly because they're easier to type =) */ -#define PVR_OPB_OP 0 /* Array indeces for these structures */ -#define PVR_OPB_OM 1 -#define PVR_OPB_TP 2 -#define PVR_OPB_TM 3 -#define PVR_OPB_PT 4 +#define PVR_OPB_OP 0 /* Array indeces for these structures */ +#define PVR_OPB_OM 1 +#define PVR_OPB_TP 2 +#define PVR_OPB_TM 3 +#define PVR_OPB_PT 4 #define PVR_OPB_COUNT 5 // TA buffers structure: we have two sets of these typedef struct { - uint32 vertex, vertex_size; /* Vertex buffer */ - uint32 opb, opb_size; /* Object pointer buffers, size */ - uint32 opb_type[PVR_OPB_COUNT]; /* Object pointer buffers (of each type) */ + uint32 vertex, vertex_size; /* Vertex buffer */ + uint32 opb, opb_size; /* Object pointer buffers, size */ + uint32 opb_type[PVR_OPB_COUNT]; /* Object pointer buffers (of each type) */ uint32 tile_matrix, tile_matrix_size; /* Tile matrix, size */ } pvr_ta_buffers_t; // DMA buffers structure: we have two sets of these typedef struct { - uint8 * base[PVR_OPB_COUNT]; // DMA buffers, if assigned + uint8 * base[PVR_OPB_COUNT]; // DMA buffers, if assigned uint32 ptr[PVR_OPB_COUNT]; // DMA buffer write pointer, if used - uint32 size[PVR_OPB_COUNT]; // DMA buffer sizes, or zero if none - int ready; // >0 if these buffers are ready to be DMAed + uint32 size[PVR_OPB_COUNT]; // DMA buffer sizes, or zero if none + int ready; // >0 if these buffers are ready to be DMAed } pvr_dma_buffers_t; // Frame buffers structure: we have two sets of these @@ -149,60 +149,60 @@ int valid; // General configuration - uint32 lists_enabled; // opb_completed's value when we're ready to render - uint32 list_reg_mask; // Active lists register mask - int dma_mode; // 1 if we are using DMA to transfer vertices - int opb_size[PVR_OPB_COUNT]; /* opb size flags */ - uint32 opb_ind[PVR_OPB_COUNT]; /* Individual opb sizes (in bytes) */ + uint32 lists_enabled; // opb_completed's value when we're ready to render + uint32 list_reg_mask; // Active lists register mask + int dma_mode; // 1 if we are using DMA to transfer vertices + int opb_size[PVR_OPB_COUNT]; // opb size flags + uint32 opb_ind[PVR_OPB_COUNT]; // Individual opb sizes (in bytes) // Pipeline state - int ram_target; // RAM buffer we're writing into - // (^1 == RAM buffer we're DMAing from) - int ta_target; // TA buffer we're writing (or DMAing) into - // (^1 == TA buffer we're rendering from) - int view_target; // Frame buffer we're viewing - // (^1 == frame buffer we're rendering to) + int ram_target; // RAM buffer we're writing into + // (^1 == RAM buffer we're DMAing from) + int ta_target; // TA buffer we're writing (or DMAing) into + // (^1 == TA buffer we're rendering from) + int view_target; // Frame buffer we're viewing + // (^1 == frame buffer we're rendering to) - int list_reg_open; // Which list is open for registration, if any? (non-DMA only) - uint32 lists_closed; // (1 << idx) for each list which the SH4 has lost interest in - uint32 lists_transferred; // (1 << idx) for each list which has completely transferred to the TA - uint32 lists_dmaed; // (1 << idx) for each list which has been DMA'd (DMA mode only) + int list_reg_open; // Which list is open for registration, if any? (non-DMA only) + uint32 lists_closed; // (1 << idx) for each list which the SH4 has lost interest in + uint32 lists_transferred; // (1 << idx) for each list which has completely transferred to the TA + uint32 lists_dmaed; // (1 << idx) for each list which has been DMA'd (DMA mode only) - mutex_t * dma_lock; // Locked if a DMA is in progress (vertex or texture) - int ta_busy; // >0 if a DMA is in progress and the TA hasn't signaled completion - int render_busy; // >0 if a render is in progress - int render_completed; // >1 if a render has recently finished + mutex_t dma_lock; // Locked if a DMA is in progress (vertex or texture) + int ta_busy; // >0 if a DMA is in progress and the TA hasn't signaled completion + int render_busy; // >0 if a render is in progress + int render_completed; // >1 if a render has recently finished // Memory pointers / buffers pvr_dma_buffers_t dma_buffers[2]; // DMA buffers (if any) pvr_ta_buffers_t ta_buffers[2]; // TA buffers pvr_frame_buffers_t frame_buffers[2]; // Frame buffers - uint32 texture_base; // Start of texture RAM + uint32 texture_base; // Start of texture RAM // Screen size / clipping constants - int w, h; // Screen width, height - int tw, th; // Screen tile width, height - uint32 tsize_const; // Screen tile size constant - float zclip; // Z clip plane - uint32 pclip_left, pclip_right; // X pixel clip constants - uint32 pclip_top, pclip_bottom; // Y pixel clip constants - uint32 pclip_x, pclip_y; // Composited clip constants - uint32 bg_color; // Background color in ARGB format + int w, h; // Screen width, height + int tw, th; // Screen tile width, height + uint32 tsize_const; // Screen tile size constant + float zclip; // Z clip plane + uint32 pclip_left, pclip_right; // X pixel clip constants + uint32 pclip_top, pclip_bottom; // Y pixel clip constants + uint32 pclip_x, pclip_y; // Composited clip constants + uint32 bg_color; // Background color in ARGB format /* Running statistics on the PVR system. All vars are in terms of milliseconds. */ - uint32 vbl_count; // VBlank counter for animations and such - uint32 frame_count; // Total number of viewed frames - uint64 frame_last_time; // When did the last frame completion occur? - uint64 buf_start_time; // When did the last DMA buffer fill begin? - uint64 reg_start_time; // When did the last registration begin? - uint64 rnd_start_time; // When did the last render begin? - int frame_last_len; // VBlank-to-VBlank length for the last frame (1.0/FrameRate) - int buf_last_len; // Cumulative buffer fill time for the last frame - int reg_last_len; // Registration time for the last frame - int rnd_last_len; // Render time for the last frame - uint32 vtx_buf_used; // Vertex buffer used size for the last frame - uint32 vtx_buf_used_max; // Maximum used vertex buffer size + uint32 vbl_count; // VBlank counter for animations and such + uint32 frame_count; // Total number of viewed frames + uint64 frame_last_time; // When did the last frame completion occur? + uint64 buf_start_time; // When did the last DMA buffer fill begin? + uint64 reg_start_time; // When did the last registration begin? + uint64 rnd_start_time; // When did the last render begin? + int frame_last_len; // VBlank-to-VBlank length for the last frame (1.0/FrameRate) + int buf_last_len; // Cumulative buffer fill time for the last frame + int reg_last_len; // Registration time for the last frame + int rnd_last_len; // Render time for the last frame + uint32 vtx_buf_used; // Vertex buffer used size for the last frame + uint32 vtx_buf_used_max; // Maximum used vertex buffer size /* Wait-ready semaphore: this will be signaled whenever the pvr_wait_ready() call should be ready to return. */ @@ -221,7 +221,7 @@ int to_txr_rp; // Output address for to-texture mode - uint32 to_txr_addr; + uint32 to_txr_addr; } pvr_state_t; /* There will be exactly one of these in KOS (in pvr_globals.c) */ Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c 2012-06-08 20:32:15 UTC (rev 805) @@ -60,7 +60,7 @@ //DBG(("dma_complete(buf %d)\n", pvr_state.ram_target ^ 1)); // Unlock - mutex_unlock(pvr_state.dma_lock); + mutex_unlock((mutex_t *)&pvr_state.dma_lock); pvr_state.lists_dmaed = 0; // Buffers are now empty again @@ -181,7 +181,7 @@ if(pvr_state.dma_mode && !pvr_state.ta_busy && pvr_state.dma_buffers[pvr_state.ram_target ^ 1].ready - && mutex_trylock(pvr_state.dma_lock) >= 0) { + && mutex_trylock((mutex_t *)&pvr_state.dma_lock) >= 0) { pvr_sync_stats(PVR_SYNC_REGSTART); // Begin DMAing the first list. Modified: kos/kernel/arch/dreamcast/hardware/pvr/pvr_texture.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/pvr/pvr_texture.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/arch/dreamcast/hardware/pvr/pvr_texture.c 2012-06-08 20:32:15 UTC (rev 805) @@ -187,10 +187,10 @@ /* We only enable DMA here for now since it sort of changes things to have to allocate an intermediary buffer. */ if(flags & PVR_TXRLOAD_DMA) { - mutex_lock(pvr_state.dma_lock); + mutex_lock((mutex_t *)&pvr_state.dma_lock); pvr_txr_load_dma(img->data, dst, img->byte_count, (flags & PVR_TXRLOAD_NONBLOCK) ? 1 : 0, NULL, 0); - mutex_unlock(pvr_state.dma_lock); + mutex_unlock((mutex_t *)&pvr_state.dma_lock); } else if(flags & PVR_TXRLOAD_SQ) { sq_cpy(dst, img->data, img->byte_count); Modified: kos/kernel/exports/nmmgr.c =================================================================== --- kos/kernel/exports/nmmgr.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/exports/nmmgr.c 2012-06-08 20:32:15 UTC (rev 805) @@ -23,7 +23,7 @@ #include <kos/exports.h> /* Thread mutex for our name handler list */ -static mutex_t * mutex; +static mutex_t mutex = MUTEX_INITIALIZER; /* Name handler structures; these structs contain path/type pairs that describe how to handle a given path name. */ @@ -53,11 +53,11 @@ /* Add a name handler */ int nmmgr_handler_add(nmmgr_handler_t *hnd) { - mutex_lock(mutex); + mutex_lock(&mutex); LIST_INSERT_HEAD(&nmmgr_handlers, hnd, list_ent); - mutex_unlock(mutex); + mutex_unlock(&mutex); return 0; } @@ -67,7 +67,7 @@ nmmgr_handler_t *c; int rv = -1; - mutex_lock(mutex); + mutex_lock(&mutex); /* Verify that it's actually in there */ LIST_FOREACH(c, &nmmgr_handlers, list_ent) { @@ -78,7 +78,7 @@ } } - mutex_unlock(mutex); + mutex_unlock(&mutex); return rv; } @@ -90,9 +90,6 @@ /* Start with no handlers */ LIST_INIT(&nmmgr_handlers); - /* Init thread mutex */ - mutex = mutex_create(); - /* Initialize our internal exports */ export_init(); @@ -112,6 +109,4 @@ c = n; } - - mutex_destroy(mutex); } Modified: kos/kernel/fs/fs_pty.c =================================================================== --- kos/kernel/fs/fs_pty.c 2012-06-08 16:06:24 UTC (rev 804) +++ kos/kernel/fs/fs_pty.c 2012-06-08 20:32:15 UTC (rev 805) @@ -59,14 +59,14 @@ int id; - mutex_t * mutex; + mutex_t mutex; condvar_t * ready_read, * ready_write; } ptyhalf_t; /* Our global pty list */ static ptylist_t ptys; static int pty_id_highest; -static mutex_t * list_mutex; +static mutex_t list_mutex; /* This struct is used for traversing the directory listing */ typedef struct diritem { @@ -80,7 +80,7 @@ dirent_t dirent; - mutex_t * mutex; + mutex_t mutex; } dirlist_t; /* We'll have one of these for each opened pipe */ @@ -148,20 +148,20 @@ master->refcnt = slave->refcnt = 0; /* Allocate a mutex for each for multiple readers or writers */ - master->mutex = mutex_create(); + mutex_init(&master->mutex, MUTEX_TYPE_NORMAL); master->ready_read = cond_create(); master->ready_write = cond_create(); - slave->mutex = mutex_create(); + mutex_init(&slave->mutex, MUTEX_TYPE_NORMAL); slave->ready_read = cond_create(); slave->ready_write = cond_create(); /* Add it to the list */ - mutex_lock(list_mutex); + mutex_lock(&list_mutex); master->id = ++pty_id_highest; slave->id = master->id; LIST_INSERT_HEAD(&ptys, master, list); LIST_INSERT_HEAD(&ptys, slave, list); - mutex_unlock(list_mutex); + mutex_unlock(&list_mutex); /* Call back up to fs to open two file descriptors */ @@ -189,7 +189,7 @@ /* Make sure no one else is messing with the list and then disable everything for a bit */ - mutex_lock(list_mutex); + mutex_lock(&list_mutex); old = irq_disable(); again: @@ -199,7 +199,7 @@ n = LIST_NEXT(c, list); /* Don't mess with the kernel console or locked items */ - if(c->id == 0 || mutex_is_locked(c->mutex)) + if(c->id == 0 || mutex_is_locked(&c->mutex)) goto next; /* Not in use? */ @@ -211,7 +211,7 @@ /* Free all our structs */ cond_destroy(c->ready_read); cond_destroy(c->ready_write); - mutex_destroy(c->mutex); + mutex_destroy(&c->mutex); /* Remove us from the list */ LIST_REMOVE(c, list); @@ -219,7 +219,7 @@ /* Now to deal with our partner... */ cond_destroy(c->other->ready_read); cond_destroy(c->other->ready_write); - mutex_destroy(c->other->mutex); + mutex_destroy(&c->other->mutex); /* Remove it from the list */ LIST_REMOVE(c->other, list); @@ -237,7 +237,7 @@ } irq_restore(old); - mutex_unlock(list_mutex); + mutex_unlock(&list_mutex); } static void * pty_open_dir(const char * fn, int mode) { @@ -246,7 +246,7 @@ int cnt; pipefd_t * fdobj = NULL; - mutex_lock(list_mutex); + mutex_lock(&list_mutex); /* Go through and count the number of items */ cnt = 0; @@ -295,7 +295,7 @@ fdobj->mode = mode; done: - mutex_unlock(list_mutex); + mutex_unlock(&list_mutex); return (void *)fdobj; } @@ -327,12 +327,12 @@ id = strtol(fn + 2, NULL, 16); /* Do we have that pty? */ - mutex_lock(list_mutex); + mutex_lock(&list_mutex); LIST_FOREACH(ph, &ptys, list) { if(ph->id == id) break; } - mutex_unlock(list_mutex); + mutex_unlock(&list_mutex); if(!ph) { errno = ENOENT; @@ -350,9 +350,9 @@ } /* Now add a refcnt and return it */ - mutex_lock(ph->mutex); + mutex_lock(&ph->mutex); ph->refcnt++; - mutex_unlock(ph->mutex); + mutex_unlock(&ph->mutex); fdobj = malloc(sizeof(pipefd_t)); memset(fdobj, 0, sizeof(pipefd_t)); @@ -394,7 +394,7 @@ if(fdobj->type == PF_PTY) { /* De-ref this end of it */ - mutex_lock(fdobj->d.p->mutex); + mutex_lock(&fdobj->d.p->mutex); fdobj->d.p->refcnt--; if(fdobj->d.p->refcnt <= 0) { @@ -403,7 +403,7 @@ cond_broadcast(fdobj->d.p->ready_write); } - mutex_unlock(fdobj->d.p->mutex); + mutex_unlock(&fdobj->d.p->mutex); pty_destroy_unused(); } @@ -479,7 +479,7 @@ return pty_read_serial(fdobj, ph, buf, bytes); /* Lock the ptyhalf */ - mutex_lock(ph->mutex); + mutex_lock(&ph->mutex); /* Is there anything to read? */ while(!ph->cnt && ph->other->refcnt > 0) { @@ -490,7 +490,7 @@ goto done; } ... [truncated message content] |
From: <ljs...@us...> - 2012-06-08 16:06:35
|
Revision: 804 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=804&view=rev Author: ljsebald Date: 2012-06-08 16:06:24 +0000 (Fri, 08 Jun 2012) Log Message: ----------- Make it so that stdin/stdout/stderr will be set as line buffered (newlib has to think they're ttys if we have fcntl, which we do now). Modified Paths: -------------- kos/kernel/libc/newlib/newlib_isatty.c Modified: kos/kernel/libc/newlib/newlib_isatty.c =================================================================== --- kos/kernel/libc/newlib/newlib_isatty.c 2012-06-07 00:04:16 UTC (rev 803) +++ kos/kernel/libc/newlib/newlib_isatty.c 2012-06-08 16:06:24 UTC (rev 804) @@ -1,16 +1,29 @@ /* KallistiOS ##version## newlib_isatty.c - Copyright (C)2004 Dan Potter + Copyright (C) 2004 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ #include <sys/reent.h> int isatty(int fd) { + /* Make sure that stdin, stdout, and stderr are shown as ttys, otherwise + they won't be set as line-buffered. */ + if(fd >= 0 && fd <= 2) { + return 1; + } + return 0; } int _isatty_r(struct _reent *reent, int fd) { + /* Make sure that stdin, stdout, and stderr are shown as ttys, otherwise + they won't be set as line-buffered.*/ + if(fd >= 0 && fd <= 2) { + return 1; + } + return 0; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-07 00:04:22
|
Revision: 803 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=803&view=rev Author: ljsebald Date: 2012-06-07 00:04:16 +0000 (Thu, 07 Jun 2012) Log Message: ----------- Add the select() function. Modified Paths: -------------- kos/kernel/libc/koslib/Makefile Added Paths: ----------- kos/include/sys/select.h kos/kernel/libc/koslib/select.c Added: kos/include/sys/select.h =================================================================== --- kos/include/sys/select.h (rev 0) +++ kos/include/sys/select.h 2012-06-07 00:04:16 UTC (rev 803) @@ -0,0 +1,45 @@ +/* KallistiOS ##version## + + sys/select.h + Copyright (C) 2012 Lawrence Sebald + +*/ + +/** \file select.h + \brief Definitions for the select() function. + + This file contains the definitions needed for using the select() function, + as directed by the POSIX 2008 standard (aka The Open Group Base + Specifications Issue 7). Currently the functionality defined herein only + really works for sockets, and that is likely how it will stay for some time. + + \author Lawrence Sebald +*/ + +#ifndef __SYS_SELECT_H +#define __SYS_SELECT_H + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +#include <time.h> + +/* <sys/types.h> defines fd_set and friends for us, so there's really not much + that we have to do here... */ + +/** \brief Timeout value for the select() function. + \headerfile sys/select.h +*/ +struct timeval { + time_t tv_sec; /**< \brief Seconds */ + suseconds_t tv_usec; /**< \brief Microseconds */ +}; + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, + struct timeval *timeout); + +__END_DECLS + +#endif /* !__SYS_SELECT_H */ Modified: kos/kernel/libc/koslib/Makefile =================================================================== --- kos/kernel/libc/koslib/Makefile 2012-06-06 22:52:53 UTC (rev 802) +++ kos/kernel/libc/koslib/Makefile 2012-06-07 00:04:16 UTC (rev 803) @@ -12,6 +12,6 @@ opendir.o readdir.o closedir.o rewinddir.o scandir.o seekdir.o \ telldir.o usleep.o inet_addr.o realpath.o getcwd.o chdir.o mkdir.o \ creat.o sleep.o rmdir.o rename.o inet_pton.o inet_ntop.o \ - inet_ntoa.o inet_aton.o poll.o + inet_ntoa.o inet_aton.o poll.o select.o include $(KOS_BASE)/Makefile.prefab Added: kos/kernel/libc/koslib/select.c =================================================================== --- kos/kernel/libc/koslib/select.c (rev 0) +++ kos/kernel/libc/koslib/select.c 2012-06-07 00:04:16 UTC (rev 803) @@ -0,0 +1,100 @@ +/* KallistiOS ##version## + + select.c + Copyright (C) 2012 Lawrence Sebald +*/ + +#include <poll.h> +#include <errno.h> +#include <string.h> +#include <sys/select.h> + +#include <kos/dbglog.h> + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, + struct timeval *timeout) { + int i, added, j = 0, rv, tmout = -1; + struct pollfd pollfds[nfds > FD_SETSIZE ? 1 : nfds]; + fd_set tmp; + + if(nfds > FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + FD_ZERO(&tmp); + + if(!readfds) + readfds = &tmp; + if(!writefds) + writefds = &tmp; + if(!errorfds) + errorfds = &tmp; + + /* Clear all the fds */ + memset(pollfds, 0, sizeof(struct pollfd) * nfds); + + /* Set up the call to poll to do the real work */ + for(i = 0; i < nfds; ++i) { + added = 0; + + if(FD_ISSET(i, readfds)) { + pollfds[j].fd = i; + pollfds[j].events = POLLIN; + added = 1; + } + + if(FD_ISSET(i, writefds)) { + pollfds[j].fd = i; + pollfds[j].events |= POLLOUT; + added = 1; + } + + if(FD_ISSET(i, errorfds)) { + pollfds[j].fd = i; + pollfds[j].events |= POLLPRI; + added = 1; + } + + if(added) + ++j; + } + + if(timeout) + tmout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + + /* Poll for a response */ + if((rv = poll(pollfds, j, tmout)) < 0) { + return rv; + } + + rv = 0; + FD_ZERO(readfds); + FD_ZERO(writefds); + FD_ZERO(errorfds); + + /* We've gotten a response, lets see what we have */ + for(i = 0; i < j; ++i) { + /* Make sure there wasn't an error */ + if(pollfds[i].revents & POLLNVAL) { + errno = EBADF; + return -1; + } + + if(pollfds[i].revents & POLLIN) { + FD_SET(pollfds[i].fd, readfds); + ++j; + } + if(pollfds[i].revents & POLLOUT) { + FD_SET(pollfds[i].fd, writefds); + ++j; + } + if((pollfds[i].events & POLLPRI) && + (pollfds[i].revents & (POLLPRI | POLLERR | POLLHUP))) { + FD_SET(pollfds[i].fd, errorfds); + ++j; + } + } + + return j; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-06 22:53:00
|
Revision: 802 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=802&view=rev Author: ljsebald Date: 2012-06-06 22:52:53 +0000 (Wed, 06 Jun 2012) Log Message: ----------- Add poll() and its support work in the fs and network stuff. Modified Paths: -------------- kos/include/kos/fs.h kos/include/kos/fs_socket.h kos/kernel/fs/fs_socket.c kos/kernel/libc/koslib/Makefile kos/kernel/net/net_tcp.c kos/kernel/net/net_udp.c Added Paths: ----------- kos/include/poll.h kos/kernel/libc/koslib/poll.c Modified: kos/include/kos/fs.h =================================================================== --- kos/include/kos/fs.h 2012-06-06 22:49:14 UTC (rev 801) +++ kos/include/kos/fs.h 2012-06-06 22:52:53 UTC (rev 802) @@ -167,6 +167,9 @@ /** \brief Manipulate file control flags on the given file. */ int (*fcntl)(void *fd, int cmd, va_list ap); + + /** \brief Check if an event is pending on the given file. */ + short (*poll)(void *fd, short events); } vfs_handler_t; /** \brief The number of distinct file descriptors that can be in use at a Modified: kos/include/kos/fs_socket.h =================================================================== --- kos/include/kos/fs_socket.h 2012-06-06 22:49:14 UTC (rev 801) +++ kos/include/kos/fs_socket.h 2012-06-06 22:52:53 UTC (rev 802) @@ -320,6 +320,20 @@ \retval -1 On error (generally, set errno appropriately). */ int (*fcntl)(net_socket_t *s, int cmd, va_list ap); + + /** \brief Poll for events. + + This function should check the given socket for any events that may have + already occured that are specified. This is used to back the ::poll() + system call. This function should not block to wait for any events. This + function may be called in an interrupt. + + \param s The socket to poll. + \param events The events to check for. + \retval A mask of any of the events specified that are + currently true in the socket. 0 if none are true. + */ + short (*poll)(net_socket_t *s, short events); } fs_socket_proto_t; /** \brief Initializer for the entry field in the fs_socket_proto_t struct. */ Added: kos/include/poll.h =================================================================== --- kos/include/poll.h (rev 0) +++ kos/include/poll.h 2012-06-06 22:52:53 UTC (rev 802) @@ -0,0 +1,85 @@ +/* KallistiOS ##version## + + poll.h + Copyright (C) 2012 Lawrence Sebald +*/ + +/** \file poll.h + \brief Definitions for the poll() function. + + This file contains the definitions needed for using the poll() function, as + directed by the POSIX 2008 standard (aka The Open Group Base Specifications + Issue 7). Currently the functionality defined herein only works for sockets, + and that is likely how it will stay for some time. + + The poll() function works quite similarly to the select() function that it + is quite likely that you'd be more familiar with. + + \author Lawrence Sebald +*/ + +#ifndef __POLL_H +#define __POLL_H + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/** \brief Type representing a number of file descriptors. */ +typedef __uint32_t nfds_t; + +/** \brief Structure representing a single file descriptor used by poll(). + \headerfile poll.h +*/ +struct pollfd { + int fd; /**< \brief The file descriptor in question. */ + short events; /**< \brief Events to poll for on input. */ + short revents; /**< \brief Events signalled for output. */ +}; + +/** \defgroup poll_events Events for the poll() function + + These are the events that can be set in the events or revents fields of the + struct pollfd. + + @{ +*/ +#define POLLRDNORM (1 << 0) /**< \brief Normal data may be read */ +#define POLLRDBAND (1 << 1) /**< \brief Priority data may be read */ +#define POLLPRI (1 << 2) /**< \brief High-priority data may be read */ +#define POLLOUT (1 << 3) /**< \brief Normal data may be written */ +#define POLLWRNORM POLLOUT /**< \brief Normal data may be written */ +#define POLLWRBAND (1 << 4) /**< \brief Priority data may be written */ +#define POLLERR (1 << 5) /**< \brief Error has occurred (revents only) */ +#define POLLHUP (1 << 6) /**< \brief Peer disconnected (revents only) */ +#define POLLNVAL (1 << 7) /**< \brief Invalid fd (revents only) */ + +/** \brief Data other than high-priority data may be read */ +#define POLLIN (POLLRDNORM | POLLRDBAND) +/** @} */ + +/** \brief Poll a group of file descriptors for activity. + + This function will poll a group of file descriptors to check for the events + specified on them. The function shall block for the specified period of time + (in milliseconds) waiting for an event to occur. The function shall return + as soon as at least one fd matches the events specified (or one of the error + conditions), or when timeout expires. + + \param fds The file descriptors to check, and what events to look + for on each. + \param nfds Number of elements in fds. + \param timeout Maximum amount of time to block, in milliseconds. Pass + 0 to ensure the function does not block and -1 to block + for an "infinite" amount of time, until an event occurs. + \return -1 on error (sets errno as appropriate), or the number + of file descriptors that matched the event flags before + the function returns. + \sa poll_events +*/ +int poll(struct pollfd fds[], nfds_t nfds, int timeout); + +__END_DECLS + +#endif /* !POLL_H */ Modified: kos/kernel/fs/fs_socket.c =================================================================== --- kos/kernel/fs/fs_socket.c 2012-06-06 22:49:14 UTC (rev 801) +++ kos/kernel/fs/fs_socket.c 2012-06-06 22:52:53 UTC (rev 802) @@ -79,6 +79,11 @@ return sock->protocol->fcntl(sock, cmd, ap); } +static short fs_socket_poll(void *hnd, short events) { + net_socket_t *sock = (net_socket_t *)hnd; + return sock->protocol->poll(sock, events); +} + /* VFS handler */ static vfs_handler_t vh = { /* Name handler */ @@ -109,7 +114,8 @@ NULL, /* stat */ NULL, /* mkdir */ NULL, /* rmdir */ - fs_socket_fcntl /* fcntl */ + fs_socket_fcntl, /* fcntl */ + fs_socket_poll /* poll */ }; /* Have we been initialized? */ Modified: kos/kernel/libc/koslib/Makefile =================================================================== --- kos/kernel/libc/koslib/Makefile 2012-06-06 22:49:14 UTC (rev 801) +++ kos/kernel/libc/koslib/Makefile 2012-06-06 22:52:53 UTC (rev 802) @@ -12,6 +12,6 @@ opendir.o readdir.o closedir.o rewinddir.o scandir.o seekdir.o \ telldir.o usleep.o inet_addr.o realpath.o getcwd.o chdir.o mkdir.o \ creat.o sleep.o rmdir.o rename.o inet_pton.o inet_ntop.o \ - inet_ntoa.o inet_aton.o + inet_ntoa.o inet_aton.o poll.o include $(KOS_BASE)/Makefile.prefab Added: kos/kernel/libc/koslib/poll.c =================================================================== --- kos/kernel/libc/koslib/poll.c (rev 0) +++ kos/kernel/libc/koslib/poll.c 2012-06-06 22:52:53 UTC (rev 802) @@ -0,0 +1,158 @@ +/* KallistiOS ##version## + + poll.c + Copyright (C) 2012 Lawrence Sebald + +*/ + +#include <poll.h> +#include <errno.h> +#include <sys/queue.h> + +#include <arch/irq.h> +#include <kos/fs.h> +#include <kos/mutex.h> +#include <kos/cond.h> + +struct poll_int { + LIST_ENTRY(poll_int) entry; + struct pollfd *fds; + nfds_t nfds; + int nmatched; + condvar_t cv; +}; + +LIST_HEAD(polllist, poll_int) poll_list; + +static mutex_t mutex = MUTEX_INITIALIZER; + +void __poll_event_trigger(int fd, short event) { + struct poll_int *i; + nfds_t j; + int gotone = 0; + short mask; + + if(irq_inside_int()) { + if(mutex_trylock(&mutex)) + /* XXXX: Uhh... this is bad... */ + return; + } + else { + mutex_lock(&mutex); + } + + /* Look through the list of poll fds for any that match */ + LIST_FOREACH(i, &poll_list, entry) { + for(j = 0; j < i->nfds; ++j) { + if(i->fds[j].fd == fd) { + mask = i->fds[j].events | POLLERR | POLLHUP | POLLNVAL; + if(event & mask) { + i->fds[j].revents |= event & mask; + ++i->nmatched; + gotone = 1; + } + } + } + + /* If we got any events, signal the waiting thread to wake it up. */ + if(gotone) { + cond_signal(&i->cv); + gotone = 0; + } + } + + mutex_unlock(&mutex); +} + +int poll(struct pollfd fds[], nfds_t nfds, int timeout) { + struct poll_int p = { { 0 }, fds, nfds, 0, COND_INITIALIZER }; + int tmp; + nfds_t i; + vfs_handler_t *hndl; + void *hnd; + + if(irq_inside_int()) { + if(mutex_trylock(&mutex)) { + errno = EAGAIN; + return -1; + } + } + else { + mutex_lock(&mutex); + } + + /* Check if any of the fds already match */ + for(i = 0; i < nfds; ++i) { + hndl = fs_get_handler(fds[i].fd); + hnd = fs_get_handle(fds[i].fd); + fds[i].revents = 0; + + /* If we didn't get one of these, then assume its a bad fd. */ + if(!hndl || !hnd) { + fds[i].revents = POLLNVAL; + ++p.nmatched; + continue; + } + + if(!hndl->poll) { + /* Assume its a regular file if there's no poll method in the + handler. */ + if(fds[i].events & (POLLRDNORM | POLLWRNORM)) { + fds[i].revents |= (POLLRDNORM | POLLWRNORM) & fds[i].events; + ++p.nmatched; + } + } + else { + if((fds[i].revents = hndl->poll(hnd, fds[i].events))) { + ++p.nmatched; + } + } + } + + /* If the user specified a 0 timeout, or we've already matched something, + bail out now. */ + if(p.nmatched || !timeout) { + mutex_unlock(&mutex); + return p.nmatched; + } + + /* We can't actually wait while we're in an interrupt, so if we got this far + it is an error. */ + if(irq_inside_int()) { + mutex_unlock(&mutex); + errno = EPERM; + return -1; + } + + /* Map to the value used by cond_wait_timed() */ + if(timeout == -1) + timeout = 0; + + /* Add this instance to the list */ + LIST_INSERT_HEAD(&poll_list, &p, entry); + + tmp = errno; + if(cond_wait_timed(&p.cv, &mutex, timeout)) { + if(errno == EAGAIN) { + errno = tmp; + tmp = 0; + goto out; + } + else { + /* The mutex won't be locked if errno != EAGAIN */ + mutex_lock(&mutex); + errno = EINTR; + tmp = -1; + goto out; + } + } + + tmp = p.nmatched; + +out: + /* Remove this instance from the list */ + LIST_REMOVE(&p, entry); + + mutex_unlock(&mutex); + return tmp; +} Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-06 22:49:14 UTC (rev 801) +++ kos/kernel/net/net_tcp.c 2012-06-06 22:52:53 UTC (rev 802) @@ -9,6 +9,7 @@ #include <stdlib.h> #include <string.h> #include <stdint.h> +#include <poll.h> #include <sys/socket.h> #include <kos/fs.h> @@ -1916,6 +1917,82 @@ return rv; } +static short net_tcp_poll(net_socket_t *hnd, short events) { + struct tcp_sock *sock; + short rv = 0; + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + return 0; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + /* Lock the mutex on the socket itself first. We need to pull some data from + it that doesn't affect the rest of the list, so let's start there... */ + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + return POLLNVAL; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + return 0; + } + } + else { + mutex_lock(sock->mutex); + } + + switch(sock->state) { + case TCP_STATE_LISTEN: + if(sock->listen.count) + rv = POLLRDNORM; + break; + + case TCP_STATE_CLOSED | TCP_STATE_RESET: + rv = POLLHUP; + + if(sock->data.rcvbuf_cur_sz) + rv |= POLLRDNORM; + break; + + case TCP_STATE_CLOSED: + case TCP_STATE_SYN_SENT: + break; + + case TCP_STATE_CLOSE_WAIT: + if(sock->data.sndbuf_cur_sz < sock->sndbuf_sz) + rv |= POLLWRNORM | POLLWRBAND; + /* Fall through... */ + + case TCP_STATE_TIME_WAIT: + case TCP_STATE_CLOSING: + rv = POLLRDNORM; + break; + + case TCP_STATE_SYN_RECEIVED: + case TCP_STATE_ESTABLISHED: + if(sock->data.sndbuf_cur_sz < sock->sndbuf_sz) + rv |= POLLWRNORM | POLLWRBAND; + /* Fall through... */ + + case TCP_STATE_FIN_WAIT_1: + case TCP_STATE_FIN_WAIT_2: + case TCP_STATE_LAST_ACK: + if(sock->data.rcvbuf_cur_sz) + rv |= POLLRDNORM; + break; + } + + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + return rv & (events | POLLHUP | POLLERR); +} + static void tcp_rst(netif_t *net, const struct in6_addr *src, const struct in6_addr *dst, uint16_t src_port, uint16_t dst_port, uint16_t flags, uint32_t seq, @@ -2209,6 +2286,8 @@ return NULL; } +extern void __poll_event_trigger(int fd, short event); + /* This function is basically a direct implementation of the first two and a half steps of the SEGMENT ARRIVES event processing defined in RFC 793 on pages 65 and 66. There are a few parts that are omitted and some are put off @@ -2218,7 +2297,7 @@ struct tcp_sock *s, uint16_t flags, int size) { int j = 0; int end_of_opts; - uint16_t mss; + uint16_t mss = 576; /* Incoming segments with a RST should be ignored */ if(flags & TCP_FLAG_RST) @@ -2242,7 +2321,6 @@ break; case TCP_OPT_MSS: - if(j + 4 > end_of_opts || tcp->options[j + 1] != 4) return -1; @@ -2299,6 +2377,7 @@ s->listen.tail = 0; /* Signal the condvar, in case anyone's waiting */ + __poll_event_trigger(s->sock, POLLRDNORM); cond_signal(s->listen.cv); /* We're done, return success. */ @@ -2332,6 +2411,7 @@ if(flags & TCP_FLAG_RST) { if(gotack) { s->state = TCP_STATE_CLOSED | TCP_STATE_RESET; + __poll_event_trigger(s->sock, POLLHUP); cond_signal(s->data.recv_cv); cond_signal(s->data.send_cv); return 0; @@ -2388,12 +2468,14 @@ if(SEQ_GT(ack, s->data.snd.iss)) { s->state = TCP_STATE_ESTABLISHED; tcp_send_ack(s); + __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); cond_signal(s->data.send_cv); } } else { s->state = TCP_STATE_SYN_RECEIVED; tcp_send_syn(s, 1); + __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); cond_signal(s->data.send_cv); } } @@ -2463,6 +2545,7 @@ } else { s->state = TCP_STATE_RESET | TCP_STATE_CLOSED; + __poll_event_trigger(s->sock, POLLHUP); cond_signal(s->data.recv_cv); cond_signal(s->data.send_cv); return 0; @@ -2501,6 +2584,7 @@ s->data.sndbuf_acked += (int32_t)(ack - s->data.snd.una - acksyn); s->data.sndbuf_cur_sz -= (int32_t)(ack - s->data.snd.una - acksyn); s->data.snd.una = ack; + __poll_event_trigger(s->sock, POLLWRNORM | POLLWRBAND); cond_signal(s->data.send_cv); if(s->data.sndbuf_acked >= s->sndbuf_sz) @@ -2600,6 +2684,7 @@ } /* Signal any waiting thread and send an ack for what we read */ + __poll_event_trigger(s->sock, POLLRDNORM); cond_signal(s->data.recv_cv); tcp_send_ack(s); } @@ -2616,6 +2701,7 @@ /* ACK the FIN */ ++s->data.rcv.nxt; tcp_send_ack(s); + __poll_event_trigger(s->sock, POLLRDNORM); cond_signal(s->data.recv_cv); /* Do the various processing that needs to be done based on our state */ @@ -2874,7 +2960,8 @@ net_tcp_input, /* input */ net_tcp_getsockopt, /* getsockopt */ net_tcp_setsockopt, /* setsockopt */ - net_tcp_fcntl /* fcntl */ + net_tcp_fcntl, /* fcntl */ + net_tcp_poll /* poll */ }; int net_tcp_init() { Modified: kos/kernel/net/net_udp.c =================================================================== --- kos/kernel/net/net_udp.c 2012-06-06 22:49:14 UTC (rev 801) +++ kos/kernel/net/net_udp.c 2012-06-06 22:52:53 UTC (rev 802) @@ -9,6 +9,7 @@ #include <string.h> #include <stdlib.h> #include <errno.h> +#include <poll.h> #include <arpa/inet.h> #include <kos/net.h> #include <kos/mutex.h> @@ -50,6 +51,7 @@ uint32 flags; int domain; int hop_limit; + file_t sock; struct udp_pkt_queue packets; }; @@ -184,6 +186,8 @@ udpsock->local_addr.sin6_port = htons(port); } + udpsock->sock = hnd->fd; + mutex_unlock(udp_mutex); return 0; @@ -867,6 +871,33 @@ return rv; } +static short net_udp_poll(net_socket_t *hnd, short events) { + struct udp_sock *sock; + short rv = POLLWRNORM; + + if(irq_inside_int()) { + if(mutex_trylock(udp_mutex) == -1) + return 0; + } + else { + mutex_lock(udp_mutex); + } + + if(!(sock = (struct udp_sock *)hnd->data)) { + mutex_unlock(udp_mutex); + return POLLNVAL; + } + + if(!TAILQ_EMPTY(&sock->packets)) + rv |= POLLRDNORM; + + mutex_unlock(udp_mutex); + + return rv & events; +} + +extern void __poll_event_trigger(int fd, short event); + static int net_udp_input4(netif_t *src, const ip_hdr_t *ip, const uint8 *data, int size) { udp_hdr_t *hdr = (udp_hdr_t *)data; @@ -947,6 +978,7 @@ TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); ++udp_stats.pkt_recv; + __poll_event_trigger(sock->sock, POLLRDNORM); genwait_wake_one(sock); mutex_unlock(udp_mutex); @@ -1039,6 +1071,7 @@ TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); ++udp_stats.pkt_recv; + __poll_event_trigger(sock->sock, POLLRDNORM); genwait_wake_one(sock); mutex_unlock(udp_mutex); @@ -1164,7 +1197,8 @@ net_udp_input, net_udp_getsockopt, net_udp_setsockopt, - net_udp_fcntl + net_udp_fcntl, + net_udp_poll }; int net_udp_init() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-06 22:49:20
|
Revision: 801 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=801&view=rev Author: ljsebald Date: 2012-06-06 22:49:14 +0000 (Wed, 06 Jun 2012) Log Message: ----------- Add initializers for transient semaphores, condvars, and mutexes. Modified Paths: -------------- kos/include/kos/cond.h kos/include/kos/mutex.h kos/include/kos/sem.h Modified: kos/include/kos/cond.h =================================================================== --- kos/include/kos/cond.h 2012-06-06 02:35:24 UTC (rev 800) +++ kos/include/kos/cond.h 2012-06-06 22:49:14 UTC (rev 801) @@ -66,6 +66,9 @@ LIST_HEAD(condlist, condvar); /* \endcond */ +/** \brief Initializer for a transient condvar. */ +#define COND_INITIALIZER { { 0 } } + /** \brief Allocate a new condition variable. This function allocates and initializes a new condition variable for use. Modified: kos/include/kos/mutex.h =================================================================== --- kos/include/kos/mutex.h 2012-06-06 02:35:24 UTC (rev 800) +++ kos/include/kos/mutex.h 2012-06-06 22:49:14 UTC (rev 801) @@ -39,6 +39,9 @@ */ typedef semaphore_t mutex_t; +/** \brief Initializer for a transient mutex. */ +#define MUTEX_INITIALIZER SEM_INITIALIZER(1) + /** \brief Allocate a new mutex. This function allocates and initializes a new mutex for use. Modified: kos/include/kos/sem.h =================================================================== --- kos/include/kos/sem.h 2012-06-06 02:35:24 UTC (rev 800) +++ kos/include/kos/sem.h 2012-06-06 22:49:14 UTC (rev 801) @@ -52,6 +52,10 @@ LIST_HEAD(semlist, semaphore); /** \endcond */ +/** \brief Initializer for a transient semaphore. + \param value The initial count of the semaphore. */ +#define SEM_INITIALIZER(value) { { 0 }, value } + /** \brief Allocate a new semaphore. This function allocates and initializes a new semaphore for use. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-06 02:35:31
|
Revision: 800 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=800&view=rev Author: ljsebald Date: 2012-06-06 02:35:24 +0000 (Wed, 06 Jun 2012) Log Message: ----------- A few changes to go along with the update for GCC 4.7.0 and Newlib 1.20.0. The new ARM CFLAGS and AFLAGS require at least binutils 2.19, and are required for the change from arm-elf to arm-eabi that will be required for future versions of GCC (as arm-elf will likely be removed in GCC 4.8.0). Modified Paths: -------------- kos/environ_dreamcast.sh kos/kernel/fs/fs.c kos/kernel/libc/newlib/newlib_fcntl.c Modified: kos/environ_dreamcast.sh =================================================================== --- kos/environ_dreamcast.sh 2012-06-06 02:28:23 UTC (rev 799) +++ kos/environ_dreamcast.sh 2012-06-06 02:35:24 UTC (rev 800) @@ -1,9 +1,9 @@ # KallistiOS environment variable settings. These are the shared pieces # for the Dreamcast(tm) platform. -export KOS_CFLAGS="${KOS_CFLAGS} -ml -m4-single-only -fno-crossjumping" +export KOS_CFLAGS="${KOS_CFLAGS} -ml -m4-single-only -ffunction-sections -fdata-sections" export KOS_AFLAGS="${KOS_AFLAGS} -little" -export KOS_LDFLAGS="${KOS_LDFLAGS} -ml -m4-single-only -Wl,-Ttext=0x8c010000" +export KOS_LDFLAGS="${KOS_LDFLAGS} -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections" # Needed for GCC >= 4 export KOS_LD_SCRIPT="-T${KOS_BASE}/utils/ldscripts/shlelf.xc" @@ -14,6 +14,6 @@ export DC_ARM_AR="${DC_ARM_BASE}/bin/${DC_ARM_PREFIX}-ar" export DC_ARM_OBJCOPY="${DC_ARM_BASE}/bin/${DC_ARM_PREFIX}-objcopy" export DC_ARM_LD="${DC_ARM_BASE}/bin/${DC_ARM_PREFIX}-ld" - export DC_ARM_CFLAGS="-mcpu=arm7 -Wall -O2 -fno-strict-aliasing" - export DC_ARM_AFLAGS="-mcpu=arm7" + export DC_ARM_CFLAGS="-mcpu=arm7di -Wall -O2 -fno-strict-aliasing -Wl,--fix-v4bx -Wa,--fix-v4bx" + export DC_ARM_AFLAGS="-mcpu=arm7di --fix-v4bx" fi Modified: kos/kernel/fs/fs.c =================================================================== --- kos/kernel/fs/fs.c 2012-06-06 02:28:23 UTC (rev 799) +++ kos/kernel/fs/fs.c 2012-06-06 02:35:24 UTC (rev 800) @@ -615,9 +615,8 @@ } } -int fs_fcntl(file_t fd, int cmd, ...) { +int fs_vfcntl(file_t fd, int cmd, va_list ap) { fs_hnd_t *h = fs_map_hnd(fd); - va_list ap; int rv; if(!h) { @@ -630,13 +629,21 @@ return -1; } - va_start(ap, cmd); rv = h->handler->fcntl(h->hnd, cmd, ap); - va_end(ap); return rv; } +int fs_fcntl(file_t fd, int cmd, ...) { + va_list ap; + int rv; + + va_start(ap, cmd); + rv = fs_vfcntl(fd, cmd, ap); + va_end(ap); + return rv; +} + /* Initialize FS structures */ int fs_init() { return 0; Modified: kos/kernel/libc/newlib/newlib_fcntl.c =================================================================== --- kos/kernel/libc/newlib/newlib_fcntl.c 2012-06-06 02:28:23 UTC (rev 799) +++ kos/kernel/libc/newlib/newlib_fcntl.c 2012-06-06 02:35:24 UTC (rev 800) @@ -14,3 +14,15 @@ int _fcntl_r(struct _reent *reent, int fd, int cmd, int arg) { return fs_fcntl(fd, cmd, arg); } + +extern int fs_vfcntl(file_t fd, int cmd, va_list ap); + +int fcntl(int fd, int cmd, ...) { + va_list ap; + int rv; + + va_start(ap, cmd); + rv = fs_vfcntl(fd, cmd, ap); + va_end(ap); + return rv; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-06 02:28:31
|
Revision: 799 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=799&view=rev Author: ljsebald Date: 2012-06-06 02:28:23 +0000 (Wed, 06 Jun 2012) Log Message: ----------- Add patches for GCC 4.7.0 and Newlib 1.20.0 to dc-chain, and update it to use them. Modified Paths: -------------- kos/utils/dc-chain/Makefile kos/utils/dc-chain/download.sh kos/utils/dc-chain/unpack.sh Added Paths: ----------- kos/utils/dc-chain/patches/gcc-4.7.0-kos.diff kos/utils/dc-chain/patches/newlib-1.20.0-kos.diff Modified: kos/utils/dc-chain/Makefile =================================================================== --- kos/utils/dc-chain/Makefile 2012-06-05 14:51:24 UTC (rev 798) +++ kos/utils/dc-chain/Makefile 2012-06-06 02:28:23 UTC (rev 799) @@ -21,7 +21,7 @@ # User configuration sh_target=sh-elf -arm_target=arm-elf +arm_target=arm-eabi sh_prefix := /opt/toolchains/dc/$(sh_target) arm_prefix := /opt/toolchains/dc/$(arm_target) # kos_root: KOS subversion root (contains kos/ and kos-ports/) @@ -29,8 +29,8 @@ # kos_base: equivalent of KOS_BASE (contains include/ and kernel/) kos_base=$(kos_root)/kos binutils_ver=2.22 -gcc_ver=4.5.2 -newlib_ver=1.19.0 +gcc_ver=4.7.0 +newlib_ver=1.20.0 gdb_ver=6.7.1 insight_ver=6.7.1 # With GCC 4.x versions, the patches provide a kos thread model, so you should @@ -124,7 +124,7 @@ @echo "+++ Building $(src_dir) to $(build)..." -mkdir -p $(build) > $(log) - cd $(build); ../$(src_dir)/configure --target=$(target) --prefix=$(prefix) --enable-install-libbfd $(to_log) + cd $(build); ../$(src_dir)/configure --target=$(target) --prefix=$(prefix) $(to_log) make -C $(build) all install DESTDIR=$(DESTDIR) $(to_log) $(clean_up) Modified: kos/utils/dc-chain/download.sh =================================================================== --- kos/utils/dc-chain/download.sh 2012-06-05 14:51:24 UTC (rev 798) +++ kos/utils/dc-chain/download.sh 2012-06-06 02:28:23 UTC (rev 799) @@ -1,5 +1,5 @@ #!/bin/sh wget -c ftp://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 || exit 1 -wget -c ftp://ftp.gnu.org/gnu/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2 || exit 1 -wget -c ftp://sources.redhat.com/pub/newlib/newlib-1.19.0.tar.gz || exit 1 +wget -c ftp://ftp.gnu.org/gnu/gcc/gcc-4.7.0/gcc-4.7.0.tar.bz2 || exit 1 +wget -c ftp://sources.redhat.com/pub/newlib/newlib-1.20.0.tar.gz || exit 1 Added: kos/utils/dc-chain/patches/gcc-4.7.0-kos.diff =================================================================== --- kos/utils/dc-chain/patches/gcc-4.7.0-kos.diff (rev 0) +++ kos/utils/dc-chain/patches/gcc-4.7.0-kos.diff 2012-06-06 02:28:23 UTC (rev 799) @@ -0,0 +1,2100 @@ +diff -ruN gcc-4.7.0/gcc/configure gcc-4.7.0-kos/gcc/configure +--- gcc-4.7.0/gcc/configure 2012-03-08 08:54:54.000000000 -0500 ++++ gcc-4.7.0-kos/gcc/configure 2012-06-04 19:16:35.000000000 -0400 +@@ -11262,7 +11262,7 @@ + target_thread_file='single' + ;; + aix | dce | lynx | mipssde | posix | rtems | \ +- single | tpf | vxworks | win32) ++ single | tpf | vxworks | win32 | kos) + target_thread_file=${enable_threads} + ;; + *) +diff -ruN gcc-4.7.0/libgcc/config/sh/crt1.S gcc-4.7.0-kos/libgcc/config/sh/crt1.S +--- gcc-4.7.0/libgcc/config/sh/crt1.S 2011-11-02 10:33:56.000000000 -0400 ++++ gcc-4.7.0-kos/libgcc/config/sh/crt1.S 2012-06-05 11:21:34.000000000 -0400 +@@ -1,1369 +1,202 @@ +-/* Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2009, 2011 +- Free Software Foundation, Inc. +- This file was pretty much copied from newlib. ++! KallistiOS ##version## ++! ++! startup.s ++! (c)2000-2001 Dan Potter ++! ++! This file must appear FIRST in your linking order, or your program won't ++! work correctly as a raw binary. ++! ++! This is very loosely based on Marcus' crt0.s/startup.s ++! ++ ++.globl start ++.globl _start ++.globl _arch_real_exit ++.globl __arch_old_sr ++.globl __arch_old_vbr ++.globl __arch_old_stack ++.globl __arch_old_fpscr + +-This file is part of GCC. +- +-GCC is free software; you can redistribute it and/or modify it +-under the terms of the GNU General Public License as published by the +-Free Software Foundation; either version 3, or (at your option) any +-later version. +- +-GCC is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-General Public License for more details. +- +-Under Section 7 of GPL version 3, you are granted additional +-permissions described in the GCC Runtime Library Exception, version +-3.1, as published by the Free Software Foundation. +- +-You should have received a copy of the GNU General Public License and +-a copy of the GCC Runtime Library Exception along with this program; +-see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +-<http://www.gnu.org/licenses/>. */ +- +- +-#ifdef MMU_SUPPORT +- /* Section used for exception/timer interrupt stack area */ +- .section .data.vbr.stack,"aw" +- .align 4 +- .global __ST_VBR +-__ST_VBR: +- .zero 1024 * 2 /* ; 2k for VBR handlers */ +-/* Label at the highest stack address where the stack grows from */ +-__timer_stack: +-#endif /* MMU_SUPPORT */ +- +- /* ;---------------------------------------- +- Normal newlib crt1.S */ +- +-#ifdef __SH5__ +- .section .data,"aw" +- .global ___data +-___data: +- +- .section .rodata,"a" +- .global ___rodata +-___rodata: +- +-#define ICCR_BASE 0x01600000 +-#define OCCR_BASE 0x01e00000 +-#define MMUIR_BASE 0x00000000 +-#define MMUDR_BASE 0x00800000 +- +-#define PTE_ENABLED 1 +-#define PTE_DISABLED 0 +- +-#define PTE_SHARED (1 << 1) +-#define PTE_NOT_SHARED 0 +- +-#define PTE_CB_UNCACHEABLE 0 +-#define PTE_CB_DEVICE 1 +-#define PTE_CB_CACHEABLE_WB 2 +-#define PTE_CB_CACHEABLE_WT 3 +- +-#define PTE_SZ_4KB (0 << 3) +-#define PTE_SZ_64KB (1 << 3) +-#define PTE_SZ_1MB (2 << 3) +-#define PTE_SZ_512MB (3 << 3) +- +-#define PTE_PRR (1 << 6) +-#define PTE_PRX (1 << 7) +-#define PTE_PRW (1 << 8) +-#define PTE_PRU (1 << 9) +- +-#define SR_MMU_BIT 31 +-#define SR_BL_BIT 28 +- +-#define ALIGN_4KB (0xfff) +-#define ALIGN_1MB (0xfffff) +-#define ALIGN_512MB (0x1fffffff) +- +-#define DYNACON_BASE 0x0f000000 +-#define DM_CB_DLINK_BASE 0x0c000000 +-#define DM_DB_DLINK_BASE 0x0b000000 +- +-#define FEMI_AREA_0 0x00000000 +-#define FEMI_AREA_1 0x04000000 +-#define FEMI_AREA_2 0x05000000 +-#define FEMI_AREA_3 0x06000000 +-#define FEMI_AREA_4 0x07000000 +-#define FEMI_CB 0x08000000 +- +-#define EMI_BASE 0X80000000 +- +-#define DMA_BASE 0X0e000000 +- +-#define CPU_BASE 0X0d000000 +- +-#define PERIPH_BASE 0X09000000 +-#define DMAC_BASE 0x0e000000 +-#define INTC_BASE 0x0a000000 +-#define CPRC_BASE 0x0a010000 +-#define TMU_BASE 0x0a020000 +-#define SCIF_BASE 0x0a030000 +-#define RTC_BASE 0x0a040000 +- +- +- +-#define LOAD_CONST32(val, reg) \ +- movi ((val) >> 16) & 65535, reg; \ +- shori (val) & 65535, reg +- +-#define LOAD_PTEH_VAL(sym, align, bits, scratch_reg, reg) \ +- LOAD_ADDR (sym, reg); \ +- LOAD_CONST32 ((align), scratch_reg); \ +- andc reg, scratch_reg, reg; \ +- LOAD_CONST32 ((bits), scratch_reg); \ +- or reg, scratch_reg, reg +- +-#define LOAD_PTEL_VAL(sym, align, bits, scratch_reg, reg) \ +- LOAD_ADDR (sym, reg); \ +- LOAD_CONST32 ((align), scratch_reg); \ +- andc reg, scratch_reg, reg; \ +- LOAD_CONST32 ((bits), scratch_reg); \ +- or reg, scratch_reg, reg +- +-#define SET_PTE(pte_addr_reg, pteh_val_reg, ptel_val_reg) \ +- putcfg pte_addr_reg, 0, r63; \ +- putcfg pte_addr_reg, 1, ptel_val_reg; \ +- putcfg pte_addr_reg, 0, pteh_val_reg +- +-#if __SH5__ == 64 +- .section .text,"ax" +-#define LOAD_ADDR(sym, reg) \ +- movi (sym >> 48) & 65535, reg; \ +- shori (sym >> 32) & 65535, reg; \ +- shori (sym >> 16) & 65535, reg; \ +- shori sym & 65535, reg +-#else +- .mode SHmedia +- .section .text..SHmedia32,"ax" +-#define LOAD_ADDR(sym, reg) \ +- movi (sym >> 16) & 65535, reg; \ +- shori sym & 65535, reg +-#endif +- .global start ++_start: + start: +- LOAD_ADDR (_stack, r15) +- +-#ifdef MMU_SUPPORT +- ! Set up the VM using the MMU and caches +- +- ! .vm_ep is first instruction to execute +- ! after VM initialization +- pt/l .vm_ep, tr1 +- +- ! Configure instruction cache (ICCR) +- movi 3, r2 +- movi 0, r3 +- LOAD_ADDR (ICCR_BASE, r1) +- putcfg r1, 0, r2 +- putcfg r1, 1, r3 +- +- ! movi 7, r2 ! write through +- ! Configure operand cache (OCCR) +- LOAD_ADDR (OCCR_BASE, r1) +- putcfg r1, 0, r2 +- putcfg r1, 1, r3 +- +- ! Disable all PTE translations +- LOAD_ADDR (MMUIR_BASE, r1) +- LOAD_ADDR (MMUDR_BASE, r2) +- movi 64, r3 +- pt/l .disable_ptes_loop, tr0 +-.disable_ptes_loop: +- putcfg r1, 0, r63 +- putcfg r2, 0, r63 +- addi r1, 16, r1 +- addi r2, 16, r2 +- addi r3, -1, r3 +- bgt r3, r63, tr0 +- +- LOAD_ADDR (MMUIR_BASE, r1) +- +- ! FEMI instruction mappings +- ! Area 0 - 1Mb cacheable at 0x00000000 +- ! Area 1 - None +- ! Area 2 - 1Mb cacheable at 0x05000000 +- ! - 1Mb cacheable at 0x05100000 +- ! Area 3 - None +- ! Area 4 - None +- +- ! Map a 1Mb page for instructions at 0x00000000 +- LOAD_PTEH_VAL (FEMI_AREA_0, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_AREA_0, ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRX | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1Mb page for instructions at 0x05000000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL (FEMI_AREA_2, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_AREA_2, ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRX | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1Mb page for instructions at 0x05100000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((FEMI_AREA_2+0x100000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((FEMI_AREA_2+0x100000), ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRX | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 512M page for instructions at EMI base +- addi r1, 16, r1 +- LOAD_PTEH_VAL (EMI_BASE, ALIGN_512MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (EMI_BASE, ALIGN_512MB, PTE_CB_CACHEABLE_WB | PTE_SZ_512MB | PTE_PRX | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for instructions at DM_DB_DLINK_BASE +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DM_DB_DLINK_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DM_DB_DLINK_BASE, ALIGN_4KB, PTE_CB_CACHEABLE_WB | PTE_SZ_4KB | PTE_PRX | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- LOAD_ADDR (MMUDR_BASE, r1) +- +- ! FEMI data mappings +- ! Area 0 - 1Mb cacheable at 0x00000000 +- ! Area 1 - 1Mb device at 0x04000000 +- ! Area 2 - 1Mb cacheable at 0x05000000 +- ! - 1Mb cacheable at 0x05100000 +- ! Area 3 - None +- ! Area 4 - None +- ! CB - 1Mb device at 0x08000000 +- +- ! Map a 1Mb page for data at 0x00000000 +- LOAD_PTEH_VAL (FEMI_AREA_0, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_AREA_0, ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1Mb page for data at 0x04000000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL (FEMI_AREA_1, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_AREA_1, ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1Mb page for data at 0x05000000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL (FEMI_AREA_2, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_AREA_2, ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1Mb page for data at 0x05100000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((FEMI_AREA_2+0x100000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((FEMI_AREA_2+0x100000), ALIGN_1MB, PTE_CB_CACHEABLE_WB | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for registers at 0x08000000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL (FEMI_CB, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (FEMI_CB, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 512M page for data at EMI +- addi r1, 16, r1 +- LOAD_PTEH_VAL (EMI_BASE, ALIGN_512MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (EMI_BASE, ALIGN_512MB, PTE_CB_CACHEABLE_WB | PTE_SZ_512MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for DYNACON at DYNACON_BASE +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DYNACON_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DYNACON_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for instructions at DM_DB_DLINK_BASE +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DM_DB_DLINK_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DM_DB_DLINK_BASE, ALIGN_4KB, PTE_CB_CACHEABLE_WB | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for data at DM_DB_DLINK_BASE+0x1000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_DB_DLINK_BASE+0x1000), ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_DB_DLINK_BASE+0x1000), ALIGN_4KB, PTE_CB_UNCACHEABLE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for stack DM_DB_DLINK_BASE+0x2000 +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_DB_DLINK_BASE+0x2000), ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_DB_DLINK_BASE+0x2000), ALIGN_4KB, PTE_CB_CACHEABLE_WB | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1M page for DM_CB_BASE2 at DM_CB_DLINK +- ! 0x0c000000 - 0x0c0fffff +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DM_CB_DLINK_BASE, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DM_CB_DLINK_BASE, ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1M page for DM_CB_BASE2 at DM_CB_DLINK +- ! 0x0c100000 - 0x0c1fffff +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_CB_DLINK_BASE+0x100000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_CB_DLINK_BASE+0x100000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1M page for DM_CB_BASE2 at DM_CB_DLINK +- ! 0x0c200000 - 0x0c2fffff +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_CB_DLINK_BASE+0x200000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_CB_DLINK_BASE+0x200000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1M page for DM_CB_BASE2 at DM_CB_DLINK +- ! 0x0c400000 - 0x0c4fffff +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_CB_DLINK_BASE+0x400000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_CB_DLINK_BASE+0x400000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 1M page for DM_CB_BASE2 at DM_CB_DLINK +- ! 0x0c800000 - 0x0c8fffff +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((DM_CB_DLINK_BASE+0x800000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((DM_CB_DLINK_BASE+0x800000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map a 4K page for DMA control registers +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DMA_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DMA_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map lots of 4K pages for peripherals +- +- ! /* peripheral */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (PERIPH_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (PERIPH_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* dmac */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (DMAC_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (DMAC_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* intc */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (INTC_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (INTC_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* rtc */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (RTC_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (RTC_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* dmac */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (TMU_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (TMU_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* scif */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (SCIF_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (SCIF_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- ! /* cprc */ +- addi r1, 16, r1 +- LOAD_PTEH_VAL (CPRC_BASE, ALIGN_4KB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (CPRC_BASE, ALIGN_4KB, PTE_CB_DEVICE | PTE_SZ_4KB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Map CPU WPC registers +- addi r1, 16, r1 +- LOAD_PTEH_VAL (CPU_BASE, ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL (CPU_BASE, ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- addi r1, 16, r1 +- +- LOAD_PTEH_VAL ((CPU_BASE+0x100000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((CPU_BASE+0x100000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((CPU_BASE+0x200000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((CPU_BASE+0x200000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- addi r1, 16, r1 +- LOAD_PTEH_VAL ((CPU_BASE+0x400000), ALIGN_1MB, PTE_ENABLED | PTE_NOT_SHARED, r25, r2) +- LOAD_PTEL_VAL ((CPU_BASE+0x400000), ALIGN_1MB, PTE_CB_DEVICE | PTE_SZ_1MB | PTE_PRR | PTE_PRW | PTE_PRU, r25, r3) +- SET_PTE (r1, r2, r3) +- +- ! Switch over to virtual addressing and enabled cache +- getcon sr, r1 +- movi 1, r2 +- shlli r2, SR_BL_BIT, r2 +- or r1, r2, r1 +- putcon r1, ssr +- getcon sr, r1 +- movi 1, r2 +- shlli r2, SR_MMU_BIT, r2 +- or r1, r2, r1 +- putcon r1, ssr +- gettr tr1, r1 +- putcon r1, spc +- synco +- rte +- +- ! VM entry point. From now on, we are in VM mode. +-.vm_ep: +- +- ! Install the trap handler, by seeding vbr with the +- ! correct value, and by assigning sr.bl = 0. +- +- LOAD_ADDR (vbr_start, r1) +- putcon r1, vbr +- movi ~(1<<28), r1 +- getcon sr, r2 +- and r1, r2, r2 +- putcon r2, sr +-#endif /* MMU_SUPPORT */ +- +- pt/l .Lzero_bss_loop, tr0 +- pt/l _init, tr5 +- pt/l ___setup_argv_and_call_main, tr6 +- pt/l _exit, tr7 +- +- ! zero out bss +- LOAD_ADDR (_edata, r0) +- LOAD_ADDR (_end, r1) +-.Lzero_bss_loop: +- stx.q r0, r63, r63 +- addi r0, 8, r0 +- bgt/l r1, r0, tr0 +- +- LOAD_ADDR (___data, r26) +- LOAD_ADDR (___rodata, r27) +- +-#ifdef __SH_FPU_ANY__ +- getcon sr, r0 +- ! enable the FP unit, by resetting SR.FD +- ! also zero out SR.FR, SR.SZ and SR.PR, as mandated by the ABI +- movi 0, r1 +- shori 0xf000, r1 +- andc r0, r1, r0 +- putcon r0, sr +-#if __SH5__ == 32 +- pt/l ___set_fpscr, tr0 +- movi 0, r4 +- blink tr0, r18 +-#endif +-#endif +- +- ! arrange for exit to call fini +- pt/l _atexit, tr1 +- LOAD_ADDR (_fini, r2) +- blink tr1, r18 +- +- ! call init +- blink tr5, r18 +- +- ! call the mainline +- blink tr6, r18 +- +- ! call exit +- blink tr7, r18 +- ! We should never return from _exit but in case we do we would enter the +- ! the following tight loop. This avoids executing any data that might follow. +-limbo: +- pt/l limbo, tr0 +- blink tr0, r63 +- +-#ifdef MMU_SUPPORT +- ! All these traps are handled in the same place. +- .balign 256 +-vbr_start: +- pt/l handler, tr0 ! tr0 trashed. +- blink tr0, r63 +- .balign 256 +-vbr_100: +- pt/l handler, tr0 ! tr0 trashed. +- blink tr0, r63 +-vbr_100_end: +- .balign 256 +-vbr_200: +- pt/l handler, tr0 ! tr0 trashed. +- blink tr0, r63 +- .balign 256 +-vbr_300: +- pt/l handler, tr0 ! tr0 trashed. +- blink tr0, r63 +- .balign 256 +-vbr_400: ! Should be at vbr+0x400 +-handler: +- /* If the trap handler is there call it */ +- LOAD_ADDR (__superh_trap_handler, r2) +- pta chandler,tr2 +- beq r2, r63, tr2 /* If zero, ie not present branch around to chandler */ +- /* Now call the trap handler with as much of the context unchanged as possible. +- Move trapping address into R18 to make it look like the trap point */ +- getcon spc, r18 +- pt/l __superh_trap_handler, tr0 +- blink tr0, r7 +-chandler: +- getcon spc, r62 +- getcon expevt, r2 +- pt/l _exit, tr0 +- blink tr0, r63 +- +- /* Simulated trap handler */ +- .section .text..SHmedia32,"ax" +-gcc2_compiled.: +- .section .debug_abbrev +-.Ldebug_abbrev0: +- .section .text..SHmedia32 +-.Ltext0: +- .section .debug_info +-.Ldebug_info0: +- .section .debug_line +-.Ldebug_line0: +- .section .text..SHmedia32,"ax" +- .align 5 +- .global __superh_trap_handler +- .type __superh_trap_handler,@function +-__superh_trap_handler: +-.LFB1: +- ptabs r18, tr0 +- addi.l r15, -8, r15 +- st.l r15, 4, r14 +- addi.l r15, -8, r15 +- add.l r15, r63, r14 +- st.l r14, 0, r2 +- ptabs r7, tr0 +- addi.l r14, 8, r14 +- add.l r14, r63, r15 +- ld.l r15, 4, r14 +- addi.l r15, 8, r15 +- blink tr0, r63 +-.LFE1: +-.Lfe1: +- .size __superh_trap_handler,.Lfe1-__superh_trap_handler +- +- .section .text..SHmedia32 +-.Letext0: +- +- .section .debug_info +- .ualong 0xa7 +- .uaword 0x2 +- .ualong .Ldebug_abbrev0 +- .byte 0x4 +- .byte 0x1 +- .ualong .Ldebug_line0 +- .ualong .Letext0 +- .ualong .Ltext0 +- .string "trap_handler.c" +- +- .string "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" +- +- .string "GNU C 2.97-sh5-010522" +- +- .byte 0x1 +- .byte 0x2 +- .ualong 0x9a +- .byte 0x1 +- .string "_superh_trap_handler" +- +- .byte 0x1 +- .byte 0x2 +- .byte 0x1 +- .ualong .LFB1 +- .ualong .LFE1 +- .byte 0x1 +- .byte 0x5e +- .byte 0x3 +- .string "trap_reason" +- +- .byte 0x1 +- .byte 0x1 +- .ualong 0x9a +- .byte 0x2 +- .byte 0x91 +- .byte 0x0 +- .byte 0x0 +- .byte 0x4 +- .string "unsigned int" +- +- .byte 0x4 +- .byte 0x7 +- .byte 0x0 +- +- .section .debug_abbrev +- .byte 0x1 +- .byte 0x11 +- .byte 0x1 +- .byte 0x10 +- .byte 0x6 +- .byte 0x12 +- .byte 0x1 +- .byte 0x11 +- .byte 0x1 +- .byte 0x3 +- .byte 0x8 +- .byte 0x1b +- .byte 0x8 +- .byte 0x25 +- .byte 0x8 +- .byte 0x13 +- .byte 0xb +- .byte 0,0 +- .byte 0x2 +- .byte 0x2e +- .byte 0x1 +- .byte 0x1 +- .byte 0x13 +- .byte 0x3f +- .byte 0xc +- .byte 0x3 +- .byte 0x8 +- .byte 0x3a +- .byte 0xb +- .byte 0x3b +- .byte 0xb +- .byte 0x27 +- .byte 0xc +- .byte 0x11 +- .byte 0x1 +- .byte 0x12 +- .byte 0x1 +- .byte 0x40 +- .byte 0xa +- .byte 0,0 +- .byte 0x3 +- .byte 0x5 +- .byte 0x0 +- .byte 0x3 +- .byte 0x8 +- .byte 0x3a +- .byte 0xb +- .byte 0x3b +- .byte 0xb +- .byte 0x49 +- .byte 0x13 +- .byte 0x2 +- .byte 0xa +- .byte 0,0 +- .byte 0x4 +- .byte 0x24 +- .byte 0x0 +- .byte 0x3 +- .byte 0x8 +- .byte 0xb +- .byte 0xb +- .byte 0x3e +- .byte 0xb +- .byte 0,0 +- .byte 0 +- +- .section .debug_pubnames +- .ualong 0x27 +- .uaword 0x2 +- .ualong .Ldebug_info0 +- .ualong 0xab +- .ualong 0x5b +- .string "_superh_trap_handler" +- +- .ualong 0x0 +- +- .section .debug_aranges +- .ualong 0x1c +- .uaword 0x2 +- .ualong .Ldebug_info0 +- .byte 0x4 +- .byte 0x0 +- .uaword 0x0,0 +- .ualong .Ltext0 +- .ualong .Letext0-.Ltext0 +- .ualong 0x0 +- .ualong 0x0 +- .ident "GCC: (GNU) 2.97-sh5-010522" +-#endif /* MMU_SUPPORT */ +-#else /* ! __SH5__ */ +- +- ! make a place to keep any previous value of the vbr register +- ! this will only have a value if it has been set by redboot (for example) +- .section .bss +-old_vbr: +- .long 0 +-#ifdef PROFILE +-profiling_enabled: +- .long 0 +-#endif +- +- +- .section .text +- .global start +- .import ___rtos_profiler_start_timer +- .weak ___rtos_profiler_start_timer +-start: +- mov.l stack_k,r15 +- +-#if defined (__SH3__) || (defined (__SH_FPU_ANY__) && ! defined (__SH2A__)) || defined (__SH4_NOFPU__) +-#define VBR_SETUP +- ! before zeroing the bss ... +- ! if the vbr is already set to vbr_start then the program has been restarted +- ! (i.e. it is not the first time the program has been run since reset) +- ! reset the vbr to its old value before old_vbr (in bss) is wiped +- ! this ensures that the later code does not create a circular vbr chain +- stc vbr, r1 +- mov.l vbr_start_k, r2 +- cmp/eq r1, r2 +- bf 0f +- ! reset the old vbr value +- mov.l old_vbr_k, r1 +- mov.l @r1, r2 +- ldc r2, vbr +-0: +-#endif /* VBR_SETUP */ +- +- ! zero out bss +- mov.l edata_k,r0 +- mov.l end_k,r1 +- mov #0,r2 +-start_l: +- mov.l r2,@r0 +- add #4,r0 +- cmp/ge r0,r1 +- bt start_l +- +-#if defined (__SH_FPU_ANY__) +- mov.l set_fpscr_k, r1 +- mov #4,r4 +- jsr @r1 +- shll16 r4 ! Set DN bit (flush denormal inputs to zero) +- lds r3,fpscr ! Switch to default precision +-#endif /* defined (__SH_FPU_ANY__) */ +- +-#ifdef VBR_SETUP +- ! save the existing contents of the vbr +- ! there will only be a prior value when using something like redboot +- ! otherwise it will be zero +- stc vbr, r1 +- mov.l old_vbr_k, r2 +- mov.l r1, @r2 +- ! setup vbr +- mov.l vbr_start_k, r1 +- ldc r1,vbr +-#endif /* VBR_SETUP */ +- +- ! if an rtos is exporting a timer start fn, +- ! then pick up an SR which does not enable ints +- ! (the rtos will take care of this) +- mov.l rtos_start_fn, r0 +- mov.l sr_initial_bare, r1 +- tst r0, r0 +- bt set_sr +- +- mov.l sr_initial_rtos, r1 +- +-set_sr: +- ! Set status register (sr) +- ldc r1, sr +- +- ! arrange for exit to call fini +- mov.l atexit_k,r0 +- mov.l fini_k,r4 +- jsr @r0 ++ ! Disable interrupts (if they're enabled) ++ mov.l old_sr_addr,r0 ++ stc sr,r1 ++ mov.l r1,@r0 ++ mov.l init_sr,r0 ++ ldc r0,sr ++ ++ ! Run in the P2 area ++ mov.l setup_cache_addr,r0 ++ mov.l p2_mask,r1 ++ or r1,r0 ++ jmp @r0 + nop + +-#ifdef PROFILE +- ! arrange for exit to call _mcleanup (via stop_profiling) +- mova stop_profiling,r0 +- mov.l atexit_k,r1 +- jsr @r1 +- mov r0, r4 +- +- ! Call profiler startup code +- mov.l monstartup_k, r0 +- mov.l start_k, r4 +- mov.l etext_k, r5 +- jsr @r0 ++setup_cache: ++ ! Now that we are in P2, it's safe to enable the cache ++ ! Check to see if we should enable OCRAM. ++ mov.l kos_init_flags_addr, r0 ++ add #2, r0 ++ mov.w @r0, r0 ++ tst #1, r0 ++ bf .L_setup_cache_L0 ++ mov.w ccr_data,r1 ++ bra .L_setup_cache_L1 ++ nop ++.L_setup_cache_L0: ++ mov.w ccr_data_ocram,r1 ++.L_setup_cache_L1: ++ mov.l ccr_addr,r0 ++ mov.l r1,@r0 ++ ++ ! After changing CCR, eight instructions must be executed before ++ ! it's safe to enter a cached area such as P1 ++ nop ! 1 ++ nop ! 2 ++ nop ! 3 ++ nop ! 4 ++ nop ! 5 (d-cache now safe) ++ nop ! 6 ++ mov.l init_addr,r0 ! 7 ++ mov #0,r1 ! 8 ++ jmp @r0 ! go ++ mov r1,r0 + nop + +- ! enable profiling trap +- ! until now any trap 33s will have been ignored +- ! This means that all library functions called before this point +- ! (directly or indirectly) may have the profiling trap at the start. +- ! Therefore, only mcount itself may not have the extra header. +- mov.l profiling_enabled_k2, r0 +- mov #1, r1 +- mov.l r1, @r0 +-#endif /* PROFILE */ ++init: ++ ! Save old PR on old stack so we can get to it later ++ sts.l pr,@-r15 + +- ! call init +- mov.l init_k,r0 +- jsr @r0 +- nop ++ ! Save the current stack, and set a new stack (higher up in RAM) ++ mov.l old_stack_addr,r0 ++ mov.l r15,@r0 ++ mov.l new_stack,r15 ++ ++ ! Save VBR ++ mov.l old_vbr_addr,r0 ++ stc vbr,r1 ++ mov.l r1,@r0 + +- ! call the mainline +- mov.l main_k,r0 ++#if defined (__SH_FPU_ANY__) ++ ! Save FPSCR ++ mov.l old_fpscr_addr,r0 ++ sts fpscr,r1 ++ mov.l r1,@r0 ++ ++ ! Reset FPSCR ++ mov #4,r4 ! Use 00040000 (DN=1) ++ mov.l fpscr_addr,r0 + jsr @r0 +- nop ++ shll16 r4 ++#endif + +- ! call exit +- mov r0,r4 +- mov.l exit_k,r0 +- jsr @r0 +- nop +- +- .balign 4 +-#ifdef PROFILE +-stop_profiling: +- # stop mcount counting +- mov.l profiling_enabled_k2, r0 +- mov #0, r1 +- mov.l r1, @r0 ++ ! Setup a sentinel value for frame pointer in case we're using ++ ! FRAME_POINTERS for stack tracing. ++ mov #-1,r14 + +- # call mcleanup +- mov.l mcleanup_k, r0 +- jmp @r0 ++ ! Jump to the kernel main ++ mov.l main_addr,r0 ++ jsr @r0 + nop +- +- .balign 4 +-mcleanup_k: +- .long __mcleanup +-monstartup_k: +- .long ___monstartup +-profiling_enabled_k2: +- .long profiling_enabled +-start_k: +- .long _start +-etext_k: +- .long __etext +-#endif /* PROFILE */ +- +- .align 2 +-#if defined (__SH_FPU_ANY__) +-set_fpscr_k: +- .long ___set_fpscr +-#endif /* defined (__SH_FPU_ANY__) */ + +-stack_k: +- .long _stack +-edata_k: +- .long _edata +-end_k: +- .long _end +-main_k: +- .long ___setup_argv_and_call_main +-exit_k: +- .long _exit +-atexit_k: +- .long _atexit +-init_k: +- .long _init +-fini_k: +- .long _fini +-#ifdef VBR_SETUP +-old_vbr_k: +- .long old_vbr +-vbr_start_k: +- .long vbr_start +-#endif /* VBR_SETUP */ +- +-sr_initial_rtos: +- ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. +- ! Whether profiling or not, keep interrupts masked, +- ! the RTOS will enable these if required. +- .long 0x600000f1 ++ ! Program can return here (not likely) or jump here directly ++ ! from anywhere in it to go straight back to the monitor ++_arch_real_exit: ++ ! Reset SR ++ mov.l old_sr,r0 ++ ldc r0,sr ++ ++ ! Disable MMU, invalidate TLB ++ mov #4,r0 ++ mov.l mmu_addr,r1 ++ mov.l r0,@r1 ++ ++ ! Wait (just in case) ++ nop ! 1 ++ nop ! 2 ++ nop ! 3 ++ nop ! 4 ++ nop ! 5 ++ nop ! 6 ++ nop ! 7 ++ nop ! 8 ++ ++ ! Restore VBR ++ mov.l old_vbr,r0 ++ ldc r0,vbr + +-rtos_start_fn: +- .long ___rtos_profiler_start_timer +- +-#ifdef PROFILE +-sr_initial_bare: +- ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. +- ! For bare machine, we need to enable interrupts to get profiling working +- .long 0x60000001 +-#else ++ ! If we're working under dcload, call its EXIT syscall ++ mov.l dcload_magic_addr,r0 ++ mov.l @r0,r0 ++ mov.l dcload_magic_value,r1 ++ cmp/eq r0,r1 ++ bf normal_exit + +-sr_initial_bare: +- ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. +- ! Keep interrupts disabled - the application will enable as required. +- .long 0x600000f1 +-#endif ++ mov.l dcload_syscall,r0 ++ mov.l @r0,r0 ++ jsr @r0 ++ mov #15,r4 + +- ! supplied for backward compatibility only, in case of linking +- ! code whose main() was compiled with an older version of GCC. +- .global ___main +-___main: ++ ! Set back the stack and return (presumably to a serial debug) ++normal_exit: ++ mov.l old_stack,r15 ++ lds.l @r15+,pr + rts + nop +-#ifdef VBR_SETUP +-! Exception handlers +- .section .text.vbr, "ax" +-vbr_start: +- +- .org 0x100 +-vbr_100: +-#ifdef PROFILE +- ! Note on register usage. +- ! we use r0..r3 as scratch in this code. If we are here due to a trapa for profiling +- ! then this is OK as we are just before executing any function code. +- ! The other r4..r7 we save explicityl on the stack +- ! Remaining registers are saved by normal ABI conventions and we assert we do not +- ! use floating point registers. +- mov.l expevt_k1, r1 +- mov.l @r1, r1 +- mov.l event_mask, r0 +- and r0,r1 +- mov.l trapcode_k, r2 +- cmp/eq r1,r2 +- bt 1f +- bra handler_100 ! if not a trapa, go to default handler +- nop +-1: +- mov.l trapa_k, r0 +- mov.l @r0, r0 +- shlr2 r0 ! trapa code is shifted by 2. +- cmp/eq #33, r0 +- bt 2f +- bra handler_100 +- nop +-2: +- +- ! If here then it looks like we have trap #33 +- ! Now we need to call mcount with the following convention +- ! Save and restore r4..r7 +- mov.l r4,@-r15 +- mov.l r5,@-r15 +- mov.l r6,@-r15 +- mov.l r7,@-r15 +- sts.l pr,@-r15 + +- ! r4 is frompc. +- ! r5 is selfpc +- ! r0 is the branch back address. +- ! The code sequence emitted by gcc for the profiling trap is +- ! .align 2 +- ! trapa #33 +- ! .align 2 +- ! .long lab Where lab is planted by the compiler. This is the address +- ! of a datum that needs to be incremented. +- sts pr, r4 ! frompc +- stc spc, r5 ! selfpc +- mov #2, r2 +- not r2, r2 ! pattern to align to 4 +- and r2, r5 ! r5 now has aligned address +-! add #4, r5 ! r5 now has address of address +- mov r5, r2 ! Remember it. +-! mov.l @r5, r5 ! r5 has value of lable (lab in above example) +- add #8, r2 +- ldc r2, spc ! our return address avoiding address word +- +- ! only call mcount if profiling is enabled +- mov.l profiling_enabled_k, r0 +- mov.l @r0, r0 +- cmp/eq #0, r0 +- bt 3f +- ! call mcount +- mov.l mcount_k, r2 +- jsr @r2 +- nop +-3: +- lds.l @r15+,pr +- mov.l @r15+,r7 +- mov.l @r15+,r6 +- mov.l @r15+,r5 +- mov.l @r15+,r4 +- rte +- nop +- .balign 4 +-event_mask: +- .long 0xfff +-trapcode_k: +- .long 0x160 +-expevt_k1: +- .long 0xff000024 ! Address of expevt +-trapa_k: +- .long 0xff000020 +-mcount_k: +- .long __call_mcount +-profiling_enabled_k: +- .long profiling_enabled +-#endif +- ! Non profiling case. +-handler_100: +- mov.l 2f, r0 ! load the old vbr setting (if any) +- mov.l @r0, r0 +- cmp/eq #0, r0 +- bf 1f +- ! no previous vbr - jump to own generic handler +- bra handler +- nop +-1: ! there was a previous handler - chain them +- add #0x7f, r0 ! 0x7f +- add #0x7f, r0 ! 0xfe +- add #0x2, r0 ! add 0x100 without corrupting another register +- jmp @r0 +- nop +- .balign 4 +-2: +- .long old_vbr +- +- .org 0x400 +-vbr_400: ! Should be at vbr+0x400 +- mov.l 2f, r0 ! load the old vbr setting (if any) +- mov.l @r0, r0 +- cmp/eq #0, r0 +- ! no previous vbr - jump to own generic handler +- bt handler +- ! there was a previous handler - chain them +- rotcr r0 +- rotcr r0 +- add #0x7f, r0 ! 0x1fc +- add #0x7f, r0 ! 0x3f8 +- add #0x02, r0 ! 0x400 +- rotcl r0 +- rotcl r0 ! Add 0x400 without corrupting another register +- jmp @r0 +- nop +- .balign 4 +-2: +- .long old_vbr +-handler: +- /* If the trap handler is there call it */ +- mov.l superh_trap_handler_k, r0 +- cmp/eq #0, r0 ! True if zero. +- bf 3f +- bra chandler +- nop +-3: +- ! Here handler available, call it. +- /* Now call the trap handler with as much of the context unchanged as possible. +- Move trapping address into PR to make it look like the trap point */ +- stc spc, r1 +- lds r1, pr +- mov.l expevt_k, r4 +- mov.l @r4, r4 ! r4 is value of expevt, first parameter. +- mov r1, r5 ! Remember trapping pc. +- mov r1, r6 ! Remember trapping pc. +- mov.l chandler_k, r1 +- mov.l superh_trap_handler_k, r2 +- ! jmp to trap handler to avoid disturbing pr. +- jmp @r2 +- nop ++! Misc variables ++ .align 2 ++dcload_magic_addr: ++ .long 0x8c004004 ++dcload_magic_value: ++ .long 0xdeadbeef ++dcload_syscall: ++ .long 0x8c004008 ++__arch_old_sr: ++old_sr: ++ .long 0 ++__arch_old_vbr: ++old_vbr: ++ .long 0 ++__arch_old_fpscr: ++old_fpscr: ++ .long 0 ++init_sr: ++ .long 0x500000f0 ++old_sr_addr: ++ .long old_sr ++old_vbr_addr: ++ .long old_vbr ++old_fpscr_addr: ++ .long old_fpscr ++old_stack_addr: ++ .long old_stack ++__arch_old_stack: ++old_stack: ++ .long 0 ++new_stack: ++ .long 0x8d000000 ++p2_mask: ++ .long 0xa0000000 ++setup_cache_addr: ++ .long setup_cache ++init_addr: ++ .long init ++main_addr: ++ .long _arch_main ++mmu_addr: ++ .long 0xff000010 ++kos_init_flags_addr: ++ .long ___kos_init_flags ++ccr_addr: ++ .long 0xff00001c ++ccr_data: ++ .word 0x090d ++ccr_data_ocram: ++ .word 0x092d + +- .org 0x600 +-vbr_600: +-#ifdef PROFILE +- ! Should be at vbr+0x600 +- ! Now we are in the land of interrupts so need to save more state. +- ! Save register state +- mov.l interrupt_stack_k, r15 ! r15 has been saved to sgr. +- mov.l r0,@-r15 +- mov.l r1,@-r15 +- mov.l r2,@-r15 +- mov.l r3,@-r15 +- mov.l r4,@-r15 +- mov.l r5,@-r15 +- mov.l r6,@-r15 +- mov.l r7,@-r15 +- sts.l pr,@-r15 +- sts.l mach,@-r15 +- sts.l macl,@-r15 +-#if defined(__SH_FPU_ANY__) +- ! Save fpul and fpscr, save fr0-fr7 in 64 bit mode +- ! and set the pervading precision for the timer_handler +- mov #0,r0 +- sts.l fpul,@-r15 +- sts.l fpscr,@-r15 +- lds r0,fpscr ! Clear fpscr +- fmov fr0,@-r15 +- fmov fr1,@-r15 +- fmov fr2,@-r15 +- fmov fr3,@-r15 +- mov.l pervading_precision_k,r0 +- fmov fr4,@-r15 +- fmov fr5,@-r15 +- mov.l @r0,r0 +- fmov fr6,@-r15 +- fmov fr7,@-r15 +- lds r0,fpscr +-#endif /* __SH_FPU_ANY__ */ +- ! Pass interrupted pc to timer_handler as first parameter (r4). +- stc spc, r4 +- mov.l timer_handler_k, r0 +- jsr @r0 +- nop +-#if defined(__SH_FPU_ANY__) +- mov #0,r0 +- lds r0,fpscr ! Clear the fpscr +- fmov @r15+,fr7 +- fmov @r15+,fr6 +- fmov @r15+,fr5 +- fmov @r15+,fr4 +- fmov @r15+,fr3 +- fmov @r15+,fr2 +- fmov @r15+,fr1 +- fmov @r15+,fr0 +- lds.l @r15+,fpscr +- lds.l @r15+,fpul +-#endif /* __SH_FPU_ANY__ */ +- lds.l @r15+,macl +- lds.l @r15+,mach +- lds.l @r15+,pr +- mov.l @r15+,r7 +- mov.l @r15+,r6 +- mov.l @r15+,r5 +- mov.l @r15+,r4 +- mov.l @r15+,r3 +- mov.l @r15+,r2 +- mov.l @r15+,r1 +- mov.l @r15+,r0 +- stc sgr, r15 ! Restore r15, destroyed by this sequence. +- rte +- nop +-#if defined(__SH_FPU_ANY__) +- .balign 4 +-pervading_precision_k: +-#define CONCAT1(A,B) A##B +-#define CONCAT(A,B) CONCAT1(A,B) +- .long CONCAT(__USER_LABEL_PREFIX__,__fpscr_values)+4 +-#endif +-#else +- mov.l 2f, r0 ! Load the old vbr setting (if any). +- mov.l @r0, r0 +- cmp/eq #0, r0 +- ! no previous vbr - jump to own handler +- bt chandler +- ! there was a previous handler - chain them +- rotcr r0 +- rotcr r0 +- add #0x7f, r0 ! 0x1fc +- add #0x7f, r0 ! 0x3f8 +- add #0x7f, r0 ! 0x5f4 +- add #0x03, r0 ! 0x600 +- rotcl r0 +- rotcl r0 ! Add 0x600 without corrupting another register +- jmp @r0 +- nop +- .balign 4 +-2: +- .long old_vbr +-#endif /* PROFILE code */ +-chandler: +- mov.l expevt_k, r4 +- mov.l @r4, r4 ! r4 is value of expevt hence making this the return code +- mov.l handler_exit_k,r0 +- jsr @r0 +- nop +- ! We should never return from _exit but in case we do we would enter the +- ! the following tight loop +-limbo: +- bra limbo +- nop +- .balign 4 +-#ifdef PROFILE +-interrupt_stack_k: +- .long __timer_stack ! The high end of the stack +-timer_handler_k: +- .long __profil_counter ++#if defined (__SH_FPU_ANY__) ++fpscr_addr: ++ .long ___set_fpscr ! in libgcc + #endif +-expevt_k: +- .long 0xff000024 ! Address of expevt +-chandler_k: +- .long chandler +-superh_trap_handler_k: +- .long __superh_trap_handler +-handler_exit_k: +- .long _exit +- .align 2 +-! Simulated compile of trap handler. +- .section .debug_abbrev,"",@progbits +-.Ldebug_abbrev0: +- .section .debug_info,"",@progbits +-.Ldebug_info0: +- .section .debug_line,"",@progbits +-.Ldebug_line0: +- .text +-.Ltext0: +- .align 5 +- .type __superh_trap_handler,@function +-__superh_trap_handler: +-.LFB1: +- mov.l r14,@-r15 +-.LCFI0: +- add #-4,r15 +-.LCFI1: +- mov r15,r14 +-.LCFI2: +- mov.l r4,@r14 +- lds r1, pr +- add #4,r14 +- mov r14,r15 +- mov.l @r15+,r14 +- rts +- nop +-.LFE1: +-.Lfe1: +- .size __superh_trap_handler,.Lfe1-__superh_trap_handler +- .section .debug_frame,"",@progbits +-.Lframe0: +- .ualong .LECIE0-.LSCIE0 +-.LSCIE0: +- .ualong 0xffffffff +- .byte 0x1 +- .string "" +- .uleb128 0x1 +- .sleb128 -4 +- .byte 0x11 +- .byte 0xc +- .uleb128 0xf +- .uleb128 0x0 +- .align 2 +-.LECIE0: +-.LSFDE0: +- .ualong .LEFDE0-.LASFDE0 +-.LASFDE0: +- .ualong .Lframe0 +- .ualong .LFB1 +- .ualong .LFE1-.LFB1 +- .byte 0x4 +- .ualong .LCFI0-.LFB1 +- .byte 0xe +- .uleb128 0x4 +- .byte 0x4 +- .ualong .LCFI1-.LCFI0 +- .byte 0xe +- .uleb128 0x8 +- .byte 0x8e +- .uleb128 0x1 +- .byte 0x4 +- .ualong .LCFI2-.LCFI1 +- .byte 0xd +- .uleb128 0xe +- .align 2 +-.LEFDE0: +- .text +-.Letext0: +- .section .debug_info +- .ualong 0xb3 +- .uaword 0x2 +- .ualong .Ldebug_abbrev0 +- .byte 0x4 +- .uleb128 0x1 +- .ualong .Ldebug_line0 +- .ualong .Letext0 +- .ualong .Ltext0 +- .string "trap_handler.c" +- .string "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" +- .string "GNU C 3.2 20020529 (experimental)" +- .byte 0x1 +- .uleb128 0x2 +- .ualong 0xa6 +- .byte 0x1 +- .string "_superh_trap_handler" +- .byte 0x1 +- .byte 0x2 +- .byte 0x1 +- .ualong .LFB1 +- .ualong .LFE1 +- .byte 0x1 +- .byte 0x5e +- .uleb128 0x3 +- .string "trap_reason" +- .byte 0x1 +- .byte 0x1 +- .ualong 0xa6 +- .byte 0x2 +- .byte 0x91 +- .sleb128 0 +- .byte 0x0 +- .uleb128 0x4 +- .string "unsigned int" +- .byte 0x4 +- .byte 0x7 +- .byte 0x0 +- .section .debug_abbrev +- .uleb128 0x1 +- .uleb128 0x11 +- .byte 0x1 +- .uleb128 0x10 +- .uleb128 0x6 +- .uleb128 0x12 +- .uleb128 0x1 +- .uleb128 0x11 +- .uleb128 0x1 +- .uleb128 0x3 +- .uleb128 0x8 +- .uleb128 0x1b +- .uleb128 0x8 +- .uleb128 0x25 +- .uleb128 0x8 +- .uleb128 0x13 +- .uleb128 0xb +- .byte 0x0 +- .byte 0x0 +- .uleb128 0x2 +- .uleb128 0x2e +- .byte 0x1 +- .uleb128 0x1 +- .uleb128 0x13 +- .uleb128 0x3f +- .uleb128 0xc +- .uleb128 0x3 +- .uleb128 0x8 +- .uleb128 0x3a +- .uleb128 0xb +- .uleb128 0x3b +- .uleb128 0xb +- .uleb128 0x27 +- .uleb128 0xc +- .uleb128 0x11 +- .uleb128 0x1 +- .uleb128 0x12 +- .uleb128 0x1 +- .uleb128 0x40 +- .uleb128 0xa +- .byte 0x0 +- .byte 0x0 +- .uleb128 0x3 +- .uleb128 0x5 +- .byte 0x0 +- .uleb128 0x3 +- .uleb128 0x8 +- .uleb128 0x3a +- .uleb128 0xb +- .uleb128 0x3b +- .uleb128 0xb +- .uleb128 0x49 +- .uleb128 0x13 +- .uleb128 0x2 +- .uleb128 0xa +- .byte 0x0 +- .byte 0x0 +- .uleb128 0x4 +- .uleb128 0x24 +- .byte 0x0 +- .uleb128 0x3 +- .uleb128 0x8 +- .uleb128 0xb +- .uleb128 0xb +- .uleb128 0x3e +- .uleb128 0xb +- .byte 0x0 +- .byte 0x0 +- .byte 0x0 +- .section .debug_pubnames,"",@progbits +- .ualong 0x27 +- .uaword 0x2 +- .ualong .Ldebug_info0 +- .ualong 0xb7 +- .ualong 0x67 +- .string "_superh_trap_handler" +- .ualong 0x0 +- .section .debug_aranges,"",@progbits +- .ualong 0x1c +- .uaword 0x2 +- .ualong .Ldebug_info0 +- .byte 0x4 +- .byte 0x0 +- .uaword 0x0 +- .uaword 0x0 +- .ualong .Ltext0 +- .ualong .Letext0-.Ltext0 +- .ualong 0x0 +- .ualong 0x0 +-#endif /* VBR_SETUP */ +-#endif /* ! __SH5__ */ +diff -ruN gcc-4.7.0/libgcc/config/sh/gthr-kos.h gcc-4.7.0-kos/libgcc/config/sh/gthr-kos.h +--- gcc-4.7.0/libgcc/config/sh/gthr-kos.h 1969-12-31 19:00:00.000000000 -0500 ++++ gcc-4.7.0-kos/libgcc/config/sh/gthr-kos.h 2012-06-05 11:03:08.000000000 -0400 +@@ -0,0 +1,374 @@ ++/* Copyright (C) 2009, 2010, 2011 Lawrence Sebald */ ++ ++/* Threads compatibility routines for libgcc2 and libobjc. */ ++/* Compile this one with gcc. */ ++/* Copyright (C) 1997, 1999, 2000, 2004, 2008, 2009 ++ Free Software Foundation, Inc. ++ ++This file is part of GCC. ++ ++GCC is free software; you can redistribute it and/or modify it under ++the terms of the GNU General Public License as published by the Free ++Software Foundation; either version 3, or (at your option) any later ++version. ++ ++GCC is distributed in the hope that it will be useful, but WITHOUT ANY ++WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++for more details. ++ ++Under Section 7 of GPL version 3, you are granted additional ++permissions described in the GCC Runtime Library Exception, version ++3.1, as published by the Free Software Foundation. ++ ++You should have received a copy of the GNU General Public License and ++a copy of the GCC Runtime Library Exception along with this program; ++see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ++<http://www.gnu.org/licenses/>. */ ++ ++#ifndef GCC_GTHR_KOS_H ++#define GCC_GTHR_KOS_H ++ ++/* KallistiOS threads specific definitions. */ ++ ++#define __GTHREADS 1 ++#define __GTHREADS_CXX0X 1 ++#define __GTHREAD_HAS_COND 1 ++ ++#include <kos/thread.h> ++#include <kos/tls.h> ++#include <kos/mutex.h> ++#include <kos/recursive_lock.h> ++#include <kos/once.h> ++#include <kos/cond.h> ++#include <time.h> ++ ++/* These should work just fine. */ ++typedef kthread_key_t __gthread_key_t; ++typedef kthread_once_t __gthread_once_t; ++typedef mutex_t * __gthread_mutex_t; ++typedef condvar_t * __gthread_cond_t; ++typedef kthread_t * __gthread_t; ++typedef struct timespec __gthread_time_t; ++ ++typedef struct { ++ recursive_lock_t *koslock; ++} __gthread_recursive_mutex_t; ++ ++static void __gthr_mutex_init(__gthread_mutex_t *__mutex) { ++ *__mutex = mutex_create(); ++} ++ ++static void __gthr_recursive_mutex_init(__gthread_recursive_mutex_t *__mutex) { ++ __mutex->koslock = rlock_create(); ++} ++ ++static void __gthr_cond_init(__gthread_cond_t *__cond) { ++ *__cond = cond_create(); ++} ++ ++#define __GTHREAD_ONCE_INIT KTHREAD_ONCE_INIT ++#define __GTHREAD_MUTEX_INIT_FUNCTION __gthr_mutex_init ++#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthr_recursive_mutex_init ++#define __GTHREAD_COND_INIT_FUNCTION __gthr_cond_init ++ ++static inline int __gthread_active_p(void) { ++ return 1; ++} ++ ++#ifdef _LIBOBJC ++ ++/* This stuff only applies to Objective C. */ ++ ++/* The config.h file in libobjc/ */ ++#include <config.h> ++ ++/* Key structure for maintaining thread specific storage */ ++static kthread_key_t _objc_thread_storage; ++ ++/* Backend initialization funcitons */ ++ ++/* Initialize the threads subsystem. */ ++static inline int __gthread_objc_init_thread_system(void) { ++ /* The only thing we have to do is to initialize the storage key. */ ++ return kthread_key_create(&_objc_thread_storage, NULL); ++} ++ ++/* Close the threads subsystem. */ ++static inline int __gthread_objc_close_thread_system(void) { ++ return kthread_key_delete(_objc_thread_storage); ++} ++ ++/* Backend thread functions */ ++ ++/* Create a new thread of execution. */ ++static inline objc_thread_t __gthread_objc_thread_detach(void (*func)(void *), ++ void *arg) { ++ kthread_t *thd_hnd; ++ ++ thd_hnd = thd_create(1, (void *)(void *)func, arg); ++ return (objc_thread_t)thd_hnd; ++} ++ ++/* Set the current thread's priority. */ ++static inline int __gthread_objc_thread_set_priority(int priority __attribute__((unused))) { ++ /* XXXX */ ++ return -1; ++} ++ ++/* Return the current thread's priority. */ ++static inline int __gthread_objc_thread_get_priority(void) { ++ /* XXXX */ ++ return OBJC_THREAD_INTERACTIVE_PRIORITY; ++} ++ ++/* Yield our process time to another thread. */ ++static inline void __gthread_objc_thread_yield(void) { ++ thd_pass(); ++} ++ ++/* Terminate the current thread. */ ++static inline int __gthread_objc_thread_exit(void) { ++ thd_exit(NULL); ++ ++ /* Failed if we reached here */ ++ return -1; ++} ++ ++/* Returns an integer value which uniquely describes a thread. */ ++static inline objc_thread_t __gthread_objc_thread_id(void) { ++ return (objc_thread_t)thd_get_current(); ++} ++ ++/* Sets the thread's local storage pointer. */ ++static inline int __gthread_objc_thread_set_data(void *value) { ++ return kthread_setspecific(_objc_thread_storage, value); ++} ++ ++/* Returns the thread's local storage pointer. */ ++static inline void *__gthread_objc_thread_get_data(void) { ++ return kthread_getspecific(_objc_thread_storage); ++} ++ ++/* Backend mutex functions */ ++ ++/* Allocate a mutex. */ ++static inline int __gthread_objc_mutex_allocate(objc_mutex_t mutex) { ++ mutex_t *m = mutex_create(); ++ ++ if(m) { ++ mutex->backend = (void *)m; ++ return 0; ++ } ++ ++ mutex->backend = NULL; ++ return -1; ++} ++ ++/* Deallocate a mutex. */ ++static inline int __gthread_objc_mutex_deallocate(objc_mutex_t mutex) { ++ mutex_t *m = (mutex_t *)mutex->backend; ++ ++ if(mutex_is_locked(m)) { ++ mutex_unlock(m); ++ } ++ ++ mutex_destroy(m); ++ mutex->backend = NULL; ++ ++ return 0; ++} ++ ++/* Grab a lock on a mutex. */ ++static inline int __gthread_objc_mutex_lock(objc_mutex_t mutex) { ++ return mutex_lock((mutex_t *)mutex->backend); ++} ++ ++/* Try to grab a lock on a mutex. */ ++static inline int __gthread_objc_mutex_trylock(objc_mutex_t mutex) { ++ return mutex_trylock((mutex_t *)mutex->backend); ++} ++ ++/* Unlock the mutex. */ ++static inline int __gthread_objc_mutex_unlock(objc_mutex_t mutex) { ++ mutex_unlock((mutex_t *)mutex->backend); ++ return 0; ++} ++ ++/* Backend condition mutex functions */ ++ ++/* Allocate a condition. */ ++static inline int __gthread_objc_condition_allocate(objc_condition_t cond) { ++ condvar_t *c = cond_create(); ++ ++ if(c) { ++ cond->backend = (void *)c; ++ return 0; ++ } ++ ++ cond->backend = NULL; ++ return -1; ++} ++ ++/* Deallocate a condition. */ ++static inline int __gthread_objc_condition_deallocate(objc_condition_t cond) { ++ cond_destroy((condvar_t *)cond->backend); ++ cond->backend = NULL; ++ return 0; ++} ++ ++/* Wait on the condition. */ ++static inline int __gthread_objc_condition_wait(objc_condition_t cond, ++ objc_mutex_t mutex) { ++ return cond_wait((condvar_t *)cond->backend, (mutex_t *)mutex->backend); ++} ++ ++/* Wake up all threads waiting on this condition. */ ++static inline int __gthread_objc_condition_broadcast(objc_condition_t cond) { ++ cond_broadcast((condvar_t *)cond->backend); ++ return 0; ++} ++ ++/* Wake up one thread waiting on this condition. */ ++static inline int __gthread_objc_condition_signal(objc_condition_t cond) { ++ cond_signal((condvar_t *)cond->backend); ++ return 0; ++} ++ ++#else /* _LIBOBJC */ ++ ++static inline int __gthread_once(__gthread_once_t *__once, ++ void (*__func)(void)) { ++ return kthread_once(__once, __func); ++} ++ ++static inline int __gthread_key_create(__gthread_key_t *__key, ++ void (*__func)(void *)) { ++ return kthread_key_create(__key, __func); ++} ++ ++static int __gthread_key_delete(__gthread_key_t __key) { ++ return kthread_key_delete(__key); ++} ++ ++static inline void *__gthread_getspecific(__gthread_key_t __key) { ++ return kthread_getspecific(__key); ++} ++ ++static inline int __gthread_setspecific(__gthread_key_t __key, ++ const void *__v) { ++ return kthread_setspecific(__key, __v); ++} ++ ++static inline int __gthread_mutex_destroy(__gthread_mutex_t *__mutex) { ++ mutex_destroy(*__mutex); ++ return 0; ++} ++ ++static inline int __gthread_mutex_lock(__gthread_mutex_t *__mutex) { ++ return mutex_lock(*__mutex); ++} ++ ++static inline int __gthread_mutex_trylock(__gthread_mutex_t *__mutex) { ++ return mutex_trylock(*__mutex); ++} ++ ++static inline int __gthread_mutex_unlock(__gthread_mutex_t *__mutex) { ++ mutex_unlock(*__mutex); ++ return 0; ++} ++ ++static inline int __gthread_recursive_mutex_lock(__gthread_recursive_mutex_t *__mutex) { ++ return rlock_lock(__mutex->koslock); ++} ++ ++static inline int __gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t *__mutex) { ++ return rlock_trylock(__mutex->koslock); ++} ++ ++static inline int __gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t *__mutex) { ++ return rlock_unlock(__mutex->koslock); ++} ++ ++static inline int __gthread_cond_broadcast(__gthread_cond_t *cond) { ++ cond_broadcast(*cond); ++ return 0; ++} ++ ++static inline int __gthread_cond_wait(__gthread_cond_t *cond, __gthread_mutex_t *mutex) { ++ return cond_wait(*cond, *mutex); ++} ++ ++static inline int __gthread_cond_wait_recursive(__gthread_cond_t *cond, ++ __gthread_recursive_mutex_t *mutex) { ++ return cond_wait_recursive(*cond, mutex->koslock); ++} ++ ++/* C++0x support functions */ ++ ++static inline int __gthread_create(__gthread_t *thd, void *(*func)(void *), ++ void *args) { ++ *thd = thd_create(0, func, args); ++ return (*thd == NULL); ++} ++ ++static inline int __gthread_join(__gthread_t thd, void **value_ptr) { ++ return thd_join(thd, value_ptr); ++} ++ ++static inline int __gthread_detach(__gthread_t thd) { ++ return thd_detach(thd); ++} ++ ++static inline int __gthread_equal(__gthread_t t1, __gthread_t t2) { ++ return t1 == t2; ++} ++ ++static inline __gthread_t __gthread_self(void) { ++ return thd_get_current(); ++} ++ ++static inline int __gthread_yield(void) { ++ thd_pass(); ++ return 0; ++} ++ ++static inline int __gthread_mutex_timedlock(__gthread_mutex_t *m, ++ const __gthread_time_t *timeout) { ++ int t = (int)(timeout->tv_sec + (timeout->tv_nsec / 1000)); ++ return mutex_lock_timed(*m, t); ++} ++ ++static inline int __gthread_recursive_mutex_timedlock(__gthread_recursive_mutex_t *l, ++ const __gthread_time_t *timeout) { ++ int t = (int)(timeout->tv_sec + (timeout->tv_nsec / 1000)); ++ return rlock_lock_timed(l->koslock, t); ++} ++ ++static inline int __gthread_cond_signal(__gthread_cond_t *cond) { ++ cond_signal(*cond); ++ return 0; ++} ++ ++static inline int __gthread_cond_timedwait(__gthread_cond_t *cond, ++ __gthread_mutex_t *mutex, ++ const __gthread_time_t *timeout) { ++ int t = (int)(timeout->tv_sec + (timeout->tv_nsec / 1000)); ++ return cond_wait_timed(*cond, *mutex, t); ++} ++ ++static inline int __gthread_cond_timedwait_recursive(__gthread_cond_t *cond, ++ __gthread_recursive_mutex_t *l, ++ const __gthread_time_t *timeout) { ++ int t = (int)(timeout->tv_sec + (timeout->tv_nsec / 1000)); ++ return cond_wait_timed_recursive(*cond, l->koslock, t); ++} ++ ++static inline int __gthread_cond_destroy(__gthread_cond_t *cond) { ++ cond_destroy(*cond); ++ return 0; ++} ++ ++#endif /* _LIBOBJC */ ++ ++#endif /* ! GCC_GTHR_KOS_H */ +diff -ruN gcc-4.7.0/libgcc/config/sh/kos-weak.S gcc-4.7.0-kos/libgcc/config/sh/kos-weak.S +--- gcc-4.7.0/libgcc/config/sh/kos-weak.S 1969-12-31 19:00:00.000000000 -0500 ++++ gcc-4.7.0-kos/libgcc/config/sh/kos-weak.S 2012-06-05 11:18:06.000000000 -0400 +@@ -0,0 +1,96 @@ ++! Weakly linked symbols used to get GCC to hopefully compile itself properly. ++! These will be replaced by the real symbols in actual compiled programs. ++ ++ ! crt1.S required symbols ++ .weak ___kos_init_flags ++ .weak _arch_main ++ ++ ! gthr-kos.h required symbols ++ .weak _mutex_create ++ .weak _mutex_is_locked ++ .weak _mutex_destroy ++ .weak _mutex_lock ++ .weak _mutex_trylock ++ .weak _mutex_lock_timed ++ .weak _mutex_unlock ++ ++ .weak _thd_create ++ .weak _thd_join ++ .weak _thd_detach ++ .weak _thd_pass ++ .weak _thd_exit ++ .weak _thd_get_current ++ ++ .weak _kthread_setspecific ++ .weak _kthread_getspecific ++ .weak _kthread_key_create ++ .weak _kthread_key_delete ++ .weak _kthread_once ++ ++ .weak _rlock_create ++ .weak _rlock_destroy ++ .weak _rlock_lock ++ .weak _rlock_trylock ++ .weak _rlock_unlock ++ .weak _rlock_lock_timed ++ ++ .weak _cond_create ++ .weak _cond_destroy ++ .weak _cond_wait ++ .weak _cond_wait_timed ++ .weak _cond_broadcast ++ .weak _cond_signal ++ .weak _cond_wait_recursive ++ .weak _cond_wait_timed_recursive ++ ++ ! Things needed by emutls ++ .weak _free ++ .weak _abort ++ .weak _malloc ++ .weak _realloc ++ .weak _calloc ++ ++___kos_init_flags: ++ .long 0 ++ ++_arch_main: ++_mutex_create: ++_mutex_is_locked: ++_mutex_unlock: ++_mutex_destroy: ++_mutex_lock: ++_mutex_trylock: ++_mutex_lock_timed: ++_thd_create: ++_thd_join: ++_thd_detach: ++_thd_pass: ++_thd_exit: ++_thd_get_current: ++_kthread_setspecific: ++_kthread_getspecific: ++_kthread_key_create: ++_kthread_key_delete: ++_kthread_once: ++_rlock_create: ++_rlock_destroy: ++_rlock_lock: ++_rlock_trylock: ++_rlock_unlock: ++_rlock_lock_timed: ++_cond_create: ++_cond_destroy: ++_cond_wait: ++_cond_wait_timed: ++_cond_broadcast: ++_cond_signal: ++_cond_wait_recursive: ++_cond_wait_timed_recursive: ++_free: ++_abort: ++_malloc: ++_realloc: ++_calloc: ++ rts ++ mov #-1, r0 ++ +\ No newline at end of file +diff -ruN gcc-4.7.0/libgcc/config/sh/t-sh gcc-4.7.0-kos/libgcc/config/sh/t-sh +--- gcc-4.7.0/libgcc/config/sh/t-sh 2011-11-07 12:14:32.000000000 -0500 ++++ gcc-4.7.0-kos/libgcc/config/sh/t-sh 2012-06-05 10:43:34.000000000 -0400 +@@ -24,6 +24,8 @@ + $(LIB1ASMFUNCS_CACHE) + LIB1ASMFUNCS_CACHE = _ic_invalidate _ic_invalidate_array + ++LIB2ADD = $(srcdir)/config/sh/kos-weak.S ++ + crt1.o: $(srcdir)/config/sh/crt1.S + $(gcc_compile) -c $< + +diff -ruN gcc-4.7.0/libgcc/configure gcc-4.7.0-kos/libgcc/configure +--- gcc-4.7.0/libgcc/configure 2012-01-23 01:25:28.000000000 -0500 ++++ gcc-4.7.0-kos/libgcc/configure 2012-06-04 19:19:26.000000000 -0400 +@@ -4801,6 +4801,7 @@ + tpf) thread_header=config/s390/gthr-tpf.h ;; + vxworks) thread_header=config/gthr-vxworks.h ;; + win32) thread_header=config/i386/gthr-win32.h ;; ++ kos) thread_header=config/sh/gthr-kos.h ;; + esac + + # Substitute configuration variables +diff -ruN gcc-4.7.0/libstdc++-v3/include/ext/concurrence.h gcc-4.7.0-kos/libstdc++-v3/include/ext/concurrence.h +--- gcc-4.7.0/libstdc++-v3/include/ext/concurrence.h 2011-01-30 17:39:36.000000000 -0500 ++++ gcc-4.7.0-kos/libstdc++-v3/include/ext/concurrence.h 2012-06-04 20:52:33.000000000 -0400 +@@ -283,6 +283,12 @@ + _S_destroy(_Rm* __mx) + { __gthread_mutex_destroy(&__mx->actual); } + ++ // matches kos ++ template<typename _Rm> ++ static typename __enable_if<sizeof(&_Rm::koslock), void>::__type ++ _S_destroy(_Rm* __mx) ++ { rlock_destroy(__mx->koslock); } ++ + // matches when there's only one mutex type + template<typename _Rm> + static typename +diff -ruN gcc-4.7.0/libstdc++-v3/include/std/mutex gcc-4.7.0-kos/libstdc++-v3/include/std/mutex +--- gcc-4.7.0/libstdc++-v3/include/std/mutex 2012-02-07 04:19:27.000000000 -0500 ++++ gcc-4.7.0-kos/libstdc++-v3/include/std/mutex 2012-06-04 21:00:52.000000000 -0400 +@@ -120,6 +120,12 @@ + _S_destroy(_Rm* __mx) + { __gthread_mutex_destroy(&__mx->actual); } + ++ // matches kos ++ template<typename _Rm> ++ static typename enable_if<sizeof(&_Rm::koslock), void>::type ++ _S_destroy(_Rm* __mx) ++ { rlock_destroy(__mx->koslock); } ++ + // matches a gthr-win32.h recursive mutex + template<typename _Rm> + static typename enable_if<sizeof(&_Rm::sema), void>::type Added: kos/utils/dc-chain/patches/newlib-1.20.0-kos.diff =================================================================== --- kos/utils/dc-chain/patches/newlib-1.20.0-kos.diff (rev 0) +++ kos/utils/dc-chain/patches/newlib-1.20.0-kos.diff 2012-06-06 02:28:23 UTC (rev 799) @@ -0,0 +1,487 @@ +diff -ruN newlib-1.20.0/newlib/configure.host newlib-1.20.0-kos/newlib/configure.host +--- newlib-1.20.0/newlib/configure.host 2011-11-29 01:33:48.000000000 -0500 ++++ newlib-1.20.0-kos/newlib/configure.host 2012-06-04 18:39:45.000000000 -0400 +@@ -237,6 +237,7 @@ + ;; + sh | sh64) + machine_dir=sh ++ newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED -DMALLOC_PROVIDED -DABORT_PROVIDED -DHAVE_FCNTL -ffunction-sections -fdata-sections" + ;; + sparc*) + machine_dir=sparc +diff -ruN newlib-1.20.0/newlib/libc/include/assert.h newlib-1.20.0-kos/newlib/libc/include/assert.h +--- newlib-1.20.0/newlib/libc/include/assert.h 2008-07-17 16:56:51.000000000 -0400 ++++ newlib-1.20.0-kos/newlib/libc/include/assert.h 2012-06-04 18:34:57.000000000 -0400 +@@ -13,8 +13,8 @@ + #ifdef NDEBUG /* required by ANSI standard */ + # define assert(__e) ((void)0) + #else +-# define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \ +- __ASSERT_FUNC, #_... [truncated message content] |
From: <los...@us...> - 2012-06-05 14:51:42
|
Revision: 798 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=798&view=rev Author: lostgeneration Date: 2012-06-05 14:51:24 +0000 (Tue, 05 Jun 2012) Log Message: ----------- Make formatting consistent across all files * This attempts to make formatting consistent across all source files in KOS. The general rules are a modified K&R style from astyle. Basically 4 spaces for indentation, indent labels, preprocessor directives, & switches, attach brackets & break closing headers, break blocks, unpad parenthesis, and add spaces around operators. * Basically: astyle --style=kr -s4 -c -L -S -w -y -f -U -p I ran though my IDE, so I'm not 100% the above is correct. Modified Paths: -------------- kos/addons/include/kos/bspline.h kos/addons/include/kos/img.h kos/addons/include/kos/netcfg.h kos/addons/include/kos/pcx.h kos/addons/include/kos/vector.h kos/addons/libkosutils/bspline.c kos/addons/libkosutils/img.c kos/addons/libkosutils/md5.c kos/addons/libkosutils/netcfg.c kos/addons/libkosutils/netcfg_icon.h kos/addons/libkosutils/pcx_small.c kos/examples/dreamcast/2ndmix/2ndmix.c kos/examples/dreamcast/2ndmix/gfx/font14_256.h kos/examples/dreamcast/2ndmix/s3mplay.h kos/examples/dreamcast/2ndmix/sintab.h kos/examples/dreamcast/basic/asserthnd/asserthnd.c kos/examples/dreamcast/basic/exec/exec.c kos/examples/dreamcast/basic/exec/sub.c kos/examples/dreamcast/basic/fpu/exc/fpu_exc.c kos/examples/dreamcast/basic/mmu/nullptr/nullptr.c kos/examples/dreamcast/basic/mmu/pvrmap/pvrmap.c kos/examples/dreamcast/basic/stacktrace/stacktrace.c kos/examples/dreamcast/basic/threading/general/general_threading_test.c kos/examples/dreamcast/basic/threading/once/once_test.c kos/examples/dreamcast/basic/threading/tls/tls_test.c kos/examples/dreamcast/conio/adventure/crc.c kos/examples/dreamcast/conio/adventure/done.c kos/examples/dreamcast/conio/adventure/hdr.h kos/examples/dreamcast/conio/adventure/init.c kos/examples/dreamcast/conio/adventure/io.c kos/examples/dreamcast/conio/adventure/main.c kos/examples/dreamcast/conio/adventure/porthelper.c kos/examples/dreamcast/conio/adventure/porthelper.h kos/examples/dreamcast/conio/adventure/save.c kos/examples/dreamcast/conio/adventure/setup.c kos/examples/dreamcast/conio/adventure/subr.c kos/examples/dreamcast/conio/adventure/vocab.c kos/examples/dreamcast/conio/adventure/wizard.c kos/examples/dreamcast/conio/basic/basic.c kos/examples/dreamcast/conio/kosh/kosh.c kos/examples/dreamcast/conio/wump/wump.c kos/examples/dreamcast/cpp/clock/clock.cc kos/examples/dreamcast/cpp/dcplib/fnt_test.cc kos/examples/dreamcast/cpp/gltest/gltest.cpp kos/examples/dreamcast/cpp/modplug_test/example.cpp kos/examples/dreamcast/dreameye/basic/dreameye.c kos/examples/dreamcast/hello/hello.c kos/examples/dreamcast/kgl/basic/gl/gltest.c kos/examples/dreamcast/kgl/basic/scissor/scissor.c kos/examples/dreamcast/kgl/basic/texenv/texenv.c kos/examples/dreamcast/kgl/basic/texwrap/texwrap.c kos/examples/dreamcast/kgl/basic/vfzclip/vfzclip.c kos/examples/dreamcast/kgl/basic/vq/vq-example.c kos/examples/dreamcast/kgl/benchmarks/quadmark/quadmark.c kos/examples/dreamcast/kgl/benchmarks/trimark/trimark.c kos/examples/dreamcast/kgl/demos/bubbles/bubbles.c kos/examples/dreamcast/kgl/demos/tunnel/menu.cpp kos/examples/dreamcast/kgl/demos/tunnel/menu.h kos/examples/dreamcast/kgl/demos/tunnel/plprint.cpp kos/examples/dreamcast/kgl/demos/tunnel/tunnel.cpp kos/examples/dreamcast/kgl/demos/tunnel/tunneldat.c kos/examples/dreamcast/kgl/nehe/nehe02/nehe02.c kos/examples/dreamcast/kgl/nehe/nehe05/nehe05.c kos/examples/dreamcast/kgl/nehe/nehe06/nehe06.c kos/examples/dreamcast/kgl/nehe/nehe08/nehe08.c kos/examples/dreamcast/kgl/nehe/nehe09/nehe09.c kos/examples/dreamcast/kgl/nehe/nehe16/nehe16.c kos/examples/dreamcast/kgl/nehe/nehe26/data/txt2bin.c kos/examples/dreamcast/kgl/nehe/nehe26/nehe26.c kos/examples/dreamcast/libdream/320x240/320x240.c kos/examples/dreamcast/libdream/640x480/640x480.c kos/examples/dreamcast/libdream/800x608/800x608.c kos/examples/dreamcast/libdream/cdfs/cdfs.c kos/examples/dreamcast/libdream/keyboard/keyboard.c kos/examples/dreamcast/libdream/lcd/lcd.c kos/examples/dreamcast/libdream/mouse/mouse.c kos/examples/dreamcast/libdream/rgb888/rgb888.c kos/examples/dreamcast/libdream/spu/s3mplay.h kos/examples/dreamcast/libdream/spu/spu.c kos/examples/dreamcast/libdream/ta/ta.c kos/examples/dreamcast/libdream/vmu/vmu.c kos/examples/dreamcast/lua/basic/lua.c kos/examples/dreamcast/modem/basic/example1.c kos/examples/dreamcast/network/basic/basic.c kos/examples/dreamcast/network/dcload-ip-lwip-test/main.c kos/examples/dreamcast/network/dns-client/dnslookup.c kos/examples/dreamcast/network/httpd/httpd.c kos/examples/dreamcast/network/httpd/simhost.c kos/examples/dreamcast/network/isp-settings/isp-settings.c kos/examples/dreamcast/network/udpecho6/echo.c kos/examples/dreamcast/parallax/bubbles/bubbles.c kos/examples/dreamcast/parallax/delay_cube/delay_cube.c kos/examples/dreamcast/parallax/font/font.c kos/examples/dreamcast/parallax/raster_melt/raster_melt.c kos/examples/dreamcast/parallax/rotocube/rotocube.c kos/examples/dreamcast/parallax/serpent_dma/perfmeter.c kos/examples/dreamcast/parallax/serpent_dma/serpent.c kos/examples/dreamcast/parallax/sinus/sinus.c kos/examples/dreamcast/png/example.c kos/examples/dreamcast/pvr/modifier_volume/modifier.c kos/examples/dreamcast/pvr/modifier_volume_tex/modifier.c kos/examples/dreamcast/pvr/plasma/plasma.c kos/examples/dreamcast/pvr/pvrmark/pvrmark.c kos/examples/dreamcast/pvr/pvrmark_strips/pvrmark_strips.c kos/examples/dreamcast/pvr/pvrmark_strips_direct/pvrmark_strips_direct.c kos/examples/dreamcast/pvr/texture_render/ta.c kos/examples/dreamcast/sound/cdda/basic_cdda/basic_cdda.c kos/examples/dreamcast/sound/ghettoplay-vorbis/3dutils.c kos/examples/dreamcast/sound/ghettoplay-vorbis/bkg.c kos/examples/dreamcast/sound/ghettoplay-vorbis/ghettoplay.c kos/examples/dreamcast/sound/ghettoplay-vorbis/gp.h kos/examples/dreamcast/sound/ghettoplay-vorbis/mouse1.h kos/examples/dreamcast/sound/ghettoplay-vorbis/sintab.h kos/examples/dreamcast/sound/ghettoplay-vorbis/songmenu.c kos/examples/dreamcast/sound/ghettoplay-vorbis/texture.c kos/examples/dreamcast/sound/ghettoplay-vorbis/vmu_ghetto.h kos/examples/dreamcast/sound/ghettoplay-vorbis/vmu_ghettoplay.h kos/examples/dreamcast/sound/ghettoplay-vorbis/vmu_play.h kos/examples/dreamcast/sound/hello-mp3/display.c kos/examples/dreamcast/sound/hello-mp3/mp3test.c kos/examples/dreamcast/sound/hello-ogg/display.c kos/examples/dreamcast/sound/hello-ogg/vorbistest.c kos/examples/dreamcast/tsunami/banner/banner.cpp kos/examples/dreamcast/tsunami/font/font.cpp kos/examples/dreamcast/tsunami/genmenu/genmenu.cpp kos/examples/dreamcast/video/bfont/bfont.c kos/examples/dreamcast/vmu/vmu_pkg/vmu.c kos/examples/gba/pogo-keen/pogo.c kos/examples/ps2/basic/hello/hello.c kos/include/assert.h kos/include/kos/cdefs.h kos/include/kos/cond.h kos/include/kos/dbgio.h kos/include/kos/dbglog.h kos/include/kos/elf.h kos/include/kos/exports.h kos/include/kos/fs.h kos/include/kos/fs_pty.h kos/include/kos/fs_ramdisk.h kos/include/kos/fs_romdisk.h kos/include/kos/fs_socket.h kos/include/kos/genwait.h kos/include/kos/iovec.h kos/include/kos/library.h kos/include/kos/limits.h kos/include/kos/mutex.h kos/include/kos/net.h kos/include/kos/nmmgr.h kos/include/kos/sem.h kos/include/kos/string.h kos/include/kos/thread.h kos/include/kos.h kos/include/malloc.h kos/include/netinet/in.h kos/include/pthread.h kos/include/sys/_pthread.h kos/include/sys/_types.h kos/include/sys/dirent.h kos/include/sys/sched.h kos/include/sys/socket.h kos/kernel/arch/dreamcast/fs/dcload-commands.c kos/kernel/arch/dreamcast/fs/dcload-commands.h kos/kernel/arch/dreamcast/fs/dcload-net.c kos/kernel/arch/dreamcast/fs/dcload-packet.c kos/kernel/arch/dreamcast/fs/dcload-packet.h kos/kernel/arch/dreamcast/fs/dcload-syscalls.c kos/kernel/arch/dreamcast/fs/dcload-syscalls.h kos/kernel/arch/dreamcast/fs/fs_dclnative.c kos/kernel/arch/dreamcast/fs/fs_dcload.c kos/kernel/arch/dreamcast/fs/fs_dclsocket.c kos/kernel/arch/dreamcast/fs/fs_iso9660.c kos/kernel/arch/dreamcast/fs/fs_vmu.c kos/kernel/arch/dreamcast/fs/vmufs.c kos/kernel/arch/dreamcast/hardware/asic.c kos/kernel/arch/dreamcast/hardware/biosfont.c kos/kernel/arch/dreamcast/hardware/cdrom.c kos/kernel/arch/dreamcast/hardware/flashrom.c kos/kernel/arch/dreamcast/hardware/g2bus.c kos/kernel/arch/dreamcast/hardware/hardware.c kos/kernel/arch/dreamcast/hardware/maple/controller.c kos/kernel/arch/dreamcast/hardware/maple/dreameye.c kos/kernel/arch/dreamcast/hardware/maple/keyboard.c kos/kernel/arch/dreamcast/hardware/maple/maple_driver.c kos/kernel/arch/dreamcast/hardware/maple/maple_enum.c kos/kernel/arch/dreamcast/hardware/maple/maple_globals.c kos/kernel/arch/dreamcast/hardware/maple/maple_init_shutdown.c kos/kernel/arch/dreamcast/hardware/maple/maple_irq.c kos/kernel/arch/dreamcast/hardware/maple/maple_queue.c kos/kernel/arch/dreamcast/hardware/maple/maple_utils.c kos/kernel/arch/dreamcast/hardware/maple/mouse.c kos/kernel/arch/dreamcast/hardware/maple/purupuru.c kos/kernel/arch/dreamcast/hardware/maple/sip.c kos/kernel/arch/dreamcast/hardware/maple/vmu.c kos/kernel/arch/dreamcast/hardware/modem/chainbuf.c kos/kernel/arch/dreamcast/hardware/modem/chainbuf.h kos/kernel/arch/dreamcast/hardware/modem/mdata.c kos/kernel/arch/dreamcast/hardware/modem/mintern.h kos/kernel/arch/dreamcast/hardware/modem/mintr.c kos/kernel/arch/dreamcast/hardware/modem/modem.c kos/kernel/arch/dreamcast/hardware/network/broadband_adapter.c kos/kernel/arch/dreamcast/hardware/network/lan_adapter.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_buffers.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_dma.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_fog.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_fog_tables.h kos/kernel/arch/dreamcast/hardware/pvr/pvr_init_shutdown.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_internal.h kos/kernel/arch/dreamcast/hardware/pvr/pvr_irq.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_mem.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_mem_core.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_mem_core.h kos/kernel/arch/dreamcast/hardware/pvr/pvr_misc.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_palette.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_prim.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_scene.c kos/kernel/arch/dreamcast/hardware/pvr/pvr_texture.c kos/kernel/arch/dreamcast/hardware/scif.c kos/kernel/arch/dreamcast/hardware/spu.c kos/kernel/arch/dreamcast/hardware/spudma.c kos/kernel/arch/dreamcast/hardware/sq.c kos/kernel/arch/dreamcast/hardware/vblank.c kos/kernel/arch/dreamcast/hardware/video.c kos/kernel/arch/dreamcast/include/arch/arch.h kos/kernel/arch/dreamcast/include/arch/cache.h kos/kernel/arch/dreamcast/include/arch/exec.h kos/kernel/arch/dreamcast/include/arch/gdb.h kos/kernel/arch/dreamcast/include/arch/irq.h kos/kernel/arch/dreamcast/include/arch/mmu.h kos/kernel/arch/dreamcast/include/arch/rtc.h kos/kernel/arch/dreamcast/include/arch/spinlock.h kos/kernel/arch/dreamcast/include/arch/stack.h kos/kernel/arch/dreamcast/include/arch/timer.h kos/kernel/arch/dreamcast/include/arch/types.h kos/kernel/arch/dreamcast/include/dc/asic.h kos/kernel/arch/dreamcast/include/dc/biosfont.h kos/kernel/arch/dreamcast/include/dc/cdrom.h kos/kernel/arch/dreamcast/include/dc/flashrom.h kos/kernel/arch/dreamcast/include/dc/fmath.h kos/kernel/arch/dreamcast/include/dc/fs_dclnative.h kos/kernel/arch/dreamcast/include/dc/fs_dcload.h kos/kernel/arch/dreamcast/include/dc/fs_iso9660.h kos/kernel/arch/dreamcast/include/dc/fs_vmu.h kos/kernel/arch/dreamcast/include/dc/g2bus.h kos/kernel/arch/dreamcast/include/dc/maple/controller.h kos/kernel/arch/dreamcast/include/dc/maple/dreameye.h kos/kernel/arch/dreamcast/include/dc/maple/keyboard.h kos/kernel/arch/dreamcast/include/dc/maple/mouse.h kos/kernel/arch/dreamcast/include/dc/maple/purupuru.h kos/kernel/arch/dreamcast/include/dc/maple/sip.h kos/kernel/arch/dreamcast/include/dc/maple/vmu.h kos/kernel/arch/dreamcast/include/dc/maple.h kos/kernel/arch/dreamcast/include/dc/matrix.h kos/kernel/arch/dreamcast/include/dc/matrix3d.h kos/kernel/arch/dreamcast/include/dc/modem/modem.h kos/kernel/arch/dreamcast/include/dc/net/broadband_adapter.h kos/kernel/arch/dreamcast/include/dc/net/lan_adapter.h kos/kernel/arch/dreamcast/include/dc/pvr.h kos/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h kos/kernel/arch/dreamcast/include/dc/sound/sound.h kos/kernel/arch/dreamcast/include/dc/sound/stream.h kos/kernel/arch/dreamcast/include/dc/spu.h kos/kernel/arch/dreamcast/include/dc/ubc.h kos/kernel/arch/dreamcast/include/dc/vblank.h kos/kernel/arch/dreamcast/include/dc/video.h kos/kernel/arch/dreamcast/include/dc/vmu_pkg.h kos/kernel/arch/dreamcast/include/dc/vmufs.h kos/kernel/arch/dreamcast/include/navi/flash.h kos/kernel/arch/dreamcast/include/navi/ide.h kos/kernel/arch/dreamcast/kernel/exec.c kos/kernel/arch/dreamcast/kernel/gdb_stub.c kos/kernel/arch/dreamcast/kernel/init.c kos/kernel/arch/dreamcast/kernel/irq.c kos/kernel/arch/dreamcast/kernel/mm.c kos/kernel/arch/dreamcast/kernel/mmu.c kos/kernel/arch/dreamcast/kernel/panic.c kos/kernel/arch/dreamcast/kernel/rtc.c kos/kernel/arch/dreamcast/kernel/ser_console.c kos/kernel/arch/dreamcast/kernel/stack.c kos/kernel/arch/dreamcast/kernel/timer.c kos/kernel/arch/dreamcast/math/fmath.c kos/kernel/arch/dreamcast/math/matrix3d.c kos/kernel/arch/dreamcast/navi/navi_flash.c kos/kernel/arch/dreamcast/navi/navi_ide.c kos/kernel/arch/dreamcast/sound/arm/aica.c kos/kernel/arch/dreamcast/sound/arm/aica.h kos/kernel/arch/dreamcast/sound/arm/aica_cmd_iface.h kos/kernel/arch/dreamcast/sound/arm/main.c kos/kernel/arch/dreamcast/sound/snd_iface.c kos/kernel/arch/dreamcast/sound/snd_mem.c kos/kernel/arch/dreamcast/sound/snd_sfxmgr.c kos/kernel/arch/dreamcast/sound/snd_stream.c kos/kernel/arch/dreamcast/util/screenshot.c kos/kernel/arch/dreamcast/util/vmu_pkg.c kos/kernel/arch/gba/include/arch/arch.h kos/kernel/arch/gba/include/arch/cache.h kos/kernel/arch/gba/include/arch/dbgio.h kos/kernel/arch/gba/include/arch/exec.h kos/kernel/arch/gba/include/arch/irq.h kos/kernel/arch/gba/include/arch/rtc.h kos/kernel/arch/gba/include/arch/spinlock.h kos/kernel/arch/gba/include/arch/stack.h kos/kernel/arch/gba/include/arch/syscall.h kos/kernel/arch/gba/include/arch/timer.h kos/kernel/arch/gba/include/arch/types.h kos/kernel/arch/gba/include/gba/dma.h kos/kernel/arch/gba/include/gba/keys.h kos/kernel/arch/gba/include/gba/math.h kos/kernel/arch/gba/include/gba/sound.h kos/kernel/arch/gba/include/gba/sprite.h kos/kernel/arch/gba/include/gba/video.h kos/kernel/arch/gba/kernel/dbgio.c kos/kernel/arch/gba/kernel/irq.c kos/kernel/arch/gba/kernel/lazy_porting.c kos/kernel/arch/gba/kernel/main.c kos/kernel/arch/gba/kernel/mm.c kos/kernel/arch/gba/kernel/panic.c kos/kernel/arch/gba/kernel/syscall.c kos/kernel/arch/gba/kernel/timer.c kos/kernel/arch/ia32/include/arch/arch.h kos/kernel/arch/ia32/include/arch/cache.h kos/kernel/arch/ia32/include/arch/dbgio.h kos/kernel/arch/ia32/include/arch/exec.h kos/kernel/arch/ia32/include/arch/gdb.h kos/kernel/arch/ia32/include/arch/irq.h kos/kernel/arch/ia32/include/arch/mmu.h kos/kernel/arch/ia32/include/arch/rtc.h kos/kernel/arch/ia32/include/arch/spinlock.h kos/kernel/arch/ia32/include/arch/stack.h kos/kernel/arch/ia32/include/arch/timer.h kos/kernel/arch/ia32/include/arch/types.h kos/kernel/arch/ia32/include/ia32/ports.h kos/kernel/arch/ia32/kernel/dbgio.c kos/kernel/arch/ia32/kernel/exec.c kos/kernel/arch/ia32/kernel/init.c kos/kernel/arch/ia32/kernel/irq.c kos/kernel/arch/ia32/kernel/mmu.c kos/kernel/arch/ia32/kernel/panic.c kos/kernel/arch/ia32/kernel/rtc.c kos/kernel/arch/ia32/kernel/stack.c kos/kernel/arch/ia32/kernel/timer.c kos/kernel/arch/ps2/fs/fs_ps2load.c kos/kernel/arch/ps2/include/arch/arch.h kos/kernel/arch/ps2/include/arch/atexit.h kos/kernel/arch/ps2/include/arch/cache.h kos/kernel/arch/ps2/include/arch/dbgio.h kos/kernel/arch/ps2/include/arch/exec.h kos/kernel/arch/ps2/include/arch/irq.h kos/kernel/arch/ps2/include/arch/rtc.h kos/kernel/arch/ps2/include/arch/spinlock.h kos/kernel/arch/ps2/include/arch/stack.h kos/kernel/arch/ps2/include/arch/syscall.h kos/kernel/arch/ps2/include/arch/timer.h kos/kernel/arch/ps2/include/arch/types.h kos/kernel/arch/ps2/include/ps2/asmregs.h kos/kernel/arch/ps2/include/ps2/fs_ps2load.h kos/kernel/arch/ps2/include/ps2/ioports.h kos/kernel/arch/ps2/include/ps2/sbios.h kos/kernel/arch/ps2/kernel/atexit.c kos/kernel/arch/ps2/kernel/crtbegin.c kos/kernel/arch/ps2/kernel/dbgio.c kos/kernel/arch/ps2/kernel/irq.c kos/kernel/arch/ps2/kernel/main.c kos/kernel/arch/ps2/kernel/mm.c kos/kernel/arch/ps2/kernel/panic.c kos/kernel/arch/ps2/kernel/syscall.c kos/kernel/arch/ps2/kernel/timer.c kos/kernel/arch/ps2/sbios/sbios_init_shutdown.c kos/kernel/debug/dbgio.c kos/kernel/exports/exports.c kos/kernel/exports/library.c kos/kernel/exports/nmmgr.c kos/kernel/fs/elf.c kos/kernel/fs/fs.c kos/kernel/fs/fs_pty.c kos/kernel/fs/fs_ramdisk.c kos/kernel/fs/fs_romdisk.c kos/kernel/fs/fs_socket.c kos/kernel/fs/fs_utils.c kos/kernel/libc/koslib/abort.c kos/kernel/libc/koslib/assert.c kos/kernel/libc/koslib/atexit.c kos/kernel/libc/koslib/byteorder.c kos/kernel/libc/koslib/chdir.c kos/kernel/libc/koslib/closedir.c kos/kernel/libc/koslib/creat.c kos/kernel/libc/koslib/crtbegin.c kos/kernel/libc/koslib/crtend.c kos/kernel/libc/koslib/dbglog.c kos/kernel/libc/koslib/getcwd.c kos/kernel/libc/koslib/inet_aton.c kos/kernel/libc/koslib/inet_ntoa.c kos/kernel/libc/koslib/inet_ntop.c kos/kernel/libc/koslib/inet_pton.c kos/kernel/libc/koslib/malloc.c kos/kernel/libc/koslib/memcpy2.c kos/kernel/libc/koslib/memcpy4.c kos/kernel/libc/koslib/memset2.c kos/kernel/libc/koslib/memset4.c kos/kernel/libc/koslib/mkdir.c kos/kernel/libc/koslib/opendir.c kos/kernel/libc/koslib/readdir.c kos/kernel/libc/koslib/realpath.c kos/kernel/libc/koslib/rename.c kos/kernel/libc/koslib/rewinddir.c kos/kernel/libc/koslib/rmdir.c kos/kernel/libc/koslib/scandir.c kos/kernel/libc/koslib/seekdir.c kos/kernel/libc/koslib/sleep.c kos/kernel/libc/koslib/telldir.c kos/kernel/libc/koslib/usleep.c kos/kernel/libc/newlib/lock_common.c kos/kernel/libc/newlib/newlib_close.c kos/kernel/libc/newlib/newlib_env_lock.c kos/kernel/libc/newlib/newlib_execve.c kos/kernel/libc/newlib/newlib_exit.c kos/kernel/libc/newlib/newlib_fcntl.c kos/kernel/libc/newlib/newlib_fork.c kos/kernel/libc/newlib/newlib_fstat.c kos/kernel/libc/newlib/newlib_getpid.c kos/kernel/libc/newlib/newlib_gettimeofday.c kos/kernel/libc/newlib/newlib_isatty.c kos/kernel/libc/newlib/newlib_kill.c kos/kernel/libc/newlib/newlib_link.c kos/kernel/libc/newlib/newlib_lseek.c kos/kernel/libc/newlib/newlib_malloc.c kos/kernel/libc/newlib/newlib_open.c kos/kernel/libc/newlib/newlib_read.c kos/kernel/libc/newlib/newlib_sbrk.c kos/kernel/libc/newlib/newlib_times.c kos/kernel/libc/newlib/newlib_unlink.c kos/kernel/libc/newlib/newlib_wait.c kos/kernel/libc/newlib/newlib_write.c kos/kernel/libc/newlib/verify_newlib.c kos/kernel/libc/pthreads/pthread_cond.c kos/kernel/libc/pthreads/pthread_mutex.c kos/kernel/libc/pthreads/pthread_thd.c kos/kernel/libc/pthreads/pthread_thd_attr.c kos/kernel/libc/pthreads/pthread_tls.c kos/kernel/mm/cplusplus.c kos/kernel/mm/malloc_debug.c kos/kernel/net/net_arp.c kos/kernel/net/net_core.c kos/kernel/net/net_crc.c kos/kernel/net/net_dhcp.c kos/kernel/net/net_icmp.c kos/kernel/net/net_icmp.h kos/kernel/net/net_icmp6.c kos/kernel/net/net_input.c kos/kernel/net/net_ipv4.c kos/kernel/net/net_ipv4.h kos/kernel/net/net_ipv4_frag.c kos/kernel/net/net_ipv6.c kos/kernel/net/net_multicast.c kos/kernel/net/net_ndp.c kos/kernel/net/net_tcp.c kos/kernel/net/net_thd.c kos/kernel/net/net_udp.c kos/kernel/thread/cond.c kos/kernel/thread/genwait.c kos/kernel/thread/mutex.c kos/kernel/thread/recursive_lock.c kos/kernel/thread/rwsem.c kos/kernel/thread/sem.c kos/kernel/thread/thread.c kos/kernel/thread/tls.c kos/libk++/mem.cc kos/libk++/pure_virtual.c kos/utils/bin2c/bin2c.c kos/utils/bincnv/bincnv.c kos/utils/gba-crcfix/gba-crcfix.c kos/utils/genromfs/genromfs.c kos/utils/gentexfont/TexFont.h kos/utils/gentexfont/gentexfont.c kos/utils/isotest/isotest.c kos/utils/kmgenc/get_image.c kos/utils/kmgenc/get_image.h kos/utils/kmgenc/get_image_jpg.c kos/utils/kmgenc/get_image_png.c kos/utils/kmgenc/kmgenc.c kos/utils/kmgenc/kmgenc.h kos/utils/kmgenc/readpng.c kos/utils/kmgenc/readpng.h kos/utils/makejitter/makejitter.c kos/utils/rdtest/rdtest.c kos/utils/vqenc/get_image.c kos/utils/vqenc/get_image.h kos/utils/vqenc/get_image_jpg.c kos/utils/vqenc/get_image_png.c kos/utils/vqenc/readpng.c kos/utils/vqenc/readpng.h kos/utils/vqenc/vq_internal.h kos/utils/vqenc/vq_types.h kos/utils/vqenc/vqenc.c kos/utils/wav2adpcm/wav2adpcm.c Modified: kos/addons/include/kos/bspline.h =================================================================== --- kos/addons/include/kos/bspline.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/include/kos/bspline.h 2012-06-05 14:51:24 UTC (rev 798) @@ -37,4 +37,4 @@ __END_DECLS -#endif /* __KOS_BSPLINE_H */ +#endif /* __KOS_BSPLINE_H */ Modified: kos/addons/include/kos/img.h =================================================================== --- kos/addons/include/kos/img.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/include/kos/img.h 2012-06-05 14:51:24 UTC (rev 798) @@ -22,14 +22,14 @@ the paletted formats) the data interpretation _may_ be platform dependent. Thus we also provide a data-length field. */ typedef struct kos_img { - void * data; - uint32 w, h; - uint32 fmt; - uint32 byte_count; + void * data; + uint32 w, h; + uint32 fmt; + uint32 byte_count; } kos_img_t; /* Access to the upper and lower pieces of the format word */ -#define KOS_IMG_FMT_I(x) ((x) & 0xffff) /* Platform independent part */ +#define KOS_IMG_FMT_I(x) ((x) & 0xffff) /* Platform independent part */ #define KOS_IMG_FMT_D(x) (((x) >> 16) & 0xffff) /* Macro to create a new format word */ @@ -38,24 +38,24 @@ /* Definitions for the plat independent part *************************************/ /* Bitmap formats */ -#define KOS_IMG_FMT_NONE 0x00 /* Undefined */ -#define KOS_IMG_FMT_RGB888 0x01 /* Interleaved r/g/b bytes (24-bit) */ -#define KOS_IMG_FMT_ARGB8888 0x02 /* Interleaved a/r/g/b bytes (32-bit) */ -#define KOS_IMG_FMT_RGB565 0x03 /* r/g/b 5/6/5 (16-bit) */ -#define KOS_IMG_FMT_ARGB4444 0x04 /* a/r/g/b 4/4/4/4 (16-bit) */ -#define KOS_IMG_FMT_ARGB1555 0x05 /* a/r/g/b 1/5/5/5 (16-bit) */ -#define KOS_IMG_FMT_PAL4BPP 0x06 /* Paletted (4-bit) */ -#define KOS_IMG_FMT_PAL8BPP 0x07 /* Paletted (8-bit) */ -#define KOS_IMG_FMT_YUV422 0x08 /* y/u/v 4/2/2 (8-bit) */ -#define KOS_IMG_FMT_BGR565 0x09 /* b/g/r 5/6/5 (16-bit) */ -#define KOS_IMG_FMT_RGBA8888 0x10 /* Interleaved r/g/b/a bytes (32-bit) */ -#define KOS_IMG_FMT_MASK 0xff +#define KOS_IMG_FMT_NONE 0x00 /* Undefined */ +#define KOS_IMG_FMT_RGB888 0x01 /* Interleaved r/g/b bytes (24-bit) */ +#define KOS_IMG_FMT_ARGB8888 0x02 /* Interleaved a/r/g/b bytes (32-bit) */ +#define KOS_IMG_FMT_RGB565 0x03 /* r/g/b 5/6/5 (16-bit) */ +#define KOS_IMG_FMT_ARGB4444 0x04 /* a/r/g/b 4/4/4/4 (16-bit) */ +#define KOS_IMG_FMT_ARGB1555 0x05 /* a/r/g/b 1/5/5/5 (16-bit) */ +#define KOS_IMG_FMT_PAL4BPP 0x06 /* Paletted (4-bit) */ +#define KOS_IMG_FMT_PAL8BPP 0x07 /* Paletted (8-bit) */ +#define KOS_IMG_FMT_YUV422 0x08 /* y/u/v 4/2/2 (8-bit) */ +#define KOS_IMG_FMT_BGR565 0x09 /* b/g/r 5/6/5 (16-bit) */ +#define KOS_IMG_FMT_RGBA8888 0x10 /* Interleaved r/g/b/a bytes (32-bit) */ +#define KOS_IMG_FMT_MASK 0xff /* Misc attributes */ -#define KOS_IMG_INVERTED_X 0x0100 /* X axis is inverted */ -#define KOS_IMG_INVERTED_Y 0x0200 /* Y axis is inverted */ -#define KOS_IMG_NOT_OWNER 0x0400 /* We don't own the buffer containing - the data (ROM or similar) */ +#define KOS_IMG_INVERTED_X 0x0100 /* X axis is inverted */ +#define KOS_IMG_INVERTED_Y 0x0200 /* Y axis is inverted */ +#define KOS_IMG_NOT_OWNER 0x0400 /* We don't own the buffer containing +the data (ROM or similar) */ /* Util functions ****************************************************************/ @@ -65,5 +65,5 @@ __END_DECLS -#endif /* __KOS_IMG_H */ +#endif /* __KOS_IMG_H */ Modified: kos/addons/include/kos/netcfg.h =================================================================== --- kos/addons/include/kos/netcfg.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/include/kos/netcfg.h 2012-06-05 14:51:24 UTC (rev 798) @@ -15,32 +15,32 @@ /* Network configuration info. This holds the information about how we will start the networking and what settings to use. */ -#define NETCFG_METHOD_DHCP 0 -#define NETCFG_METHOD_STATIC 1 -#define NETCFG_METHOD_PPPOE 4 -#define NETCFG_SRC_VMU 0 -#define NETCFG_SRC_FLASH 1 -#define NETCFG_SRC_CWD 2 -#define NETCFG_SRC_CDROOT 3 +#define NETCFG_METHOD_DHCP 0 +#define NETCFG_METHOD_STATIC 1 +#define NETCFG_METHOD_PPPOE 4 +#define NETCFG_SRC_VMU 0 +#define NETCFG_SRC_FLASH 1 +#define NETCFG_SRC_CWD 2 +#define NETCFG_SRC_CDROOT 3 typedef struct netcfg { - int src; // Config source - int method; // Configuration method - uint32 ip; // IP addresses - uint32 gateway; - uint32 netmask; - uint32 broadcast; - uint32 dns[2]; // DNS servers - char hostname[64]; // DHCP hostname - char email[64]; // E-Mail address - char smtp[64]; // SMTP server - char pop3[64]; // POP3 server - char pop3_login[64]; // POP3 login name - char pop3_passwd[64]; // POP3 password - char proxy_host[64]; // Proxy server hostname - int proxy_port; // Proxy server port - char ppp_login[64]; // PPP login - char ppp_passwd[64]; // PPP password - char driver[64]; // Driver program filename (if any) + int src; // Config source + int method; // Configuration method + uint32 ip; // IP addresses + uint32 gateway; + uint32 netmask; + uint32 broadcast; + uint32 dns[2]; // DNS servers + char hostname[64]; // DHCP hostname + char email[64]; // E-Mail address + char smtp[64]; // SMTP server + char pop3[64]; // POP3 server + char pop3_login[64]; // POP3 login name + char pop3_passwd[64]; // POP3 password + char proxy_host[64]; // Proxy server hostname + int proxy_port; // Proxy server port + char ppp_login[64]; // PPP login + char ppp_passwd[64]; // PPP password + char driver[64]; // Driver program filename (if any) } netcfg_t; // Load a network config from a specific file. @@ -61,5 +61,5 @@ __END_DECLS -#endif /* __KOS_NETCFG_H */ +#endif /* __KOS_NETCFG_H */ Modified: kos/addons/include/kos/pcx.h =================================================================== --- kos/addons/include/kos/pcx.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/include/kos/pcx.h 2012-06-05 14:51:24 UTC (rev 798) @@ -32,5 +32,5 @@ __END_DECLS -#endif /* __KOS_PCX_H */ +#endif /* __KOS_PCX_H */ Modified: kos/addons/include/kos/vector.h =================================================================== --- kos/addons/include/kos/vector.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/include/kos/vector.h 2012-06-05 14:51:24 UTC (rev 798) @@ -21,12 +21,14 @@ typedef float matrix_t[4][4]; /* Vector definition */ -typedef struct vectorstr { float x, y, z, w; } vector_t; +typedef struct vectorstr { + float x, y, z, w; +} vector_t; /* Points are just vectors */ typedef vector_t point_t; __END_DECLS -#endif /* __KOS_VECTOR_H */ +#endif /* __KOS_VECTOR_H */ Modified: kos/addons/libkosutils/bspline.c =================================================================== --- kos/addons/libkosutils/bspline.c 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/libkosutils/bspline.c 2012-06-05 14:51:24 UTC (rev 798) @@ -18,41 +18,50 @@ function below. */ static float bc_x[4], bc_y[4], bc_z[4]; void bspline_coeff(const point_t * pnt) { - float a, b, c, d; + float a, b, c, d; - /* First calculate the X coefficients */ - a = pnt[-1].x; b = pnt[0].x; c = pnt[1].x; d = pnt[2].x; - bc_x[3] = (-a+3*(b-c)+d) / 6.0f; - bc_x[2] = (a-2*b+c)/2.0f; - bc_x[1] = (c-a)/2.0f; - bc_x[0] = (a+4*b+c)/6.0f; + /* First calculate the X coefficients */ + a = pnt[-1].x; + b = pnt[0].x; + c = pnt[1].x; + d = pnt[2].x; + bc_x[3] = (-a + 3 * (b - c) + d) / 6.0f; + bc_x[2] = (a - 2 * b + c) / 2.0f; + bc_x[1] = (c - a) / 2.0f; + bc_x[0] = (a + 4 * b + c) / 6.0f; - /* Next, the Y coefficients */ - a = pnt[-1].y; b = pnt[0].y; c = pnt[1].y; d = pnt[2].y; - bc_y[3] = (-a+3*(b-c)+d) / 6.0f; - bc_y[2] = (a-2*b+c)/2.0f; - bc_y[1] = (c-a)/2.0f; - bc_y[0] = (a+4*b+c)/6.0f; + /* Next, the Y coefficients */ + a = pnt[-1].y; + b = pnt[0].y; + c = pnt[1].y; + d = pnt[2].y; + bc_y[3] = (-a + 3 * (b - c) + d) / 6.0f; + bc_y[2] = (a - 2 * b + c) / 2.0f; + bc_y[1] = (c - a) / 2.0f; + bc_y[0] = (a + 4 * b + c) / 6.0f; - /* Finally, the Z coefficients */ - a = pnt[-1].z; b = pnt[0].z; c = pnt[1].z; d = pnt[2].z; - bc_z[3] = (-a+3*(b-c)+d) / 6.0f; - bc_z[2] = (a-2*b+c)/2.0f; - bc_z[1] = (c-a)/2.0f; - bc_z[0] = (a+4*b+c)/6.0f; + /* Finally, the Z coefficients */ + a = pnt[-1].z; + b = pnt[0].z; + c = pnt[1].z; + d = pnt[2].z; + bc_z[3] = (-a + 3 * (b - c) + d) / 6.0f; + bc_z[2] = (a - 2 * b + c) / 2.0f; + bc_z[1] = (c - a) / 2.0f; + bc_z[0] = (a + 4 * b + c) / 6.0f; } /* Given a 't' (between 0.0f and 1.0f) this will generate the next point values for the current set of coefficients. */ void bspline_get_point(float t, point_t *p) { - /* Generate X */ - p->x = ((bc_x[3]*t+bc_x[2])*t+bc_x[1])*t + bc_x[0]; + /* Generate X */ + p->x = ((bc_x[3] * t + bc_x[2]) * t + bc_x[1]) * t + bc_x[0]; - /* Generate Y */ - p->y = ((bc_y[3]*t+bc_y[2])*t+bc_y[1])*t + bc_y[0]; + /* Generate Y */ + p->y = ((bc_y[3] * t + bc_y[2]) * t + bc_y[1]) * t + bc_y[0]; - /* Generate Z */ - p->z = ((bc_z[3]*t+bc_z[2])*t+bc_z[1])*t + bc_z[0]; + /* Generate Z */ + p->z = ((bc_z[3] * t + bc_z[2]) * t + bc_z[1]) * t + bc_z[0]; } Modified: kos/addons/libkosutils/img.c =================================================================== --- kos/addons/libkosutils/img.c 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/libkosutils/img.c 2012-06-05 14:51:24 UTC (rev 798) @@ -13,15 +13,15 @@ /* Free a kos_img_t which was created by an image loader; set struct_also to non-zero if you want it to free the struct itself as well. */ void kos_img_free(kos_img_t *img, int struct_also) { - assert( img != NULL ); + assert(img != NULL); - /* Free the image data (if any) */ - if (img->data && !(KOS_IMG_FMT_I(img->fmt) & KOS_IMG_NOT_OWNER)) - free(img->data); + /* Free the image data (if any) */ + if(img->data && !(KOS_IMG_FMT_I(img->fmt) & KOS_IMG_NOT_OWNER)) + free(img->data); - /* Free the struct itself */ - if (struct_also) - free(img); + /* Free the struct itself */ + if(struct_also) + free(img); } Modified: kos/addons/libkosutils/md5.c =================================================================== --- kos/addons/libkosutils/md5.c 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/libkosutils/md5.c 2012-06-05 14:51:24 UTC (rev 798) @@ -18,9 +18,9 @@ depending on its length. This is the padding that is to be used. */ static const uint8 md5padding[64] = { 0x80, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* MD5 "magic" values */ @@ -87,28 +87,28 @@ /* Compound operations, consisting of a F, G, H, or I operation and a rotate */ #define MD5_FH(a, b, c, d, w, s, t) { \ - (a) += MD5_F((b), (c), (d)) + (w) + (t); \ - (a) = MD5_ROT((a), (s)); \ - (a) += (b); \ -} + (a) += MD5_F((b), (c), (d)) + (w) + (t); \ + (a) = MD5_ROT((a), (s)); \ + (a) += (b); \ + } #define MD5_GH(a, b, c, d, w, s, t) { \ - (a) += MD5_G((b), (c), (d)) + (w) + (t); \ - (a) = MD5_ROT((a), (s)); \ - (a) += (b); \ -} + (a) += MD5_G((b), (c), (d)) + (w) + (t); \ + (a) = MD5_ROT((a), (s)); \ + (a) += (b); \ + } #define MD5_HH(a, b, c, d, w, s, t) { \ - (a) += MD5_H((b), (c), (d)) + (w) + (t); \ - (a) = MD5_ROT((a), (s)); \ - (a) += (b); \ -} + (a) += MD5_H((b), (c), (d)) + (w) + (t); \ + (a) = MD5_ROT((a), (s)); \ + (a) += (b); \ + } #define MD5_IH(a, b, c, d, w, s, t) { \ - (a) += MD5_I((b), (c), (d)) + (w) + (t); \ - (a) = MD5_ROT((a), (s)); \ - (a) += (b); \ -} + (a) += MD5_I((b), (c), (d)) + (w) + (t); \ + (a) = MD5_ROT((a), (s)); \ + (a) += (b); \ + } void kos_md5_start(kos_md5_cxt_t *cxt) { cxt->size = 0; @@ -132,7 +132,7 @@ /* Read the input into our buffer */ for(i = 0; i < 16; ++i) { w[i] = input[(i << 2)] | (input[(i << 2) + 1] << 8) | - (input[(i << 2) + 2] << 16) | (input[(i << 2) + 3] << 24); + (input[(i << 2) + 2] << 16) | (input[(i << 2) + 3] << 24); } /* First Round */ Modified: kos/addons/libkosutils/netcfg.c =================================================================== --- kos/addons/libkosutils/netcfg.c 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/libkosutils/netcfg.c 2012-06-05 14:51:24 UTC (rev 798) @@ -22,40 +22,40 @@ #endif void netcfg_vmuify(const char *filename_in, const char *filename_out) { - int fd, pkg_size; - uint8 *buf; - uint8 *pkg_out; - vmu_pkg_t pkg; + int fd, pkg_size; + uint8 *buf; + uint8 *pkg_out; + vmu_pkg_t pkg; - dbgp("Opening source file\n"); - fd = fs_open(filename_in, O_RDONLY); - buf = (uint8 *) malloc(fs_total(fd)); - fs_read(fd, buf, fs_total(fd)); - dbgp("Read %i bytes\n", fs_total(fd)); + dbgp("Opening source file\n"); + fd = fs_open(filename_in, O_RDONLY); + buf = (uint8 *) malloc(fs_total(fd)); + fs_read(fd, buf, fs_total(fd)); + dbgp("Read %i bytes\n", fs_total(fd)); - strcpy(pkg.desc_short, "KallistiOS 1.3"); - strcpy(pkg.desc_long, "KOS Network Settings"); - strcpy(pkg.app_id, "KOS"); - pkg.icon_cnt = 1; - pkg.icon_anim_speed = 1; - memcpy(&pkg.icon_pal[0], netcfg_icon, 32); - pkg.icon_data = netcfg_icon + 32; - pkg.eyecatch_type = VMUPKG_EC_NONE; - pkg.data_len = fs_total(fd); - pkg.data = buf; - dbgp("Building package\n"); - vmu_pkg_build(&pkg, &pkg_out, &pkg_size); - fs_close(fd); - dbgp("Closing source file\n"); + strcpy(pkg.desc_short, "KallistiOS 1.3"); + strcpy(pkg.desc_long, "KOS Network Settings"); + strcpy(pkg.app_id, "KOS"); + pkg.icon_cnt = 1; + pkg.icon_anim_speed = 1; + memcpy(&pkg.icon_pal[0], netcfg_icon, 32); + pkg.icon_data = netcfg_icon + 32; + pkg.eyecatch_type = VMUPKG_EC_NONE; + pkg.data_len = fs_total(fd); + pkg.data = buf; + dbgp("Building package\n"); + vmu_pkg_build(&pkg, &pkg_out, &pkg_size); + fs_close(fd); + dbgp("Closing source file\n"); - dbgp("Opening output file\n"); - fd = fs_open(filename_out, O_WRONLY); - dbgp("Writing..\n"); - fs_write(fd, pkg_out, pkg_size); - dbgp("Closing output file\n"); - fs_close(fd); - free(buf); - dbgp("VMUification complete\n"); + dbgp("Opening output file\n"); + fd = fs_open(filename_out, O_WRONLY); + dbgp("Writing..\n"); + fs_write(fd, pkg_out, pkg_size); + dbgp("Closing output file\n"); + fs_close(fd); + free(buf); + dbgp("VMUification complete\n"); } /* This module attempts to ferret out a valid network configuration by @@ -65,289 +65,339 @@ and then from the root of the CD. If that fails, we give up. */ int netcfg_load_from(const char * fn, netcfg_t * out) { - FILE * f; - char buf[64], *b; - int l; + FILE * f; + char buf[64], *b; + int l; - assert( out ); + assert(out); - // Open the file - f = fopen(fn, "rb"); - if (!f) - return -1; + // Open the file + f = fopen(fn, "rb"); - // If we're reading from a VMU, seek past the header - // In the future, we could read this and use data_len to - // know how big the file really is - if (fn[0]=='/' && fn[1]=='v' && fn[2] == 'm' && fn[3] == 'u') { - // Make sure there's a VMU header to skip. If so, skip it. - fread(buf, 4, 1, f); buf[4] = 0; - if (strcmp(buf, "# KO")) - fseek(f, 128+512, SEEK_SET); - } + if(!f) + return -1; - // Read each line... - while (fgets(buf, 64, f)) { - // Skip comments and blank lines - if (buf[0] == 0 || buf[0] == '#') - continue; + // If we're reading from a VMU, seek past the header + // In the future, we could read this and use data_len to + // know how big the file really is + if(fn[0] == '/' && fn[1] == 'v' && fn[2] == 'm' && fn[3] == 'u') { + // Make sure there's a VMU header to skip. If so, skip it. + fread(buf, 4, 1, f); + buf[4] = 0; - // Strip newlines - l = strlen(buf); - if (buf[l-1] == '\n') { - buf[l-1] = 0; - l--; - } - if (buf[l-1] == '\r') { - buf[l-1] = 0; - l--; - } + if(strcmp(buf, "# KO")) + fseek(f, 128 + 512, SEEK_SET); + } - // Look for an equals - b = strchr(buf, '='); - if (!b) - continue; + // Read each line... + while(fgets(buf, 64, f)) { + // Skip comments and blank lines + if(buf[0] == 0 || buf[0] == '#') + continue; - *b = 0; b++; + // Strip newlines + l = strlen(buf); - // What was the line type? - if (!strcmp(buf, "driver")) { - strcpy(out->driver, b); - } else if (!strcmp(buf, "ip")) { - out->ip = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "gateway")) { - out->gateway = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "netmask")) { - out->netmask = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "broadcast")) { - out->broadcast = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "dns1")) { - out->dns[0] = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "dns2")) { - out->dns[1] = strtoul(b, NULL, 16); - } else if (!strcmp(buf, "hostname")) { - strcpy(out->hostname, b); - } else if (!strcmp(buf, "email")) { - strcpy(out->email, b); - } else if (!strcmp(buf, "smtp")) { - strcpy(out->smtp, b); - } else if (!strcmp(buf, "pop3")) { - strcpy(out->pop3, b); - } else if (!strcmp(buf, "pop3_login")) { - strcpy(out->pop3_login, b); - } else if (!strcmp(buf, "pop3_passwd")) { - strcpy(out->pop3_passwd, b); - } else if (!strcmp(buf, "proxy_host")) { - strcpy(out->proxy_host, b); - } else if (!strcmp(buf, "proxy_port")) { - out->proxy_port = strtoul(b, NULL, 10); - } else if (!strcmp(buf, "ppp_login")) { - strcpy(out->ppp_login, b); - } else if (!strcmp(buf, "ppp_passwd")) { - strcpy(out->ppp_passwd, b); - } else if (!strcmp(buf, "method")) { - if (!strcmp(b, "dhcp")) - out->method = NETCFG_METHOD_DHCP; - else if (!strcmp(b, "static")) - out->method = NETCFG_METHOD_STATIC; - else if (!strcmp(b, "pppoe")) - out->method = NETCFG_METHOD_PPPOE; - } - } + if(buf[l - 1] == '\n') { + buf[l - 1] = 0; + l--; + } - fclose(f); + if(buf[l - 1] == '\r') { + buf[l - 1] = 0; + l--; + } - return 0; + // Look for an equals + b = strchr(buf, '='); + + if(!b) + continue; + + *b = 0; + b++; + + // What was the line type? + if(!strcmp(buf, "driver")) { + strcpy(out->driver, b); + } + else if(!strcmp(buf, "ip")) { + out->ip = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "gateway")) { + out->gateway = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "netmask")) { + out->netmask = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "broadcast")) { + out->broadcast = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "dns1")) { + out->dns[0] = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "dns2")) { + out->dns[1] = strtoul(b, NULL, 16); + } + else if(!strcmp(buf, "hostname")) { + strcpy(out->hostname, b); + } + else if(!strcmp(buf, "email")) { + strcpy(out->email, b); + } + else if(!strcmp(buf, "smtp")) { + strcpy(out->smtp, b); + } + else if(!strcmp(buf, "pop3")) { + strcpy(out->pop3, b); + } + else if(!strcmp(buf, "pop3_login")) { + strcpy(out->pop3_login, b); + } + else if(!strcmp(buf, "pop3_passwd")) { + strcpy(out->pop3_passwd, b); + } + else if(!strcmp(buf, "proxy_host")) { + strcpy(out->proxy_host, b); + } + else if(!strcmp(buf, "proxy_port")) { + out->proxy_port = strtoul(b, NULL, 10); + } + else if(!strcmp(buf, "ppp_login")) { + strcpy(out->ppp_login, b); + } + else if(!strcmp(buf, "ppp_passwd")) { + strcpy(out->ppp_passwd, b); + } + else if(!strcmp(buf, "method")) { + if(!strcmp(b, "dhcp")) + out->method = NETCFG_METHOD_DHCP; + else if(!strcmp(b, "static")) + out->method = NETCFG_METHOD_STATIC; + else if(!strcmp(b, "pppoe")) + out->method = NETCFG_METHOD_PPPOE; + } + } + + fclose(f); + + return 0; } int netcfg_load_flash(netcfg_t * out) { - flashrom_ispcfg_t cfg; + flashrom_ispcfg_t cfg; - if (flashrom_get_ispcfg(&cfg) < 0) - return -1; + if(flashrom_get_ispcfg(&cfg) < 0) + return -1; - // Start out with a clean config - memset(out, 0, sizeof(netcfg_t)); + // Start out with a clean config + memset(out, 0, sizeof(netcfg_t)); #define READIP(dst, src) \ - dst = ((src[0]) << 24) | \ - ((src[1]) << 16) | \ - ((src[2]) << 8) | \ - ((src[3]) << 0) + dst = ((src[0]) << 24) | \ + ((src[1]) << 16) | \ + ((src[2]) << 8) | \ + ((src[3]) << 0) - if (cfg.valid_fields & FLASHROM_ISP_IP) - READIP(out->ip, cfg.ip); - if (cfg.valid_fields & FLASHROM_ISP_GATEWAY) - READIP(out->gateway, cfg.gw); - if (cfg.valid_fields & FLASHROM_ISP_NETMASK) - READIP(out->netmask, cfg.nm); - if (cfg.valid_fields & FLASHROM_ISP_BROADCAST) - READIP(out->broadcast, cfg.bc); - if (cfg.valid_fields & FLASHROM_ISP_DNS) { - READIP(out->dns[0], cfg.dns[0]); - READIP(out->dns[1], cfg.dns[1]); - } - if (cfg.valid_fields & FLASHROM_ISP_HOSTNAME) - strcpy(out->hostname, cfg.hostname); - if (cfg.valid_fields & FLASHROM_ISP_EMAIL) - strcpy(out->email, cfg.email); - if (cfg.valid_fields & FLASHROM_ISP_SMTP) - strcpy(out->smtp, cfg.smtp); - if (cfg.valid_fields & FLASHROM_ISP_POP3) - strcpy(out->pop3, cfg.pop3); - if (cfg.valid_fields & FLASHROM_ISP_POP3_USER) - strcpy(out->pop3_login, cfg.pop3_login); - if (cfg.valid_fields & FLASHROM_ISP_POP3_PASS) - strcpy(out->pop3_passwd, cfg.pop3_passwd); - if (cfg.valid_fields & FLASHROM_ISP_PROXY_PORT) - out->proxy_port = cfg.proxy_port; - if (cfg.valid_fields & FLASHROM_ISP_PROXY_HOST) - strcpy(out->proxy_host, cfg.proxy_host); - if (cfg.valid_fields & FLASHROM_ISP_PPP_USER) - strcpy(out->ppp_login, cfg.ppp_login); - if (cfg.valid_fields & FLASHROM_ISP_PPP_PASS) - strcpy(out->ppp_passwd, cfg.ppp_passwd); + if(cfg.valid_fields & FLASHROM_ISP_IP) + READIP(out->ip, cfg.ip); + if(cfg.valid_fields & FLASHROM_ISP_GATEWAY) + READIP(out->gateway, cfg.gw); + + if(cfg.valid_fields & FLASHROM_ISP_NETMASK) + READIP(out->netmask, cfg.nm); + + if(cfg.valid_fields & FLASHROM_ISP_BROADCAST) + READIP(out->broadcast, cfg.bc); + + if(cfg.valid_fields & FLASHROM_ISP_DNS) { + READIP(out->dns[0], cfg.dns[0]); + READIP(out->dns[1], cfg.dns[1]); + } + + if(cfg.valid_fields & FLASHROM_ISP_HOSTNAME) + strcpy(out->hostname, cfg.hostname); + + if(cfg.valid_fields & FLASHROM_ISP_EMAIL) + strcpy(out->email, cfg.email); + + if(cfg.valid_fields & FLASHROM_ISP_SMTP) + strcpy(out->smtp, cfg.smtp); + + if(cfg.valid_fields & FLASHROM_ISP_POP3) + strcpy(out->pop3, cfg.pop3); + + if(cfg.valid_fields & FLASHROM_ISP_POP3_USER) + strcpy(out->pop3_login, cfg.pop3_login); + + if(cfg.valid_fields & FLASHROM_ISP_POP3_PASS) + strcpy(out->pop3_passwd, cfg.pop3_passwd); + + if(cfg.valid_fields & FLASHROM_ISP_PROXY_PORT) + out->proxy_port = cfg.proxy_port; + + if(cfg.valid_fields & FLASHROM_ISP_PROXY_HOST) + strcpy(out->proxy_host, cfg.proxy_host); + + if(cfg.valid_fields & FLASHROM_ISP_PPP_USER) + strcpy(out->ppp_login, cfg.ppp_login); + + if(cfg.valid_fields & FLASHROM_ISP_PPP_PASS) + strcpy(out->ppp_passwd, cfg.ppp_passwd); + #undef READIP - return 0; + return 0; } int netcfg_load(netcfg_t * out) { - file_t f; - dirent_t * d; - char buf[64]; + file_t f; + dirent_t * d; + char buf[64]; - // Scan for VMUs - f = fs_open("/vmu", O_RDONLY | O_DIR); - if (f >= 0) { - for ( ; ; ) { - d = fs_readdir(f); - if (!d) { - fs_close(f); - break; - } + // Scan for VMUs + f = fs_open("/vmu", O_RDONLY | O_DIR); - sprintf(buf, "/vmu/%s/net.cfg", d->name); - if (netcfg_load_from(buf, out) >= 0) { - out->src = NETCFG_SRC_VMU; - fs_close(f); - return 0; - } - } - } + if(f >= 0) { + for(; ;) { + d = fs_readdir(f); - // Couldn't find anything. Try reading the config - // from flash. - if (netcfg_load_flash(out) >= 0) { - out->src = NETCFG_SRC_FLASH; - return 0; - } + if(!d) { + fs_close(f); + break; + } - // Didn't work out->. try the current dir. - if (netcfg_load_from("net.cfg", out) >= 0) { - out->src = NETCFG_SRC_CWD; - return 0; - } + sprintf(buf, "/vmu/%s/net.cfg", d->name); - // Finally, try the CD - if (netcfg_load_from("/cd/net.cfg", out) >= 0) { - out->src = NETCFG_SRC_CDROOT; - return 0; - } + if(netcfg_load_from(buf, out) >= 0) { + out->src = NETCFG_SRC_VMU; + fs_close(f); + return 0; + } + } + } - return -1; + // Couldn't find anything. Try reading the config + // from flash. + if(netcfg_load_flash(out) >= 0) { + out->src = NETCFG_SRC_FLASH; + return 0; + } + + // Didn't work out->. try the current dir. + if(netcfg_load_from("net.cfg", out) >= 0) { + out->src = NETCFG_SRC_CWD; + return 0; + } + + // Finally, try the CD + if(netcfg_load_from("/cd/net.cfg", out) >= 0) { + out->src = NETCFG_SRC_CDROOT; + return 0; + } + + return -1; } int netcfg_save_to(const char * fn, const netcfg_t * cfg) { - FILE * f; - char buf[64]; + FILE * f; + char buf[64]; - assert( cfg ); + assert(cfg); - dbgp("Saving: %s\n",fn); - // Open the output file - if (fn[0]=='/' && fn[1]=='v' && fn[2] == 'm' && fn[3] == 'u') { - dbgp("Saving to VMU\n"); - f = fopen("/ram/netcfg.tmp", "wb"); - } else { - f = fopen(fn, "wb"); - } - if (!f) - return -1; + dbgp("Saving: %s\n", fn); - // Write out each line... - sprintf(buf, "# KOS Network Config written by netcfg_save_to\n"); - if (fwrite(buf, strlen(buf), 1, f) != 1) - goto error; + // Open the output file + if(fn[0] == '/' && fn[1] == 'v' && fn[2] == 'm' && fn[3] == 'u') { + dbgp("Saving to VMU\n"); + f = fopen("/ram/netcfg.tmp", "wb"); + } + else { + f = fopen(fn, "wb"); + } + if(!f) + return -1; + + // Write out each line... + sprintf(buf, "# KOS Network Config written by netcfg_save_to\n"); + + if(fwrite(buf, strlen(buf), 1, f) != 1) + goto error; + #define WRITESTR(fmt, data) \ - sprintf(buf, fmt, data); \ - if (fwrite(buf, strlen(buf), 1, f) != 1) \ - goto error; + sprintf(buf, fmt, data); \ + if (fwrite(buf, strlen(buf), 1, f) != 1) \ + goto error; - WRITESTR("driver=%s\n", cfg->driver); - WRITESTR("ip=%08lx\n", cfg->ip); - WRITESTR("gateway=%08lx\n", cfg->gateway); - WRITESTR("netmask=%08lx\n", cfg->netmask); - WRITESTR("broadcast=%08lx\n", cfg->broadcast); - WRITESTR("dns1=%08lx\n", cfg->dns[0]); - WRITESTR("dns2=%08lx\n", cfg->dns[1]); - WRITESTR("hostname=%s\n", cfg->hostname); - WRITESTR("email=%s\n", cfg->email); - WRITESTR("smtp=%s\n", cfg->smtp); - WRITESTR("pop3=%s\n", cfg->pop3); - WRITESTR("pop3_login=%s\n", cfg->pop3_login); - WRITESTR("pop3_passwd=%s\n", cfg->pop3_passwd); - WRITESTR("proxy_host=%s\n", cfg->proxy_host); - WRITESTR("proxy_port=%d\n", cfg->proxy_port); - WRITESTR("ppp_login=%s\n", cfg->ppp_login); - WRITESTR("ppp_passwd=%s\n", cfg->ppp_passwd); - switch (cfg->method) { - case 0: - WRITESTR("method=%s\n", "dhcp"); - break; - case 1: - WRITESTR("method=%s\n", "static"); - break; - case 4: - WRITESTR("method=%s\n", "pppoe"); - break; - } + WRITESTR("driver=%s\n", cfg->driver); + WRITESTR("ip=%08lx\n", cfg->ip); + WRITESTR("gateway=%08lx\n", cfg->gateway); + WRITESTR("netmask=%08lx\n", cfg->netmask); + WRITESTR("broadcast=%08lx\n", cfg->broadcast); + WRITESTR("dns1=%08lx\n", cfg->dns[0]); + WRITESTR("dns2=%08lx\n", cfg->dns[1]); + WRITESTR("hostname=%s\n", cfg->hostname); + WRITESTR("email=%s\n", cfg->email); + WRITESTR("smtp=%s\n", cfg->smtp); + WRITESTR("pop3=%s\n", cfg->pop3); + WRITESTR("pop3_login=%s\n", cfg->pop3_login); + WRITESTR("pop3_passwd=%s\n", cfg->pop3_passwd); + WRITESTR("proxy_host=%s\n", cfg->proxy_host); + WRITESTR("proxy_port=%d\n", cfg->proxy_port); + WRITESTR("ppp_login=%s\n", cfg->ppp_login); + WRITESTR("ppp_passwd=%s\n", cfg->ppp_passwd); + + switch(cfg->method) { + case 0: + WRITESTR("method=%s\n", "dhcp"); + break; + case 1: + WRITESTR("method=%s\n", "static"); + break; + case 4: + WRITESTR("method=%s\n", "pppoe"); + break; + } + #undef WRITESTR - fclose(f); + fclose(f); - //If we're saving to a VMU, tack on the header and send it out - if (fn[0]=='/' && fn[1]=='v' && fn[2] == 'm' && fn[3] == 'u') { - netcfg_vmuify("/ram/netcfg.tmp", fn); - unlink("/ram/netcfg.tmp"); - } - return 0; + //If we're saving to a VMU, tack on the header and send it out + if(fn[0] == '/' && fn[1] == 'v' && fn[2] == 'm' && fn[3] == 'u') { + netcfg_vmuify("/ram/netcfg.tmp", fn); + unlink("/ram/netcfg.tmp"); + } + return 0; + error: - fclose(f); - return -1; + fclose(f); + return -1; } int netcfg_save(const netcfg_t * cfg) { - file_t f; - dirent_t * d; - char buf[64]; + file_t f; + dirent_t * d; + char buf[64]; - // Scan for a VMU - f = fs_open("/vmu", O_RDONLY | O_DIR); - if (f < 0) - return -1; + // Scan for a VMU + f = fs_open("/vmu", O_RDONLY | O_DIR); - d = fs_readdir(f); - if (!d) { - fs_close(f); - return -1; - } + if(f < 0) + return -1; - sprintf(buf, "/vmu/%s/net.cfg", d->name); - fs_close(f); + d = fs_readdir(f); - return netcfg_save_to(buf, cfg); + if(!d) { + fs_close(f); + return -1; + } + + sprintf(buf, "/vmu/%s/net.cfg", d->name); + fs_close(f); + + return netcfg_save_to(buf, cfg); } Modified: kos/addons/libkosutils/netcfg_icon.h =================================================================== --- kos/addons/libkosutils/netcfg_icon.h 2012-06-04 02:36:19 UTC (rev 797) +++ kos/addons/libkosutils/netcfg_icon.h 2012-06-05 14:51:24 UTC (rev 798) @@ -4,74 +4,74 @@ * */ -const unsigned char netcfg_icon[544] ={ - 0x00, 0xf0, 0x11, 0xf1, 0x22, 0xf2, 0x33, 0xf3, - 0x44, 0xf4, 0x66, 0xf6, 0x5a, 0xf6, 0x77, 0xf7, - 0x88, 0xf8, 0x98, 0xf8, 0xa9, 0xf9, 0xaa, 0xfa, - 0xbb, 0xfb, 0xcc, 0xfc, 0xdd, 0xfd, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf3, 0x75, 0x75, 0x55, 0x7f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x58, 0x48, 0xaa, 0xa9, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x55, 0x58, 0x57, 0x88, 0x98, 0x5f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x55, 0x54, 0x78, 0x57, 0x78, 0x88, - 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x77, 0x75, 0x55, 0x77, 0x55, 0x77, - 0x87, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x77, 0x77, 0x55, 0x55, 0x85, 0x55, - 0x77, 0x88, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x77, 0x77, 0x77, 0x55, 0x55, 0x95, - 0x57, 0x78, 0x99, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x58, 0x88, 0x77, 0x77, 0x55, 0x48, - 0x75, 0x78, 0x89, 0xaa, 0x8f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x58, 0x88, 0x88, 0x77, 0x77, 0x75, - 0x59, 0x75, 0x89, 0xab, 0xbc, 0x55, 0x87, 0xff, - 0xff, 0xff, 0xf7, 0x98, 0x88, 0x88, 0x77, 0x75, - 0x55, 0x79, 0x78, 0x98, 0x87, 0xb8, 0x88, 0x5f, - 0xff, 0xff, 0xff, 0x99, 0x88, 0x88, 0x87, 0x78, - 0x77, 0x55, 0x89, 0xaa, 0x89, 0x9e, 0xee, 0x8f, - 0xff, 0xff, 0xff, 0x59, 0x99, 0x98, 0x88, 0x87, - 0x77, 0x77, 0x55, 0x7b, 0xee, 0xed, 0xee, 0x9f, - 0xff, 0xff, 0xff, 0xf8, 0x99, 0x99, 0x98, 0x88, - 0x87, 0x77, 0x75, 0x8e, 0xdb, 0xa9, 0x7a, 0x9f, - 0xff, 0xff, 0xf6, 0xff, 0x8a, 0xa9, 0x96, 0x66, - 0x88, 0x88, 0x77, 0x7d, 0x95, 0x43, 0x39, 0x9f, - 0xff, 0x66, 0x66, 0xff, 0xf7, 0xaa, 0x66, 0x66, - 0x68, 0x88, 0x88, 0x77, 0x31, 0x10, 0x28, 0x9f, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0x56, 0xaa, 0x99, - 0x99, 0x98, 0x88, 0x87, 0x20, 0x00, 0x18, 0xaf, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0x65, 0xaa, 0xaa, - 0x99, 0x99, 0x88, 0x78, 0x20, 0x00, 0x17, 0xaf, - 0xff, 0xf6, 0x66, 0xff, 0xf6, 0xff, 0x5a, 0xaa, - 0xaa, 0xa9, 0x99, 0x79, 0x20, 0x00, 0x37, 0xaf, - 0xff, 0xf6, 0x66, 0xff, 0x66, 0xff, 0xf5, 0xab, - 0xaa, 0xaa, 0x9a, 0x79, 0x41, 0x35, 0x8c, 0xaf, - 0xff, 0xf6, 0x66, 0xf6, 0x6f, 0xff, 0xff, 0xfa, - 0xba, 0xaa, 0xaa, 0x5b, 0x59, 0xde, 0xee, 0xaf, - 0xff, 0xf6, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, - 0xab, 0xba, 0xaa, 0x7e, 0xee, 0xee, 0xee, 0xaf, - 0xff, 0xf6, 0x66, 0xf6, 0x66, 0xff, 0xff, 0xff, - 0xf9, 0xbb, 0xba, 0x7e, 0xee, 0xee, 0xee, 0xaf, - 0xff, 0xf6, 0x66, 0xff, 0x66, 0x6f, 0xff, 0xff, - 0xff, 0x9b, 0xbb, 0x8d, 0xee, 0xee, 0xee, 0xbf, - 0xff, 0xf6, 0x66, 0xff, 0x66, 0x66, 0xff, 0xff, - 0xff, 0xf9, 0xcc, 0xb7, 0xee, 0xee, 0xee, 0xbf, - 0xff, 0xf6, 0x66, 0xff, 0xf6, 0x66, 0x6f, 0xff, - 0xff, 0xff, 0x8c, 0xc8, 0xee, 0xee, 0xee, 0xbf, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0x66, 0x6f, 0xff, - 0xff, 0xff, 0xf7, 0xcc, 0x8e, 0xee, 0xee, 0x9f, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0xf6, 0x66, 0xff, - 0xff, 0xff, 0xff, 0x7c, 0x8e, 0xed, 0x9f, 0xff, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0xf6, 0x66, 0x6f, - 0xff, 0xff, 0xff, 0xff, 0x95, 0x8f, 0xff, 0xff, - 0xff, 0xf6, 0x66, 0xff, 0xff, 0x66, 0x66, 0x66, - 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +const unsigned char netcfg_icon[544] = { + 0x00, 0xf0, 0x11, 0xf1, 0x22, 0xf2, 0x33, 0xf3, + 0x44, 0xf4, 0x66, 0xf6, 0x5a, 0xf6, 0x77, 0xf7, + 0x88, 0xf8, 0x98, 0xf8, 0xa9, 0xf9, 0xaa, 0xfa, + 0xbb, 0xfb, 0xcc, 0xfc, 0xdd, 0xfd, 0xfe, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf3, 0x75, 0x75, 0x55, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf4, 0x58, 0x48, 0xaa, 0xa9, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf4, 0x55, 0x58, 0x57, 0x88, 0x98, 0x5f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf4, 0x55, 0x54, 0x78, 0x57, 0x78, 0x88, + 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x77, 0x75, 0x55, 0x77, 0x55, 0x77, + 0x87, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x77, 0x77, 0x55, 0x55, 0x85, 0x55, + 0x77, 0x88, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x77, 0x77, 0x77, 0x55, 0x55, 0x95, + 0x57, 0x78, 0x99, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x58, 0x88, 0x77, 0x77, 0x55, 0x48, + 0x75, 0x78, 0x89, 0xaa, 0x8f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x58, 0x88, 0x88, 0x77, 0x77, 0x75, + 0x59, 0x75, 0x89, 0xab, 0xbc, 0x55, 0x87, 0xff, + 0xff, 0xff, 0xf7, 0x98, 0x88, 0x88, 0x77, 0x75, + 0x55, 0x79, 0x78, 0x98, 0x87, 0xb8, 0x88, 0x5f, + 0xff, 0xff, 0xff, 0x99, 0x88, 0x88, 0x87, 0x78, + 0x77, 0x55, 0x89, 0xaa, 0x89, 0x9e, 0xee, 0x8f, + 0xff, 0xff, 0xff, 0x59, 0x99, 0x98, 0x88, 0x87, + 0x77, 0x77, 0x55, 0x7b, 0xee, 0xed, 0xee, 0x9f, + 0xff, 0xff, 0xff, 0xf8, 0x99, 0x99, 0x98, 0x88, + 0x87, 0x77, 0x75, 0x8e, 0xdb, 0xa9, 0x7a, 0x9f, + 0xff, 0xff, 0xf6, 0xff, 0x8a, 0xa9, 0x96, 0x66, + 0x88, 0x88, 0x77, 0x7d, 0x95, 0x43, 0x39, 0x9f, + 0xff, 0x66, 0x66, 0xff, 0xf7, 0xaa, 0x66, 0x66, + 0x68, 0x88, 0x88, 0x77, 0x31, 0x10, 0x28, 0x9f, + 0xff, 0xf6, 0x66, 0xff, 0xff, 0x56, 0xaa, 0x99, + 0x99, 0x98, 0x88, 0x87, 0x20, 0x00, 0x18, 0xaf, + 0xff, 0xf6, 0x66, 0xff, 0xff, 0x65, 0xaa, 0xaa, + 0x99, 0x99, 0x88, 0x78, 0x20, 0x00, 0x17, 0xaf, + 0xff, 0xf6, 0x66, 0xff, 0xf6, 0xff, 0x5a, 0xaa, + 0xaa, 0xa9, 0x99, 0x79, 0x20, 0x00, 0x37, 0xaf, + 0xff, 0xf6, 0x66, 0xff, 0x66, 0xff, 0xf5, 0xab, + 0xaa, 0xaa, 0x9a, 0x79, 0x41, 0x35, 0x8c, 0xaf, + 0xff, 0xf6, 0x66, 0xf6, 0x6f, 0xff, 0xff, 0xfa, + 0xba, 0xaa, 0xaa, 0x5b, 0x59, 0xde, 0xee, 0xaf, + 0xff, 0xf6, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, + 0xab, 0xba, 0xaa, 0x7e, 0xee, 0xee, 0xee, 0xaf, + 0xff, 0xf6, 0x66, 0xf6, 0x66, 0xff, 0xff, 0xff, + 0xf9, 0xbb, 0xba, 0x7e, 0xee, 0xee, 0xee, 0xaf, + 0xff, 0xf6, 0x66, 0xff, 0x66, 0x6f, 0xff, 0xff, + 0xff, 0x9b, 0xbb, 0x8d, 0xee, 0xee, 0xee, 0xbf, + 0xff, 0xf6, 0x66, 0xff, 0x66, 0x66, 0xff, 0xff, + 0xff, 0xf9, 0xcc, 0xb7, 0xee, 0xee, 0xee, 0xbf, + 0xff, 0xf6, 0x66, 0xff, 0xf6, 0x66, 0x6f, 0xff, + 0xff, 0xff, 0x8c, 0xc8, 0xee, 0xee, 0xee, 0xbf, + 0xff, 0xf6, 0x66, 0xff, 0xff, 0x66, 0x6f, 0xff, + 0xff, 0xff, 0xf7, 0xcc, 0x8e, 0xee, 0xee, 0x9f, + 0xff, 0xf6, 0x66, 0xff, 0xff, 0xf6, 0x66, 0xff, + 0xff, 0xff, 0xff, 0x7c, 0x8e, 0xed, 0x9f, 0xff, + 0xff, 0xf6, 0x66, 0xff, 0xff, 0xf6, 0x66, 0x6f, + 0xff, 0xff, 0xff, 0xff, 0x95, 0x8f, 0xff, 0xff, + 0xff, 0xf6, 0x66, 0xff, ... [truncated message content] |
From: <ljs...@us...> - 2012-06-04 02:36:25
|
Revision: 797 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=797&view=rev Author: ljsebald Date: 2012-06-04 02:36:19 +0000 (Mon, 04 Jun 2012) Log Message: ----------- Support fcntl in fs_vmu, fs_dclsocket, fs_iso9660, and fs_dcload. Some of these are a bit hackish, but they should work for what we need them for. Modified Paths: -------------- kos/kernel/arch/dreamcast/fs/fs_dcload.c kos/kernel/arch/dreamcast/fs/fs_dclsocket.c kos/kernel/arch/dreamcast/fs/fs_iso9660.c kos/kernel/arch/dreamcast/fs/fs_vmu.c kos/kernel/net/net_tcp.c kos/kernel/net/net_udp.c Modified: kos/kernel/arch/dreamcast/fs/fs_dcload.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_dcload.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/arch/dreamcast/fs/fs_dcload.c 2012-06-04 02:36:19 UTC (rev 797) @@ -1,8 +1,9 @@ /* KallistiOS ##version## kernel/arch/dreamcast/fs/fs_dcload.c - Copyright (C)2002 Andrew Kieschnick - Copyright (C)2004 Dan Potter + Copyright (C) 2002 Andrew Kieschnick + Copyright (C) 2004 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -27,6 +28,7 @@ #include <ctype.h> #include <string.h> #include <malloc.h> +#include <errno.h> static spinlock_t mutex = SPINLOCK_INITIALIZER; @@ -330,34 +332,59 @@ return ret; } +static int dcload_fcntl(void *h, int cmd, va_list ap) { + int rv = -1; + switch(cmd) { + case F_GETFL: + /* XXXX: Not the right thing to do... */ + rv = O_RDWR; + break; + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + /* Pull all that together */ static vfs_handler_t vh = { - /* Name handler */ - { - "/pc", /* name */ - 0, /* tbfi */ - 0x00010000, /* Version 1.0 */ - 0, /* flags */ - NMMGR_TYPE_VFS, - NMMGR_LIST_INIT - }, + /* Name handler */ + { + "/pc", /* name */ + 0, /* tbfi */ + 0x00010000, /* Version 1.0 */ + 0, /* flags */ + NMMGR_TYPE_VFS, + NMMGR_LIST_INIT + }, - 0, NULL, /* no cache, privdata */ + 0, NULL, /* no cache, privdata */ - dcload_open, - dcload_close, - dcload_read, - dcload_write, - dcload_seek, - dcload_tell, - dcload_total, - dcload_readdir, - NULL, /* ioctl */ - dcload_rename, - dcload_unlink, - NULL /* mmap */ + dcload_open, + dcload_close, + dcload_read, + dcload_write, + dcload_seek, + dcload_tell, + dcload_total, + dcload_readdir, + NULL, /* ioctl */ + dcload_rename, + dcload_unlink, + NULL, /* mmap */ + NULL, /* complete */ + NULL, /* stat */ + NULL, /* mkdir */ + NULL, /* rmdir */ + dcload_fcntl }; // We have to provide a minimal interface in case dcload usage is Modified: kos/kernel/arch/dreamcast/fs/fs_dclsocket.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_dclsocket.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/arch/dreamcast/fs/fs_dclsocket.c 2012-06-04 02:36:19 UTC (rev 797) @@ -1,7 +1,7 @@ /* KallistiOS ##version## kernel/arch/dreamcast/fs/fs_dclsocket.c - Copyright (C) 2007, 2008 Lawrence Sebald + Copyright (C) 2007, 2008, 2012 Lawrence Sebald Based on fs_dclnative.c and related files Copyright (C) 2003 Dan Potter @@ -652,6 +652,28 @@ return retval; } +static int dcls_fcntl(void *h, int cmd, va_list ap) { + int rv = -1; + + switch(cmd) { + case F_GETFL: + /* XXXX: Not the right thing to do... */ + rv = O_RDWR; + break; + + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + /* VFS handler */ static vfs_handler_t vh = { /* Name handler */ @@ -681,7 +703,8 @@ NULL, /* complete */ dcls_stat, NULL, /* mkdir */ - NULL /* rmdir */ + NULL, /* rmdir */ + dcls_fcntl }; /* dbgio handler */ Modified: kos/kernel/arch/dreamcast/fs/fs_iso9660.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_iso9660.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/arch/dreamcast/fs/fs_iso9660.c 2012-06-04 02:36:19 UTC (rev 797) @@ -1,9 +1,10 @@ /* KallistiOS ##version## fs_iso9660.c - Copyright (C)2000,2001,2003 Dan Potter - Copyright (C)2001 Andrew Kieschnick - Copyright (C)2002 Bero + Copyright (C) 2000, 2001, 2003 Dan Potter + Copyright (C) 2001 Andrew Kieschnick + Copyright (C) 2002 Bero + Copyright (C) 2012 Lawrence Sebald */ @@ -40,6 +41,7 @@ #include <ctype.h> #include <string.h> #include <malloc.h> +#include <errno.h> static int init_percd(); static int percd_done; @@ -840,32 +842,66 @@ return 0; } +static int iso_fcntl(void *h, int cmd, va_list ap) { + file_t fd = (file_t)h; + int rv = -1; + + if(fd>=MAX_ISO_FILES || !fh[fd].first_extent || fh[fd].broken) { + errno = EBADF; + return -1; + } + + switch(cmd) { + case F_GETFL: + rv = O_RDONLY; + if(fh[fd].dir) + rv |= O_DIR; + break; + + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + /* Put everything together */ static vfs_handler_t vh = { - /* Name handler */ - { - "/cd", /* name */ - 0, /* tbfi */ - 0x00010000, /* Version 1.0 */ - 0, /* flags */ - NMMGR_TYPE_VFS, /* VFS handler */ - NMMGR_LIST_INIT - }, + /* Name handler */ + { + "/cd", /* name */ + 0, /* tbfi */ + 0x00010000, /* Version 1.0 */ + 0, /* flags */ + NMMGR_TYPE_VFS, /* VFS handler */ + NMMGR_LIST_INIT + }, - 0, NULL, /* no cacheing, privdata */ + 0, NULL, /* no cacheing, privdata */ - iso_open, - iso_close, - iso_read, - NULL, - iso_seek, - iso_tell, - iso_total, - iso_readdir, - iso_ioctl, - NULL, - NULL, - NULL + iso_open, + iso_close, + iso_read, + NULL, + iso_seek, + iso_tell, + iso_total, + iso_readdir, + iso_ioctl, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + iso_fcntl }; /* Initialize the file system */ Modified: kos/kernel/arch/dreamcast/fs/fs_vmu.c =================================================================== --- kos/kernel/arch/dreamcast/fs/fs_vmu.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/arch/dreamcast/fs/fs_vmu.c 2012-06-04 02:36:19 UTC (rev 797) @@ -1,7 +1,8 @@ /* KallistiOS ##version## fs_vmu.c - Copyright (C)2003 Dan Potter + Copyright (C) 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -17,6 +18,7 @@ #include <dc/maple.h> #include <dc/maple/vmu.h> #include <sys/queue.h> +#include <errno.h> /* @@ -541,35 +543,69 @@ return (rv->size < 0) ? -1 : 0; } +static int vmu_fcntl(void *fd, int cmd, va_list ap) { + vmu_fh_t *fh; + int rv = -1; + + /* Check the handle */ + if(!vmu_verify_hnd(fd, VMU_ANY)) { + errno = EBADF; + return -1; + } + + fh = (vmu_fh_t *)fd; + + switch(cmd) { + case F_GETFL: + if(fh->strtype) + rv = fh->mode; + else + rv = O_RDONLY | O_DIR; + break; + + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + /* handler interface */ static vfs_handler_t vh = { - /* Name handler */ - { - "/vmu", /* name */ - 0, /* tbfi */ - 0x00010000, /* Version 1.0 */ - 0, /* flags */ - NMMGR_TYPE_VFS, /* VFS handler */ - NMMGR_LIST_INIT - }, - 0, NULL, /* In-kernel, privdata */ + /* Name handler */ + { + "/vmu", /* name */ + 0, /* tbfi */ + 0x00010000, /* Version 1.0 */ + 0, /* flags */ + NMMGR_TYPE_VFS, /* VFS handler */ + NMMGR_LIST_INIT + }, + 0, NULL, /* In-kernel, privdata */ - vmu_open, - vmu_close, - vmu_read, - vmu_write, /* the write function */ - vmu_seek, /* the seek function */ - vmu_tell, - vmu_total, - vmu_readdir, /* readdir */ - NULL, /* ioctl */ - NULL, /* rename/move */ - vmu_unlink, /* unlink */ - vmu_mmap, /* mmap */ - NULL, /* complete */ - vmu_stat, /* stat */ - NULL, /* mkdir */ - NULL /* rmdir */ + vmu_open, + vmu_close, + vmu_read, + vmu_write, /* the write function */ + vmu_seek, /* the seek function */ + vmu_tell, + vmu_total, + vmu_readdir, /* readdir */ + NULL, /* ioctl */ + NULL, /* rename/move */ + vmu_unlink, /* unlink */ + vmu_mmap, /* mmap */ + NULL, /* complete */ + vmu_stat, /* stat */ + NULL, /* mkdir */ + NULL, /* rmdir */ + vmu_fcntl }; int fs_vmu_init() { Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/net/net_tcp.c 2012-06-04 02:36:19 UTC (rev 797) @@ -1869,6 +1869,11 @@ if(sock->flags & FS_SOCKET_NONBLOCK) rv |= O_NONBLOCK; goto out; + + case F_GETFD: + case F_SETFD: + rv = 0; + goto out; } errno = EINVAL; Modified: kos/kernel/net/net_udp.c =================================================================== --- kos/kernel/net/net_udp.c 2012-06-04 01:23:58 UTC (rev 796) +++ kos/kernel/net/net_udp.c 2012-06-04 02:36:19 UTC (rev 797) @@ -821,6 +821,11 @@ if(sock->flags & FS_SOCKET_NONBLOCK) rv |= O_NONBLOCK; goto out; + + case F_GETFD: + case F_SETFD: + rv = 0; + goto out; } errno = EINVAL; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-04 01:24:04
|
Revision: 796 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=796&view=rev Author: ljsebald Date: 2012-06-04 01:23:58 +0000 (Mon, 04 Jun 2012) Log Message: ----------- Add fcntl support to fs_romdisk, fs_ramdisk, and fs_pty. Modified Paths: -------------- kos/kernel/fs/fs_pty.c kos/kernel/fs/fs_ramdisk.c kos/kernel/fs/fs_romdisk.c Modified: kos/kernel/fs/fs_pty.c =================================================================== --- kos/kernel/fs/fs_pty.c 2012-06-03 20:38:30 UTC (rev 795) +++ kos/kernel/fs/fs_pty.c 2012-06-04 01:23:58 UTC (rev 796) @@ -2,6 +2,7 @@ fs_pty.c Copyright (C)2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -595,31 +596,72 @@ return &dl->dirent; } +static int pty_fcntl(void *h, int cmd, va_list ap) { + pipefd_t *fd = (pipefd_t *)h; + int rv = -1; + long val; + + if(!fd) { + errno = EBADF; + return -1; + } + + switch(cmd) { + case F_GETFL: + rv = fd->mode; + break; + + case F_SETFL: + val = va_arg(ap, long); + if(val & O_NONBLOCK) + fd->mode |= O_NONBLOCK; + else + fd->mode &= ~O_NONBLOCK; + rv = 0; + break; + + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + static vfs_handler_t vh = { - /* Name Handler */ - { - { "/pty" }, /* name */ - 0, /* in-kernel */ - 0x00010000, /* Version 1.0 */ - 0, /* flags */ - NMMGR_TYPE_VFS, /* VFS handler */ - NMMGR_LIST_INIT /* list */ - }, + /* Name Handler */ + { + { "/pty" }, /* name */ + 0, /* in-kernel */ + 0x00010000, /* Version 1.0 */ + 0, /* flags */ + NMMGR_TYPE_VFS, /* VFS handler */ + NMMGR_LIST_INIT /* list */ + }, - 0, NULL, /* no cacheing, privdata */ + 0, NULL, /* no cacheing, privdata */ - pty_open, - pty_close, - pty_read, - pty_write, - NULL, - NULL, - pty_total, - pty_readdir, - NULL, - NULL, - NULL, - NULL + pty_open, + pty_close, + pty_read, + pty_write, + NULL, + NULL, + pty_total, + pty_readdir, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + pty_fcntl }; /* Are we initialized? */ Modified: kos/kernel/fs/fs_ramdisk.c =================================================================== --- kos/kernel/fs/fs_ramdisk.c 2012-06-03 20:38:30 UTC (rev 795) +++ kos/kernel/fs/fs_ramdisk.c 2012-06-04 01:23:58 UTC (rev 796) @@ -2,6 +2,7 @@ fs_ramdisk.c Copyright (C)2002,2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -38,6 +39,7 @@ #include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <errno.h> /* File definition */ typedef struct rd_file { @@ -82,10 +84,11 @@ /* File handles.. I could probably do this with a linked list, but I'm just too lazy right now. =) */ static struct { - rd_file_t * file; /* ramdisk file struct */ - int dir; /* >0 if a directory */ - uint32 ptr; /* Current read position in bytes */ - dirent_t dirent; /* A static dirent to pass back to clients */ + rd_file_t *file; /* ramdisk file struct */ + int dir; /* >0 if a directory */ + uint32 ptr; /* Current read position in bytes */ + dirent_t dirent; /* A static dirent to pass back to clients */ + int omode; /* Open mode */ } fh[MAX_RAM_FILES]; /* Mutex for file system structs */ @@ -260,6 +263,7 @@ /* Fill the basic fd structure */ fh[fd].file = f; fh[fd].dir = mode & O_DIR; + fh[fd].omode = mode; /* The rest require a bit more thought */ switch (mm) { @@ -534,36 +538,68 @@ return rv; } +static int ramdisk_fcntl(void *h, int cmd, va_list ap) { + file_t fd = (file_t)h; + int rv = -1; + + mutex_lock(rd_mutex); + + if(fd >= MAX_RAM_FILES || !fh[fd].file) { + mutex_unlock(rd_mutex); + errno = EBADF; + return -1; + } + + switch(cmd) { + case F_GETFL: + rv = fh[fd].omode; + break; + + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + mutex_unlock(rd_mutex); + return rv; +} + /* Put everything together */ static vfs_handler_t vh = { - /* Name handler */ - { - "/ram", /* name */ - 0, /* tbfi */ - 0x00010000, /* Version 1.0 */ - 0, /* flags */ - NMMGR_TYPE_VFS, /* VFS handler */ - NMMGR_LIST_INIT - }, + /* Name handler */ + { + "/ram", /* name */ + 0, /* tbfi */ + 0x00010000, /* Version 1.0 */ + 0, /* flags */ + NMMGR_TYPE_VFS, /* VFS handler */ + NMMGR_LIST_INIT + }, - 0, NULL, /* no cacheing, privdata */ + 0, NULL, /* no cacheing, privdata */ - ramdisk_open, - ramdisk_close, - ramdisk_read, - ramdisk_write, - ramdisk_seek, - ramdisk_tell, - ramdisk_total, - ramdisk_readdir, - NULL, /* ioctl */ - NULL, /* rename XXX */ - ramdisk_unlink, - ramdisk_mmap, - NULL, /* complete */ - NULL, /* stat XXX */ - NULL, /* mkdir XXX */ - NULL /* rmdir XXX */ + ramdisk_open, + ramdisk_close, + ramdisk_read, + ramdisk_write, + ramdisk_seek, + ramdisk_tell, + ramdisk_total, + ramdisk_readdir, + NULL, /* ioctl */ + NULL, /* rename XXX */ + ramdisk_unlink, + ramdisk_mmap, + NULL, /* complete */ + NULL, /* stat XXX */ + NULL, /* mkdir XXX */ + NULL, /* rmdir XXX */ + ramdisk_fcntl }; /* Attach a piece of memory to a file. This works somewhat like open for Modified: kos/kernel/fs/fs_romdisk.c =================================================================== --- kos/kernel/fs/fs_romdisk.c 2012-06-03 20:38:30 UTC (rev 795) +++ kos/kernel/fs/fs_romdisk.c 2012-06-04 01:23:58 UTC (rev 796) @@ -2,6 +2,7 @@ fs_romdisk.c Copyright (C)2001,2002,2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -361,32 +362,66 @@ return (void *)(fh[fd].mnt->image + fh[fd].index); } +static int romdisk_fcntl(void *h, int cmd, va_list ap) { + file_t fd = (file_t)h; + int rv = -1; + + if(fd >= MAX_RD_FILES || !fh[fd].index) { + errno = EBADF; + return -1; + } + + switch(cmd) { + case F_GETFL: + rv = O_RDONLY; + if(fh[fd].dir) + rv |= O_DIR; + break; + + case F_SETFL: + case F_GETFD: + case F_SETFD: + rv = 0; + break; + + default: + errno = EINVAL; + } + + return rv; +} + /* This is a template that will be used for each mount */ static vfs_handler_t vh = { - /* Name Handler */ - { - { 0 }, /* name */ - 0, /* in-kernel */ - 0x00010000, /* Version 1.0 */ - NMMGR_FLAGS_NEEDSFREE, /* We malloc each VFS struct */ - NMMGR_TYPE_VFS, /* VFS handler */ - NMMGR_LIST_INIT /* list */ - }, + /* Name Handler */ + { + { 0 }, /* name */ + 0, /* in-kernel */ + 0x00010000, /* Version 1.0 */ + NMMGR_FLAGS_NEEDSFREE, /* We malloc each VFS struct */ + NMMGR_TYPE_VFS, /* VFS handler */ + NMMGR_LIST_INIT /* list */ + }, - 0, NULL, /* no cacheing, privdata */ + 0, NULL, /* no cacheing, privdata */ - romdisk_open, - romdisk_close, - romdisk_read, - NULL, - romdisk_seek, - romdisk_tell, - romdisk_total, - romdisk_readdir, - NULL, - NULL, - NULL, - romdisk_mmap + romdisk_open, + romdisk_close, + romdisk_read, + NULL, + romdisk_seek, + romdisk_tell, + romdisk_total, + romdisk_readdir, + NULL, + NULL, + NULL, + romdisk_mmap, + NULL, + NULL, + NULL, + NULL, + romdisk_fcntl }; /* Are we initialized? */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-03 20:38:38
|
Revision: 795 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=795&view=rev Author: ljsebald Date: 2012-06-03 20:38:30 +0000 (Sun, 03 Jun 2012) Log Message: ----------- 1. Add setsockopt(), getsockopt() and fs_fcntl() functions. 2. Provide a _fcntl_r() function for Newlib. The Newlib patch will need to be updated for this, but we need to actually support fcntl in the various fs modules first (otherwise we might break things). 3. Remove fs_socket_setflags(), since the only useful flag should be set through fs_fcntl()/fcntl(). Modified Paths: -------------- kos/include/kos/fs.h kos/include/kos/fs_socket.h kos/include/netinet/in.h kos/include/sys/socket.h kos/kernel/fs/fs.c kos/kernel/fs/fs_socket.c kos/kernel/libc/newlib/Makefile kos/kernel/net/net_dhcp.c kos/kernel/net/net_tcp.c kos/kernel/net/net_udp.c Added Paths: ----------- kos/kernel/libc/newlib/newlib_fcntl.c Modified: kos/include/kos/fs.h =================================================================== --- kos/include/kos/fs.h 2012-06-03 01:08:53 UTC (rev 794) +++ kos/include/kos/fs.h 2012-06-03 20:38:30 UTC (rev 795) @@ -1,7 +1,8 @@ /* KallistiOS ##version## kos/fs.h - Copyright (C)2000,2001,2002,2003 Dan Potter + Copyright (C) 2000, 2001, 2002, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -15,6 +16,7 @@ #include <kos/limits.h> #include <time.h> #include <sys/queue.h> +#include <stdarg.h> #include <kos/nmmgr.h> @@ -29,6 +31,7 @@ programs, feel free to use them to your heart's content! \author Dan Potter + \author Lawrence Sebald */ /** \brief Directory entry. @@ -161,6 +164,9 @@ /** \brief Remove a directory from the given VFS */ int (*rmdir)(struct vfs_handler *vfs, const char *fn); + + /** \brief Manipulate file control flags on the given file. */ + int (*fcntl)(void *fd, int cmd, va_list ap); } vfs_handler_t; /** \brief The number of distinct file descriptors that can be in use at a @@ -402,6 +408,17 @@ */ int fs_rmdir(const char *fn); +/** \brief Manipulate file control flags. + + This function implements the standard C fcntl function. + + \param fd The file descriptor to use. + \param cmd The command to run. + \param ... Arguments for the command specified. + \return -1 on error (generally). +*/ +int fs_fcntl(file_t fd, int cmd, ...); + /** \brief Duplicate a file descriptor. This function duplicates the specified file descriptor, returning a new file Modified: kos/include/kos/fs_socket.h =================================================================== --- kos/include/kos/fs_socket.h 2012-06-03 01:08:53 UTC (rev 794) +++ kos/include/kos/fs_socket.h 2012-06-03 20:38:30 UTC (rev 795) @@ -139,20 +139,6 @@ */ void (*close)(net_socket_t *hnd); - /** \brief Set flags on a socket created with the protocol. - - This function will be called when the user calls fs_socket_setflags() on - a socket created with this protocol. The semantics are the same as - described in the documentation for that function. - - \param s The socket to set flags on - \param flags The flags to set - \retval -1 On error (set errno appropriately) - \retval 0 On success - \see fs_socket_setflags - */ - int (*setflags)(net_socket_t *s, uint32_t flags); - /** \brief Accept a connection on a socket created with the protocol. This function should implement the ::accept() system call for the @@ -282,6 +268,58 @@ */ int (*input)(netif_t *src, int domain, const void *hdr, const uint8 *data, int size); + + /** \brief Get socket options. + + This function should implement the ::getsockopt() system call for the + given protocol. The semantics are exactly as defined for that function. + + Currently all options (regardless of level) are passed onto the + protocol handler. + + \param s The socket to get options for. + \param level The protocol level to get options at. + \param option_name The option to look up. + \param option_value Storage for the value of the option. + \param option_len The length of option_value on call, and the real + option length (if less than the original value) + on return. + \retval -1 On error (set errno appropriately). + \retval 0 On success. + */ + int (*getsockopt)(net_socket_t *s, int level, int option_name, + void *option_value, socklen_t *option_len); + + /** \brief Set socket options. + + This function should implement the ::setsockopt() system call for the + given protocol. The semantics are exactly as defined for that function. + + Currently all options (regardless of level) are passed onto the + protocol handler. + + \param s The socket to set options for. + \param level The protocol level to set options at. + \param option_name The option to set. + \param option_value The value to set for the option. + \param option_len The length of the option_value value. + \retval -1 On error (set errno appropriately). + \retval 0 On success. + */ + int (*setsockopt)(net_socket_t *s, int level, int option_name, + const void *option_value, socklen_t option_len); + + /** \brief Manipulate file options. + + This function should implement the ::fcntl() system call for the given + protocol. The semantics are exactly as defined for that function. + + \param s The socket to manipulate. + \param cmd The fcntl command to run. + \param ap Arguments to the command. + \retval -1 On error (generally, set errno appropriately). + */ + int (*fcntl)(net_socket_t *s, int cmd, va_list ap); } fs_socket_proto_t; /** \brief Initializer for the entry field in the fs_socket_proto_t struct. */ @@ -313,7 +351,7 @@ /** \defgroup sock_flags Socket flags - These are the available flags to set with the fs_socket_setflags() function. + These are the available flags defined for sockets. Every flag after FS_SOCKET_FAM_MAX is for internal-use only, and should never be passed into any functions. @@ -346,27 +384,6 @@ int fs_socket_input(netif_t *src, int domain, int protocol, const void *hdr, const uint8 *data, int size); -/** \brief Set flags on a socket file descriptor. - - This function can be used to set various flags on a socket file descriptor, - similar to what one would use fcntl or ioctl on a normal system for. The - flags available for use here are largely protocol dependent. - - \param sock The socket to operate on (returned from a call to the - function socket()) - \param flags The flags to set on the socket. - \retval -1 On error, and sets errno as appropriate - \retval 0 On success - \see sock_flags - - \par Error Conditions: - \em EWOULDBLOCK - if the function would block while inappropriate to \n - \em EBADF - if passed an invalid file descriptor \n - \em ENOTSOCK - if passed a file descriptor other than a socket \n - \em EINVAL - if an invalid flag (or combination) was passed in -*/ -int fs_socket_setflags(int sock, uint32_t flags); - /** \brief Add a new protocol for use with fs_socket. This function registers a protocol handler with fs_socket for use when Modified: kos/include/netinet/in.h =================================================================== --- kos/include/netinet/in.h 2012-06-03 01:08:53 UTC (rev 794) +++ kos/include/netinet/in.h 2012-06-03 20:38:30 UTC (rev 795) @@ -182,6 +182,44 @@ /** \brief Internet Protocol Version 6. */ #define IPPROTO_IPV6 41 +/** \defgroup ipv4_opts IPv4 protocol level options + + These are the various socket-level optoins that can be accessed with the + setsockopt() and getsockopt() fnctions for the IPPROTO_IP level value. + + As there isn't really a full standard list of these defined in the SUS + (apparently), only ones that we support are listed here. + + \see so_opts + \see ipv6_opts + + @{ +*/ +#define IP_TTL 24 /**< \brief TTL for unicast (get/set) */ +/** @} */ + +/** \defgroup ipv6_opts IPv6 protocol level options + + These are the various socket-level options that can be accessed with the + setsockopt() and getsockopt() functions for the IPPROTO_IPV6 level value. + + Not all of these are currently supported, but they are listed for + completeness. + + \see so_opts + \see ipv4_opts + + @{ +*/ +#define IPV6_JOIN_GROUP 17 /**< \brief Join a multicast group (set) */ +#define IPV6_LEAVE_GROUP 18 /**< \brief Leave a multicast group (set) */ +#define IPV6_MULTICAST_HOPS 19 /**< \brief Hop limit for multicast (get/set) */ +#define IPV6_MULTICAST_IF 20 /**< \brief Multicast interface (get/set) */ +#define IPV6_MULTICAST_LOOP 21 /**< \brief Multicasts loopback (get/set) */ +#define IPV6_UNICAST_HOPS 22 /**< \brief Hop limit for unicast (get/set) */ +#define IPV6_V6ONLY 23 /**< \brief IPv6 only -- no IPv4 (get/set) */ +/** @} */ + /** \brief Test if an IPv6 Address is unspecified. This macro tests whether an IPv6 address (struct in6_addr *) is an Modified: kos/include/sys/socket.h =================================================================== --- kos/include/sys/socket.h 2012-06-03 01:08:53 UTC (rev 794) +++ kos/include/sys/socket.h 2012-06-03 20:38:30 UTC (rev 795) @@ -1,7 +1,7 @@ /* KallistiOS ##version## sys/socket.h - Copyright (C)2006, 2010 Lawrence Sebald + Copyright (C)2006, 2010, 2012 Lawrence Sebald */ @@ -96,6 +96,44 @@ */ #define SOCK_STREAM 2 +/** \brief Socket-level option setting. + + This constant should be used with the setsockopt() or getsockopt() function + to represent that options should be accessed at the socket level, not the + protocol level. +*/ +#define SOL_SOCKET 1 + +/** \defgroup so_opts Socket-level options + + These are the various socket-level options that can be accessed with the + setsockopt() and getsockopt() functions for the SOL_SOCKET level value. + + Not all of these are currently supported, but they are listed for + completeness. + + \see ipv6_opts + + @{ +*/ +#define SO_ACCEPTCONN 1 /**< \brief Socket is accepting connections (get) */ +#define SO_BROADCAST 2 /**< \brief Support broadcasting (get/set) */ +#define SO_DEBUG 3 /**< \brief Record debugging info (get/set) */ +#define SO_DONTROUTE 4 /**< \brief Do not route packets (get/set) */ +#define SO_ERROR 5 /**< \brief Retrieve error status (get) */ +#define SO_KEEPALIVE 6 /**< \brief Send keepalive messages (get/set) */ +#define SO_LINGER 7 /**< \brief Socket lingers on close (get/set) */ +#define SO_OOBINLINE 8 /**< \brief OOB data is inline (get/set) */ +#define SO_RCVBUF 9 /**< \brief Receive buffer size (get/set) */ +#define SO_RCVLOWAT 10 /**< \brief Receive low-water mark (get/set) */ +#define SO_RCVTIMEO 11 /**< \brief Receive timeout value (get/set) */ +#define SO_REUSEADDR 12 /**< \brief Reuse local addresses (get/set) */ +#define SO_SNDBUF 13 /**< \brief Send buffer size (get/set) */ +#define SO_SNDLOWAT 14 /**< \brief Send low-water mark (get/set) */ +#define SO_SNDTIMEO 15 /**< \brief Send timeout value (get/set) */ +#define SO_TYPE 16 /**< \brief Socket type (get) */ +/** @} */ + /** \brief Internet domain sockets for use with IPv4 addresses. */ #define AF_INET 1 @@ -272,6 +310,46 @@ */ int socket(int domain, int type, int protocol); +/** \brief Get socket options. + + This function retrieves options associated with a socket. This function + shall attempt to retrieve the specified option (at the specified level) from + the given socket. + + \param sock The socket to get options for. + \param level The protocol level to get options at. + \param option_name The option to look up. + \param option_value Storage for the value of the option. + \param option_len The length of option_value on call, and the real + option length (if less than the original value) + on return. + \return Zero on success. -1 on error, and sets errno as + appropriate. + + \see so_opts +*/ +int getsockopt(int socket, int level, int option_name, void *option_value, + socklen_t *option_len); + +/** \brief Set socket options. + + This function sets options associated with a socket. This function shall + attempt to set the specified option (at the specified level) from the given + socket. + + \param sock The socket to set options for. + \param level The protocol level to set options at. + \param option_name The option to set. + \param option_value The value to set for the option. + \param option_len The length of option_value in bytes. + \return Zero on success. -1 on error, and sets errno as + appropriate. + + \see so_opts +*/ +int setsockopt(int socket, int level, int option_name, const void *option_value, + socklen_t option_len); + __END_DECLS #endif /* __SYS_SOCKET_H */ Modified: kos/kernel/fs/fs.c =================================================================== --- kos/kernel/fs/fs.c 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/fs/fs.c 2012-06-03 20:38:30 UTC (rev 795) @@ -1,7 +1,8 @@ /* KallistiOS ##version## fs.c - Copyright (C)2000,2001,2002,2003 Dan Potter + Copyright (C) 2000, 2001, 2002, 2003 Dan Potter + Copyright (C) 2012 Lawrence Sebald */ @@ -567,7 +568,27 @@ } } +int fs_fcntl(file_t fd, int cmd, ...) { + fs_hnd_t *h = fs_map_hnd(fd); + va_list ap; + int rv; + if(!h) { + errno = EBADF; + return -1; + } + if(!h->handler || !h->handler->fcntl) { + errno = ENOSYS; + return -1; + } + + va_start(ap, cmd); + rv = h->handler->fcntl(h->hnd, cmd, ap); + va_end(ap); + + return rv; +} + /* Initialize FS structures */ int fs_init() { return 0; Modified: kos/kernel/fs/fs_socket.c =================================================================== --- kos/kernel/fs/fs_socket.c 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/fs/fs_socket.c 2012-06-03 20:38:30 UTC (rev 795) @@ -74,6 +74,11 @@ return sock->protocol->sendto(sock, buffer, cnt, 0, NULL, 0); } +static int fs_socket_fcntl(void *hnd, int cmd, va_list ap) { + net_socket_t *sock = (net_socket_t *)hnd; + return sock->protocol->fcntl(sock, cmd, ap); +} + /* VFS handler */ static vfs_handler_t vh = { /* Name handler */ @@ -103,7 +108,8 @@ NULL, /* complete */ NULL, /* stat */ NULL, /* mkdir */ - NULL /* rmdir */ + NULL, /* rmdir */ + fs_socket_fcntl /* fcntl */ }; /* Have we been initialized? */ @@ -197,24 +203,6 @@ return rv; } -int fs_socket_setflags(int sock, uint32_t flags) { - net_socket_t *hnd; - - hnd = (net_socket_t *)fs_get_handle(sock); - if(hnd == NULL) { - errno = EBADF; - return -1; - } - - /* Make sure this is actually a socket. */ - if(fs_get_handler(sock) != &vh) { - errno = ENOTSOCK; - return -1; - } - - return hnd->protocol->setflags(hnd, flags); -} - int fs_socket_proto_add(fs_socket_proto_t *proto) { if(!initted) return -1; @@ -547,3 +535,43 @@ return hnd->protocol->shutdownsock(hnd, how); } + +int getsockopt(int sock, int level, int option_name, void *option_value, + socklen_t *option_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *)fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + /* Make sure this is actually a socket. */ + if(fs_get_handler(sock) != &vh) { + errno = ENOTSOCK; + return -1; + } + + return hnd->protocol->getsockopt(hnd, level, option_name, option_value, + option_len); +} + +int setsockopt(int sock, int level, int option_name, const void *option_value, + socklen_t option_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *)fs_get_handle(sock); + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + /* Make sure this is actually a socket. */ + if(fs_get_handler(sock) != &vh) { + errno = ENOTSOCK; + return -1; + } + + return hnd->protocol->setsockopt(hnd, level, option_name, option_value, + option_len); +} Modified: kos/kernel/libc/newlib/Makefile =================================================================== --- kos/kernel/libc/newlib/Makefile 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/libc/newlib/Makefile 2012-06-03 20:38:30 UTC (rev 795) @@ -18,7 +18,7 @@ newlib_gettimeofday.o newlib_isatty.o newlib_kill.o newlib_link.o \ newlib_lseek.o newlib_malloc.o newlib_open.o \ newlib_read.o newlib_sbrk.o newlib_stat.o newlib_times.o \ - newlib_unlink.o newlib_wait.o newlib_write.o \ + newlib_unlink.o newlib_wait.o newlib_write.o newlib_fcntl.o \ verify_newlib.o include $(KOS_BASE)/Makefile.prefab Added: kos/kernel/libc/newlib/newlib_fcntl.c =================================================================== --- kos/kernel/libc/newlib/newlib_fcntl.c (rev 0) +++ kos/kernel/libc/newlib/newlib_fcntl.c 2012-06-03 20:38:30 UTC (rev 795) @@ -0,0 +1,16 @@ +/* KallistiOS ##version## + + newlib_fcntl.c + Copyright (C) 2012 Lawrence Sebald + +*/ + +#include <sys/reent.h> +#include <sys/fcntl.h> +#include <stdarg.h> + +#include <kos/fs.h> + +int _fcntl_r(struct _reent *reent, int fd, int cmd, int arg) { + return fs_fcntl(fd, cmd, arg); +} Modified: kos/kernel/net/net_dhcp.c =================================================================== --- kos/kernel/net/net_dhcp.c 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/net/net_dhcp.c 2012-06-03 20:38:30 UTC (rev 795) @@ -627,23 +627,23 @@ } /* Bind the socket to the DHCP "Client" port */ + memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(DHCP_CLIENT_PORT); addr.sin_addr.s_addr = INADDR_ANY; - memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); if(bind(dhcp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { return -2; } /* Set up the server address */ + memset(&srv_addr, 0, sizeof(srv_addr)); srv_addr.sin_family = AF_INET; srv_addr.sin_port = htons(DHCP_SERVER_PORT); srv_addr.sin_addr.s_addr = INADDR_BROADCAST; - memset(srv_addr.sin_zero, 0, sizeof(addr.sin_zero)); /* Make the socket non-blocking */ - fs_socket_setflags(dhcp_sock, FS_SOCKET_NONBLOCK); + fs_fcntl(dhcp_sock, F_SETFL, O_NONBLOCK); /* Create the callback for processing DHCP packets */ dhcp_cbid = net_thd_add_callback(&net_dhcp_thd, NULL, 50); Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/net/net_tcp.c 2012-06-03 20:38:30 UTC (rev 795) @@ -141,6 +141,9 @@ file_t sock; int state; mutex_t *mutex; + int hop_limit; + uint32_t rcvbuf_sz; + uint32_t sndbuf_sz; union { struct { @@ -156,12 +159,10 @@ struct sndrec snd; struct rcvrec rcv; uint8_t *rcvbuf; - uint32_t rcvbuf_sz; uint32_t rcvbuf_cur_sz; uint32_t rcvbuf_head; uint32_t rcvbuf_tail; uint8_t *sndbuf; - uint32_t sndbuf_sz; uint32_t sndbuf_cur_sz; uint32_t sndbuf_head; uint32_t sndbuf_acked; @@ -193,6 +194,9 @@ /* Default retransmission timeout (in milliseconds). */ #define TCP_DEFAULT_RTTO 2000 +/* Default hop limit (or ttl for IPv4) for new sockets */ +#define TCP_DEFAULT_HOPS 64 + /* Flags that can be set in the off_flags field of the above struct */ #define TCP_FLAG_FIN 0x01 #define TCP_FLAG_SYN 0x02 @@ -266,6 +270,9 @@ sock->domain = domain; sock->sock = hnd->fd; + sock->hop_limit = TCP_DEFAULT_HOPS; + sock->rcvbuf_sz = TCP_DEFAULT_WINDOW; + sock->sndbuf_sz = TCP_DEFAULT_WINDOW; if(irq_inside_int()) { if(rwsem_write_trylock(tcp_sem)) { @@ -434,49 +441,6 @@ return; } -static int net_tcp_setflags(net_socket_t *hnd, uint32_t flags) { - struct tcp_sock *sock; - - if(irq_inside_int()) { - if(rwsem_read_trylock(tcp_sem)) { - errno = EWOULDBLOCK; - return -1; - } - } - else { - rwsem_read_lock(tcp_sem); - } - - if(!(sock = (struct tcp_sock *)hnd->data)) { - rwsem_read_unlock(tcp_sem); - errno = EBADF; - return -1; - } - - if(irq_inside_int()) { - if(mutex_trylock(sock->mutex)) { - errno = EWOULDBLOCK; - return -1; - } - } - else { - mutex_lock(sock->mutex); - } - - if(flags & (~FS_SOCKET_NONBLOCK)) { - mutex_unlock(sock->mutex); - rwsem_read_unlock(tcp_sem); - errno = EINVAL; - return -1; - } - - sock->flags |= flags; - mutex_unlock(sock->mutex); - rwsem_read_unlock(tcp_sem); - - return 0; -} - static int net_tcp_accept(net_socket_t *hnd, struct sockaddr *addr, socklen_t *addr_len) { struct tcp_sock *sock, *sock2; @@ -589,7 +553,7 @@ return -1; } - if(!(sock2->data.rcvbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + if(!(sock2->data.rcvbuf = (uint8_t *)malloc(sock->rcvbuf_sz))) { errno = ENOMEM; mutex_unlock(sock->mutex); mutex_destroy(sock2->mutex); @@ -597,7 +561,7 @@ return -1; } - if(!(sock2->data.sndbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + if(!(sock2->data.sndbuf = (uint8_t *)malloc(sock->sndbuf_sz))) { errno = ENOMEM; mutex_unlock(sock->mutex); free(sock2->data.rcvbuf); @@ -645,6 +609,10 @@ sock2->state = TCP_STATE_SYN_RECEIVED; sock2->local_addr = lsock.local_addr; sock2->remote_addr = lsock.remote_addr; + sock2->hop_limit = sock->hop_limit; + sock2->rcvbuf_sz = sock->rcvbuf_sz; + sock2->sndbuf_sz = sock->sndbuf_sz; + sock2->data.rcv.wnd = sock->rcvbuf_sz; /* Fill in the address, if they asked for it. */ if(addr != NULL) { @@ -745,9 +713,6 @@ sock2->data.snd.mss = lsock.mss; sock2->data.rcv.nxt = lsock.isn + 1; sock2->data.rcv.irs = lsock.isn; - sock2->data.rcv.wnd = TCP_DEFAULT_WINDOW; - sock2->data.rcvbuf_sz = TCP_DEFAULT_WINDOW; - sock2->data.sndbuf_sz = TCP_DEFAULT_WINDOW; /* Since nothing else has a pointer to this socket, this will not fail. */ mutex_trylock(sock2->mutex); @@ -1107,14 +1072,14 @@ includes setting up all the data we need for that). */ sock->remote_addr = realaddr6; - if(!(sock->data.rcvbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + if(!(sock->data.rcvbuf = (uint8_t *)malloc(sock->rcvbuf_sz))) { errno = ENOBUFS; mutex_unlock(sock->mutex); rwsem_write_unlock(tcp_sem); return -1; } - if(!(sock->data.sndbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + if(!(sock->data.sndbuf = (uint8_t *)malloc(sock->sndbuf_sz))) { errno = ENOBUFS; mutex_unlock(sock->mutex); rwsem_write_unlock(tcp_sem); @@ -1141,9 +1106,7 @@ return -1; } - sock->data.rcv.wnd = TCP_DEFAULT_WINDOW; - sock->data.rcvbuf_sz = TCP_DEFAULT_WINDOW; - sock->data.sndbuf_sz = TCP_DEFAULT_WINDOW; + sock->data.rcv.wnd = sock->rcvbuf_sz; sock->data.rcvbuf_head = sock->data.rcvbuf_tail = 0; sock->data.net = net_default_dev; sock->data.snd.iss = timer_us_gettime64() >> 2; @@ -1372,15 +1335,15 @@ sock->data.rcv.wnd += size; sock->data.rcvbuf_cur_sz -= size; - if(sock->data.rcvbuf_head + size <= sock->data.rcvbuf_sz) { + if(sock->data.rcvbuf_head + size <= sock->rcvbuf_sz) { memcpy(buf, rb, size); sock->data.rcvbuf_head += size; - if(sock->data.rcvbuf_head == sock->data.rcvbuf_sz) + if(sock->data.rcvbuf_head == sock->rcvbuf_sz) sock->data.rcvbuf_head = 0; } else { - tmp = sock->data.rcvbuf_sz - sock->data.rcvbuf_head; + tmp = sock->rcvbuf_sz - sock->data.rcvbuf_head; memcpy(buf, rb, tmp); memcpy(buf + tmp, sock->data.rcvbuf, size - tmp); sock->data.rcvbuf_head = size - tmp; @@ -1516,7 +1479,7 @@ } /* See if we have space to buffer at least some of the data... */ - if(sock->data.sndbuf_cur_sz == sock->data.sndbuf_sz) { + if(sock->data.sndbuf_cur_sz == sock->sndbuf_sz) { if((sock->flags & FS_SOCKET_NONBLOCK) || irq_inside_int()) { errno = EWOULDBLOCK; size = -1; @@ -1527,7 +1490,7 @@ /* If we still don't have any buffer space, its because the connection has either been closed or reset by the other side... */ - if(sock->data.sndbuf_cur_sz == sock->data.sndbuf_sz) { + if(sock->data.sndbuf_cur_sz == sock->sndbuf_sz) { if(sock->state & TCP_STATE_RESET) { errno = ECONNRESET; size = -1; @@ -1547,7 +1510,7 @@ sock->data.sndbuf_tail = 0; /* Figure out how much we can copy in */ - bsz = sock->data.sndbuf_sz - sock->data.sndbuf_cur_sz; + bsz = sock->sndbuf_sz - sock->data.sndbuf_cur_sz; if(length > bsz) size = bsz; @@ -1557,15 +1520,15 @@ sb = sock->data.sndbuf + sock->data.sndbuf_tail; sock->data.sndbuf_cur_sz += size; - if(sock->data.sndbuf_tail + size <= sock->data.sndbuf_sz) { + if(sock->data.sndbuf_tail + size <= sock->sndbuf_sz) { memcpy(sb, buf, size); sock->data.sndbuf_tail += size; - if(sock->data.sndbuf_tail == sock->data.sndbuf_sz) + if(sock->data.sndbuf_tail == sock->sndbuf_sz) sock->data.sndbuf_tail = 0; } else { - tmp = sock->data.sndbuf_sz - sock->data.sndbuf_tail; + tmp = sock->sndbuf_sz - sock->data.sndbuf_tail; memcpy(sb, buf, tmp); memcpy(sock->data.sndbuf, buf + tmp, size - tmp); sock->data.sndbuf_tail = size - tmp; @@ -1624,6 +1587,298 @@ return 0; } +static int net_tcp_getsockopt(net_socket_t *hnd, int level, int option_name, + void *option_value, socklen_t *option_len) { + int tmp; + struct tcp_sock *sock; + + if(!option_value || !option_len) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + switch(level) { + case SOL_SOCKET: + switch(option_name) { + case SO_ACCEPTCONN: + tmp = sock->state == TCP_STATE_LISTEN; + goto copy_int; + + case SO_RCVBUF: + tmp = sock->rcvbuf_sz; + goto copy_int; + + case SO_SNDBUF: + tmp = sock->sndbuf_sz; + goto copy_int; + + case SO_TYPE: + tmp = SOCK_STREAM; + goto copy_int; + } + + break; + + case IPPROTO_IP: + if(sock->domain != AF_INET) + goto ret_inval; + + switch(option_name) { + case IP_TTL: + tmp = sock->hop_limit; + goto copy_int; + } + + break; + + case IPPROTO_IPV6: + if(sock->domain != AF_INET6) + goto ret_inval; + + switch(option_name) { + case IPV6_UNICAST_HOPS: + tmp = sock->hop_limit; + goto copy_int; + + case IPV6_V6ONLY: + tmp = !!(sock->flags & FS_SOCKET_V6ONLY); + goto copy_int; + } + } + + /* If it wasn't handled, return that errror. */ + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = ENOPROTOOPT; + return -1; + +ret_inval: + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EINVAL; + return -1; + +copy_int: + if(*option_len >= sizeof(int)) { + memcpy(option_value, &tmp, sizeof(int)); + *option_len = sizeof(int); + } + else { + memcpy(option_value, &tmp, *option_len); + } + + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + return 0; +} + +static int net_tcp_setsockopt(net_socket_t *hnd, int level, int option_name, + const void *option_value, socklen_t option_len) { + struct tcp_sock *sock; + int tmp; + + if(!option_value || !option_len) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + switch(level) { + case SOL_SOCKET: + switch(option_name) { + case SO_ACCEPTCONN: + case SO_ERROR: + case SO_TYPE: + goto ret_inval; + } + + break; + + case IPPROTO_IP: + if(sock->domain != AF_INET) + goto ret_inval; + + switch(option_name) { + case IP_TTL: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp < -1 || tmp > 255) + goto ret_inval; + else if(tmp == -1) + sock->hop_limit = TCP_DEFAULT_HOPS; + else + sock->hop_limit = tmp; + goto ret_success; + } + + break; + + case IPPROTO_IPV6: + if(sock->domain != AF_INET6) + goto ret_inval; + + switch(option_name) { + case IPV6_UNICAST_HOPS: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp < -1 || tmp > 255) + goto ret_inval; + else if(tmp == -1) + sock->hop_limit = TCP_DEFAULT_HOPS; + else + sock->hop_limit = tmp; + goto ret_success; + + case IPV6_V6ONLY: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp) + sock->flags |= FS_SOCKET_V6ONLY; + else + sock->flags &= ~FS_SOCKET_V6ONLY; + goto ret_success; + } + + break; + } + + /* If it wasn't handled, return that errror. */ + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = ENOPROTOOPT; + return -1; + +ret_inval: + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EINVAL; + return -1; + +ret_success: + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + return 0; +} + +static int net_tcp_fcntl(net_socket_t *hnd, int cmd, va_list ap) { + + struct tcp_sock *sock; + int rv = -1; + long val; + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + /* Lock the socket's mutex, since we're going to be manipulating its state + in here... */ + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + switch(cmd) { + case F_SETFL: + val = va_arg(ap, long); + if(val & O_NONBLOCK) + sock->flags |= FS_SOCKET_NONBLOCK; + else + sock->flags &= ~FS_SOCKET_NONBLOCK; + rv = 0; + goto out; + + case F_GETFL: + rv = O_RDWR; + if(sock->flags & FS_SOCKET_NONBLOCK) + rv |= O_NONBLOCK; + goto out; + } + + errno = EINVAL; + +out: + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + return rv; +} + static void tcp_rst(netif_t *net, const struct in6_addr *src, const struct in6_addr *dst, uint16_t src_port, uint16_t dst_port, uint16_t flags, uint32_t seq, @@ -1722,8 +1977,9 @@ sizeof(tcp_hdr_t) + 4, IPPROTO_TCP); hdr->checksum = net_ipv4_checksum(rawpkt, sizeof(tcp_hdr_t) + 4, cs); - return net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t) + 4, 0, - IPPROTO_TCP, &sock->local_addr.sin6_addr, + return net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t) + 4, + sock->hop_limit, IPPROTO_TCP, + &sock->local_addr.sin6_addr, &sock->remote_addr.sin6_addr); } @@ -1748,8 +2004,9 @@ sizeof(tcp_hdr_t), IPPROTO_TCP); hdr->checksum = net_ipv4_checksum(rawpkt, sizeof(tcp_hdr_t), cs); - net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t), 0, IPPROTO_TCP, - &sock->local_addr.sin6_addr, &sock->remote_addr.sin6_addr); + net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t), sock->hop_limit, + IPPROTO_TCP, &sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr); } static void tcp_send_ack(struct tcp_sock *sock) { @@ -1772,8 +2029,8 @@ sizeof(tcp_hdr_t), IPPROTO_TCP); hdr.checksum = net_ipv4_checksum((const uint8 *)&hdr, sizeof(tcp_hdr_t), c); - net_ipv6_send(sock->data.net, (const uint8 *)&hdr, sizeof(tcp_hdr_t), 0, - IPPROTO_TCP, &sock->local_addr.sin6_addr, + net_ipv6_send(sock->data.net, (const uint8 *)&hdr, sizeof(tcp_hdr_t), + sock->hop_limit, IPPROTO_TCP, &sock->local_addr.sin6_addr, &sock->remote_addr.sin6_addr); } @@ -1823,15 +2080,15 @@ snd = sock->data.sndbuf_cur_sz - unacked; /* Copy in the data */ - if(head + snd <= sock->data.sndbuf_sz) { + if(head + snd <= sock->sndbuf_sz) { memcpy(buf, sb, snd); head += snd; - if(head == sock->data.sndbuf_sz) + if(head == sock->sndbuf_sz) head = 0; } else { - sz = sock->data.sndbuf_sz - head; + sz = sock->sndbuf_sz - head; memcpy(buf, sb, sz); memcpy(buf + sz, sock->data.sndbuf, snd - sz); head = snd - sz; @@ -1848,7 +2105,7 @@ IPPROTO_TCP); hdr->checksum = net_ipv4_checksum(rawpkt, sz, cs); - net_ipv6_send(sock->data.net, rawpkt, sz, 0, IPPROTO_TCP, + net_ipv6_send(sock->data.net, rawpkt, sz, sock->hop_limit, IPPROTO_TCP, &sock->local_addr.sin6_addr, &sock->remote_addr.sin6_addr); } @@ -2198,8 +2455,8 @@ s->data.snd.una = ack; cond_signal(s->data.send_cv); - if(s->data.sndbuf_acked >= s->data.sndbuf_sz) - s->data.sndbuf_acked -= s->data.sndbuf_sz; + if(s->data.sndbuf_acked >= s->sndbuf_sz) + s->data.sndbuf_acked -= s->sndbuf_sz; if(SEQ_LT(s->data.snd.wl1, seq) || (s->data.snd.wl1 == seq && SEQ_LE(s->data.snd.wl2, ack))) { @@ -2276,12 +2533,12 @@ s->data.rcv.wnd -= sz; s->data.rcvbuf_cur_sz += sz; - if(s->data.rcvbuf_tail + sz <= s->data.rcvbuf_sz) { + if(s->data.rcvbuf_tail + sz <= s->rcvbuf_sz) { memcpy(rb, buf, sz); s->data.rcvbuf_tail += sz; } else { - tmp = s->data.rcvbuf_sz - s->data.rcvbuf_tail; + tmp = s->rcvbuf_sz - s->data.rcvbuf_tail; memcpy(rb, buf, tmp); sz -= tmp; buf += tmp; @@ -2543,7 +2800,6 @@ IPPROTO_TCP, /* protocol */ net_tcp_socket, /* socket */ net_tcp_close, /* close */ - net_tcp_setflags, /* setflags */ net_tcp_accept, /* accept */ net_tcp_bind, /* bind */ net_tcp_connect, /* connect */ @@ -2551,7 +2807,10 @@ net_tcp_recvfrom, /* recvfrom */ net_tcp_sendto, /* sendto */ net_tcp_shutdownsock, /* shutdown */ - net_tcp_input /* input */ + net_tcp_input, /* input */ + net_tcp_getsockopt, /* getsockopt */ + net_tcp_setsockopt, /* setsockopt */ + net_tcp_fcntl /* fcntl */ }; int net_tcp_init() { Modified: kos/kernel/net/net_udp.c =================================================================== --- kos/kernel/net/net_udp.c 2012-06-03 01:08:53 UTC (rev 794) +++ kos/kernel/net/net_udp.c 2012-06-03 20:38:30 UTC (rev 795) @@ -21,6 +21,9 @@ #include "net_ipv4.h" #include "net_ipv6.h" +/* Default hop limit (or ttl for IPv4) for new sockets */ +#define UDP_DEFAULT_HOPS 64 + #define packed __attribute__((packed)) typedef struct { uint16 src_port packed; @@ -46,6 +49,7 @@ uint32 flags; int domain; + int hop_limit; struct udp_pkt_queue packets; }; @@ -58,7 +62,7 @@ static int net_udp_send_raw(netif_t *net, const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, const uint8 *data, - int size, int flags); + int size, int flags, int hops); static int net_udp_accept(net_socket_t *hnd, struct sockaddr *addr, socklen_t *addr_len) { @@ -488,7 +492,8 @@ mutex_unlock(udp_mutex); return net_udp_send_raw(NULL, &local_addr, &realaddr6, - (const uint8 *)message, length, sflags); + (const uint8 *)message, length, sflags, + udpsock->hop_limit); err: mutex_unlock(udp_mutex); return -1; @@ -539,6 +544,7 @@ memset(udpsock, 0, sizeof(struct udp_sock)); TAILQ_INIT(&udpsock->packets); udpsock->domain = domain; + udpsock->hop_limit = UDP_DEFAULT_HOPS; if(irq_inside_int()) { if(mutex_trylock(udp_mutex) == -1) { @@ -591,8 +597,10 @@ mutex_unlock(udp_mutex); } -static int net_udp_setflags(net_socket_t *hnd, uint32_t flags) { - struct udp_sock *udpsock; +static int net_udp_getsockopt(net_socket_t *hnd, int level, int option_name, + void *option_value, socklen_t *option_len) { + struct udp_sock *sock; + int tmp; if(irq_inside_int()) { if(mutex_trylock(udp_mutex) == -1) { @@ -604,25 +612,224 @@ mutex_lock(udp_mutex); } - udpsock = (struct udp_sock *) hnd->data; - if(udpsock == NULL) { + if(!(sock = (struct udp_sock *)hnd->data)) { mutex_unlock(udp_mutex); errno = EBADF; return -1; } - if(flags & (~FS_SOCKET_NONBLOCK)) { + switch(level) { + case SOL_SOCKET: + switch(option_name) { + case SO_ACCEPTCONN: + tmp = 0; + goto copy_int; + + case SO_TYPE: + tmp = SOCK_DGRAM; + goto copy_int; + } + + break; + + case IPPROTO_IP: + if(sock->domain != AF_INET) + goto ret_inval; + + switch(option_name) { + case IP_TTL: + tmp = sock->hop_limit; + goto copy_int; + } + + break; + + case IPPROTO_IPV6: + if(sock->domain != AF_INET6) + goto ret_inval; + + switch(option_name) { + case IPV6_UNICAST_HOPS: + tmp = sock->hop_limit; + goto copy_int; + + case IPV6_V6ONLY: + tmp = !!(sock->flags & FS_SOCKET_V6ONLY); + goto copy_int; + } + + break; + } + + /* If it wasn't handled, return that error. */ + mutex_unlock(udp_mutex); + errno = ENOPROTOOPT; + return -1; + +ret_inval: + mutex_unlock(udp_mutex); + errno = EINVAL; + return -1; + +copy_int: + if(*option_len >= sizeof(int)) { + memcpy(option_value, &tmp, sizeof(int)); + *option_len = sizeof(int); + } + else { + memcpy(option_value, &tmp, *option_len); + } + + mutex_unlock(udp_mutex); + return 0; +} + +static int net_udp_setsockopt(net_socket_t *hnd, int level, int option_name, + const void *option_value, socklen_t option_len) { + struct udp_sock *sock; + int tmp; + + if(irq_inside_int()) { + if(mutex_trylock(udp_mutex) == -1) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(udp_mutex); + } + + if(!(sock = (struct udp_sock *)hnd->data)) { mutex_unlock(udp_mutex); - errno = EINVAL; + errno = EBADF; return -1; } - udpsock->flags |= flags; + switch(level) { + case SOL_SOCKET: + switch(option_name) { + case SO_ACCEPTCONN: + case SO_ERROR: + case SO_TYPE: + goto ret_inval; + } + + break; + + case IPPROTO_IP: + if(sock->domain != AF_INET) + goto ret_inval; + + switch(option_name) { + case IP_TTL: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp < -1 || tmp > 255) + goto ret_inval; + else if(tmp == -1) + sock->hop_limit = UDP_DEFAULT_HOPS; + else + sock->hop_limit = tmp; + goto ret_success; + } + + break; + + case IPPROTO_IPV6: + if(sock->domain != AF_INET6) + goto ret_inval; + + switch(option_name) { + case IPV6_UNICAST_HOPS: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp < -1 || tmp > 255) + goto ret_inval; + else if(tmp == -1) + sock->hop_limit = UDP_DEFAULT_HOPS; + else + sock->hop_limit = tmp; + goto ret_success; + + case IPV6_V6ONLY: + if(option_len != sizeof(int)) + goto ret_inval; + + tmp = *((int *)option_value); + if(tmp) + sock->flags |= FS_SOCKET_V6ONLY; + else + sock->flags &= ~FS_SOCKET_V6ONLY; + goto ret_success; + } + + break; + } + + /* If it wasn't handled, return that error. */ mutex_unlock(udp_mutex); + errno = ENOPROTOOPT; + return -1; +ret_inval: + mutex_unlock(udp_mutex); + errno = EINVAL; + return -1; + +ret_success: + mutex_unlock(udp_mutex); return 0; } +static int net_udp_fcntl(net_socket_t *hnd, int cmd, va_list ap) { + struct udp_sock *sock; + long val; + int rv = -1; + + if(irq_inside_int()) { + if(mutex_trylock(udp_mutex) == -1) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(udp_mutex); + } + + if(!(sock = (struct udp_sock *)hnd->data)) { + mutex_unlock(udp_mutex); + errno = EBADF; + return -1; + } + + switch(cmd) { + case F_SETFL: + val = va_arg(ap, long); + if(val & O_NONBLOCK) + sock->flags |= FS_SOCKET_NONBLOCK; + else + sock->flags &= ~FS_SOCKET_NONBLOCK; + rv = 0; + goto out; + + case F_GETFL: + rv = O_RDWR; + if(sock->flags & FS_SOCKET_NONBLOCK) + rv |= O_NONBLOCK; + goto out; + } + + errno = EINVAL; + +out: + mutex_unlock(udp_mutex); + return rv; +} + static int net_udp_input4(netif_t *src, const ip_hdr_t *ip, const uint8 *data, int size) { udp_hdr_t *hdr = (udp_hdr_t *)data; @@ -823,7 +1030,7 @@ static int net_udp_send_raw(netif_t *net, const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, const uint8 *data, - int size, int flags) { + int size, int flags, int hops) { uint8 buf[size + sizeof(udp_hdr_t)]; udp_hdr_t *hdr = (udp_hdr_t *)buf; uint16 cs; @@ -883,7 +1090,7 @@ hdr->checksum = net_ipv4_checksum(buf, size, cs); /* Pass everything off to the network layer to do the rest. */ - err = net_ipv6_send(net, buf, size, 0, IPPROTO_UDP, &srcaddr, + err = net_ipv6_send(net, buf, size, hops, IPPROTO_UDP, &srcaddr, &dst->sin6_addr); if(err < 0) { ++udp_stats.pkt_send_failed; @@ -907,7 +1114,6 @@ IPPROTO_UDP, /* protocol */ net_udp_socket, net_udp_close, - net_udp_setflags, net_udp_accept, net_udp_bind, net_udp_connect, @@ -915,7 +1121,10 @@ net_udp_recvfrom, net_udp_sendto, net_udp_shutdownsock, - net_udp_input + net_udp_input, + net_udp_getsockopt, + net_udp_setsockopt, + net_udp_fcntl }; int net_udp_init() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ljs...@us...> - 2012-06-03 01:09:01
|
Revision: 794 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=794&view=rev Author: ljsebald Date: 2012-06-03 01:08:53 +0000 (Sun, 03 Jun 2012) Log Message: ----------- Hrm, I wonder what this is. ;-) Modified Paths: -------------- kos/kernel/net/net_ipv4.c kos/kernel/net/net_tcp.c Modified: kos/kernel/net/net_ipv4.c =================================================================== --- kos/kernel/net/net_ipv4.c 2012-06-02 03:33:00 UTC (rev 793) +++ kos/kernel/net/net_ipv4.c 2012-06-03 01:08:53 UTC (rev 794) @@ -165,7 +165,7 @@ /* Send it away */ net->if_tx(net, pkt, sizeof(ip_hdr_t) + size + sizeof(eth_hdr_t), - NETIF_BLOCK); + NETIF_BLOCK); return 0; } Modified: kos/kernel/net/net_tcp.c =================================================================== --- kos/kernel/net/net_tcp.c 2012-06-02 03:33:00 UTC (rev 793) +++ kos/kernel/net/net_tcp.c 2012-06-03 01:08:53 UTC (rev 794) @@ -6,15 +6,88 @@ */ #include <errno.h> +#include <stdlib.h> +#include <string.h> #include <stdint.h> #include <sys/socket.h> +#include <kos/fs.h> #include <kos/net.h> +#include <kos/cond.h> +#include <kos/mutex.h> +#include <kos/rwsem.h> #include <kos/fs_socket.h> +#include <arch/timer.h> + +#include <kos/dbglog.h> + #include "net_ipv4.h" #include "net_ipv6.h" +#include "net_thd.h" +/* Since some of this is a bit odd in its implementation, here's a few notes on + what my thinking was while writing all of this... + + On IRQs: + All of the functions in here should be relatively IRQ-safe. That doesn't mean + its a particularly good idea to use sockets all over the place in IRQs, but + it is possible. I *strongly* recommend not closing sockets in an IRQ, since + there are ways that can fail if it is done during an IRQ. I also recommend + not calling socket(), listen(), or accept() in an IRQ. All of these functions + allocate memory, which is not exactly the best idea in an IRQ for various + reasons. Any functions called in an IRQ may return error and set errno to + EWOULDBLOCK, even if they are not on non-blocking sockets. All socket calls + in an IRQ context *MUST* be non-blocking, since we don't have any way to + suspend an IRQ while its being processed. + + On locking: + I took a two-leveled locking approach when writing all of this code. The + first-level of locking is on the list of sockets itself. This is done with a + reader/writer semaphore. If the function in question will ever modify the + list of sockets in any way, it acquires the write lock. Otherwise, it will + always acquire the read lock. The second level of locking is on the + individual socket level. This is done with a standard mutex. When looking at + an individual socket, grab that mutex in addition to the read or write lock, + as is appropriate. The only function that is somewhat counter-intuitive in + its locking is bind(). The bind() function, even though it does not modify + the list itself, does grab the write lock. The reason for this is fairly + simple. If bind() were to grab the read lock, then iterate through the list + of sockets looking for duplicate binds, there is a possibility that a second + call to bind() in another thread could cause a deadlock due to the locking + and unlocking of the mutexes on the individual sockets. To prevent this + problem, I have it grab the write lock instead. That way, no two bind() calls + can be active at a time. + + On listening: + When a connection comes in for a socket that is in the listening state, that + connection will have some state saved about it and it will be added to the + listening socket's queue for listening connections, assuming there is space + for it in there. Otherwise, it'll simply be reset, as should be expected. + The positive side effect of this is that all sockets should be created + outside of IRQ context (unless you're crazy enough to make one in an IRQ + handler in your own code), since incoming connections do not actually have a + real socket created for them until they are accept()ed. + + On matching sockets: + All new sockets (including those created by accept()) are added to the head + of the list. Since we cannot bind a socket to an already used port for + listening, that means that any fully-created sockets should appear in the + list in front of those created for listening to a port (and thus that are + only partially-created). This simplifies the procedure for finding matching + sockets for incoming packets, since this makes sure that the fully-created + socket will be found first if it exists when simply iterating through the + list of sockets. + + On what's actually here: + I didn't bother implementing any TCP extensions beyond RFC 793. That means + that I just ignore things like the timestamp option and the selective + acknowledgement option. That also means that the window size maxes out at + 65535. Some extensions may be implemented in the future, if I see fit to do + so. That all said, everything in here works just fine over IPv4 or IPv6, and + can be used just fine to communicate with "normal" TCP/IP implementations. +*/ + typedef struct tcp_hdr { uint16_t src_port; uint16_t dst_port; @@ -24,8 +97,102 @@ uint16_t wnd; uint16_t checksum; uint16_t urg; + uint8_t options[]; } __attribute__((packed)) tcp_hdr_t; +/* Listening socket. Each one of these is an incoming connection from a socket + that is in the listen state */ +struct lsock { + netif_t *net; + struct sockaddr_in6 local_addr; + struct sockaddr_in6 remote_addr; + uint32_t isn; + uint32_t wnd; + uint16_t mss; +}; + +/* Send/receive variables... */ +struct sndrec { + uint32_t una; + uint32_t nxt; + uint32_t wnd; + uint32_t up; + uint32_t wl1; + uint32_t wl2; + uint32_t iss; + uint16_t mss; +}; + +struct rcvrec { + uint32_t nxt; + uint32_t wnd; + uint32_t up; + uint32_t irs; +}; + +struct tcp_sock { + LIST_ENTRY(tcp_sock) sock_list; + struct sockaddr_in6 local_addr; + struct sockaddr_in6 remote_addr; + + uint32_t flags; + uint32_t intflags; + int domain; + file_t sock; + int state; + mutex_t *mutex; + + union { + struct { + int backlog; + int head; + int tail; + int count; + struct lsock *queue; + condvar_t *cv; + } listen; + struct { + netif_t *net; + struct sndrec snd; + struct rcvrec rcv; + uint8_t *rcvbuf; + uint32_t rcvbuf_sz; + uint32_t rcvbuf_cur_sz; + uint32_t rcvbuf_head; + uint32_t rcvbuf_tail; + uint8_t *sndbuf; + uint32_t sndbuf_sz; + uint32_t sndbuf_cur_sz; + uint32_t sndbuf_head; + uint32_t sndbuf_acked; + uint32_t sndbuf_tail; + uint64_t timer; + condvar_t *send_cv; + condvar_t *recv_cv; + } data; + }; +}; + +LIST_HEAD(tcp_sock_list, tcp_sock); + +static struct tcp_sock_list tcp_socks = LIST_HEAD_INITIALIZER(0); +static rw_semaphore_t *tcp_sem = NULL; +static int thd_cb_id = 0; + +/* Default starting window size for connections. This should be big enough as a + starting point, in general. If you need to adjust it, you can do so... */ +#define TCP_DEFAULT_WINDOW 8192 + +/* Default MSS */ +#define TCP_DEFAULT_MSS 1460 + +/* Default Maximum Segment Lifetime (in milliseconds). I arbitrarily chose this + to be 15 seconds, since that's what Mac OS X does. */ +#define TCP_DEFAULT_MSL 15000 + +/* Default retransmission timeout (in milliseconds). */ +#define TCP_DEFAULT_RTTO 2000 + /* Flags that can be set in the off_flags field of the above struct */ #define TCP_FLAG_FIN 0x01 #define TCP_FLAG_SYN 0x02 @@ -37,64 +204,1451 @@ #define TCP_GET_OFFSET(x) (((x) & 0xF000) >> 10) #define TCP_OFFSET(y) (((y) & 0x0F) << 12) -/* Sockets interface. These are all stubs at the moment. */ +#define TCP_STATE_CLOSED 0 +#define TCP_STATE_LISTEN 1 +#define TCP_STATE_SYN_SENT 2 +#define TCP_STATE_SYN_RECEIVED 3 +#define TCP_STATE_ESTABLISHED 4 +#define TCP_STATE_FIN_WAIT_1 5 +#define TCP_STATE_FIN_WAIT_2 6 +#define TCP_STATE_CLOSE_WAIT 7 +#define TCP_STATE_CLOSING 8 +#define TCP_STATE_LAST_ACK 9 +#define TCP_STATE_TIME_WAIT 10 + +#define TCP_STATE_RESET 0x80000000 +#define TCP_STATE_ACCEPTING 0x40000000 + +/* Internal flags */ +#define TCP_IFLAG_CANBEDEL 0x00000001 +#define TCP_IFLAG_QUEUEDCLOSE 0x00000002 +#define TCP_IFLAG_ACCEPTWAIT 0x00000004 + +#define TCP_OPT_EOL 0 +#define TCP_OPT_NOP 1 +#define TCP_OPT_MSS 2 + +/* A few macros for comparing sequence numbers */ +#define SEQ_LT(x, y) (((int32_t)((x) - (y))) < 0) +#define SEQ_LE(x, y) (((int32_t)((x) - (y))) <= 0) +#define SEQ_GT(x, y) (((int32_t)((x) - (y))) > 0) +#define SEQ_GE(x, y) (((int32_t)((x) - (y))) >= 0) + +#define MAX(x, y) (x > y ? x : y) + +/* Forward declarations */ +static fs_socket_proto_t proto; +static void tcp_rst(netif_t *net, const struct in6_addr *src, + const struct in6_addr *dst, uint16_t src_port, + uint16_t dst_port, uint16_t flags, uint32_t seq, + uint32_t ack); +static int tcp_send_syn(struct tcp_sock *sock, int ack); +static void tcp_send_ack(struct tcp_sock *sock); +static void tcp_send_data(struct tcp_sock *sock, int resend); +static void tcp_send_fin_ack(struct tcp_sock *sock); + +/* Sockets interface... */ static int net_tcp_socket(net_socket_t *hnd, int domain, int type, int proto) { - errno = EPROTONOSUPPORT; - return -1; + struct tcp_sock *sock; + + if(!(sock = (struct tcp_sock *)malloc(sizeof(struct tcp_sock)))) { + errno = ENOMEM; + return -1; + } + + memset(sock, 0, sizeof(struct tcp_sock)); + + if(!(sock->mutex = mutex_create())) { + errno = ENOMEM; + free(sock); + return -1; + } + + sock->domain = domain; + sock->sock = hnd->fd; + + if(irq_inside_int()) { + if(rwsem_write_trylock(tcp_sem)) { + free(sock); + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_write_lock(tcp_sem); + } + + hnd->data = sock; + + LIST_INSERT_HEAD(&tcp_socks, sock, sock_list); + rwsem_write_unlock(tcp_sem); + + return 0; } static void net_tcp_close(net_socket_t *hnd) { - errno = EBADF; + struct tcp_sock *sock; + struct lsock *ls; + int i; + +retry: + if(irq_inside_int()) { + if(rwsem_write_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return; + } + } + else { + rwsem_write_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_write_unlock(tcp_sem); + errno = EBADF; + return; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + errno = EWOULDBLOCK; + rwsem_write_unlock(tcp_sem); + return; + } + } + else { + mutex_lock(sock->mutex); + } + + /* This is to work-around the ugly issue discussed in the accept() function. + This is... well, bad... Granted, you really shouldn't ever have this + happening if you're sane... */ + if(sock->state == (TCP_STATE_LISTEN | TCP_STATE_ACCEPTING)) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + + if(irq_inside_int()) { + errno = EWOULDBLOCK; + return; + } + + thd_pass(); + goto retry; + } + + /* Deal with queued data and/or connections and sending the closing messages + as appropriate. */ + switch(sock->state) { + case TCP_STATE_LISTEN: + for(i = sock->listen.head; i < sock->listen.tail; ++i) { + ls = sock->listen.queue + i; + + /* Reset the connection */ + tcp_rst(ls->net, &ls->local_addr.sin6_addr, + &ls->remote_addr.sin6_addr, ls->local_addr.sin6_port, + ls->remote_addr.sin6_port, TCP_FLAG_ACK | TCP_FLAG_RST, + 0, ls->isn + 1); + } + + /* If we were waiting on an accept call, then we have to let it + handle tearing down the connection... */ + if(sock->intflags & TCP_IFLAG_ACCEPTWAIT) { + sock->state = TCP_STATE_CLOSED; + goto ret_no_remove; + } + + free(sock->listen.queue); + cond_destroy(sock->listen.cv); + goto ret_remove; + + case TCP_STATE_SYN_SENT: + free(sock->data.rcvbuf); + free(sock->data.sndbuf); + cond_destroy(sock->data.send_cv); + cond_destroy(sock->data.recv_cv); + goto ret_remove; + + case TCP_STATE_ESTABLISHED: + /* See if all sends have finished... */ + if(sock->data.sndbuf_cur_sz) { + goto ret_no_remove; + } + + /* Fall through... */ + + case TCP_STATE_SYN_RECEIVED: + /* Don't have to worry about queued packets, since we don't allow + any queueing until after the connection is established. */ + tcp_send_fin_ack(sock); + ++sock->data.snd.nxt; + sock->state = TCP_STATE_FIN_WAIT_1; + goto ret_no_remove; + + case TCP_STATE_CLOSE_WAIT: + /* See if all sends have finished... */ + if(sock->data.sndbuf_cur_sz) { + goto ret_no_remove; + } + + tcp_send_fin_ack(sock); + ++sock->data.snd.nxt; + sock->state = TCP_STATE_CLOSING; + goto ret_no_remove; + + case TCP_STATE_CLOSED | TCP_STATE_RESET: + goto ret_no_remove; + + case TCP_STATE_FIN_WAIT_1: + case TCP_STATE_FIN_WAIT_2: + goto ret_no_remove; + + case TCP_STATE_CLOSING: + case TCP_STATE_LAST_ACK: + case TCP_STATE_TIME_WAIT: + /* Uh... shouldn't get here... */ + dbglog(DBG_KDEBUG, "close() on TCP socket in invalid state!\n"); + goto ret_no_remove; + } + +ret_remove: + LIST_REMOVE(sock, sock_list); + mutex_unlock(sock->mutex); + mutex_destroy(sock->mutex); + free(sock); + + rwsem_write_unlock(tcp_sem); + return; + +ret_no_remove: + if(sock->state != TCP_STATE_LISTEN) + sock->intflags = TCP_IFLAG_CANBEDEL; + + if(sock->state == TCP_STATE_ESTABLISHED || + sock->state == TCP_STATE_CLOSE_WAIT) + sock->intflags |= TCP_IFLAG_QUEUEDCLOSE; + sock->sock = -1; + + /* Don't free anything here, it will be dealt with later on in the + net_thd callback. */ + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + return; } static int net_tcp_setflags(net_socket_t *hnd, uint32_t flags) { - errno = EBADF; - return -1; + struct tcp_sock *sock; + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + if(flags & (~FS_SOCKET_NONBLOCK)) { + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + sock->flags |= flags; + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + + return 0; } static int net_tcp_accept(net_socket_t *hnd, struct sockaddr *addr, socklen_t *addr_len) { - errno = EBADF; - return -1; + struct tcp_sock *sock, *sock2; + net_socket_t *newhnd; + struct lsock lsock; + int canblock = 1; + int fd; + + if(addr != NULL && addr_len == NULL) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + /* Lock the mutex on the socket itself first. We need to pull some data from + it that doesn't affect the rest of the list, so let's start there... */ + if(!(sock = (struct tcp_sock *)hnd->data)) { + errno = EBADF; + rwsem_read_unlock(tcp_sem); + return -1; + } + + if(irq_inside_int()) { + canblock = 0; + + if(mutex_trylock(sock->mutex)) { + errno = EWOULDBLOCK; + rwsem_read_unlock(tcp_sem); + return -1; + } + } + else { + mutex_lock(sock->mutex); + canblock = !(sock->flags & FS_SOCKET_NONBLOCK); + } + + rwsem_read_unlock(tcp_sem); + + /* Make sure the socket is listening... */ + if(sock->state != TCP_STATE_LISTEN) { + errno = EINVAL; + mutex_unlock(sock->mutex); + return -1; + } + + /* See if there are any waiting connections... */ + while(!sock->listen.count) { + if(!canblock) { + errno = EWOULDBLOCK; + mutex_unlock(sock->mutex); + return -1; + } + + /* There are no waiting connections and we can block, so block while we + wait for an incoming connection. */ + sock->intflags |= TCP_IFLAG_ACCEPTWAIT; + cond_wait(sock->listen.cv, sock->mutex); + + /* If we come out of the wait in the closed state, that means that the + user has run a close() on the socket in another thread. Bail out in a + graceful fashion. */ + if(sock->state == TCP_STATE_CLOSED) { + mutex_unlock(sock->mutex); + rwsem_write_lock(tcp_sem); + mutex_lock(sock->mutex); + free(sock->listen.queue); + cond_destroy(sock->listen.cv); + LIST_REMOVE(sock, sock_list); + mutex_unlock(sock->mutex); + mutex_destroy(sock->mutex); + free(sock); + + rwsem_write_unlock(tcp_sem); + + errno = EINTR; /* Close enough, I suppose. */ + return -1; + } + } + + /* We now have a connection to use, so, lets grab it and release the lock on + the old socket. */ + lsock = sock->listen.queue[sock->listen.head++]; + --sock->listen.count; + + if(sock->listen.head == sock->listen.backlog) + sock->listen.head = 0; + + /* Allocate the memory we will need... */ + if(!(sock2 = (struct tcp_sock *)malloc(sizeof(struct tcp_sock)))) { + mutex_unlock(sock->mutex); + errno = ENOMEM; + return -1; + } + + memset(sock2, 0, sizeof(struct tcp_sock)); + + if(!(sock2->mutex = mutex_create())) { + mutex_unlock(sock->mutex); + errno = ENOMEM; + free(sock2); + return -1; + } + + if(!(sock2->data.rcvbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + errno = ENOMEM; + mutex_unlock(sock->mutex); + mutex_destroy(sock2->mutex); + free(sock2); + return -1; + } + + if(!(sock2->data.sndbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + errno = ENOMEM; + mutex_unlock(sock->mutex); + free(sock2->data.rcvbuf); + mutex_destroy(sock2->mutex); + free(sock2); + return -1; + } + + if(!(sock2->data.send_cv = cond_create())) { + errno = ENOMEM; + mutex_unlock(sock->mutex); + free(sock2->data.sndbuf); + free(sock2->data.rcvbuf); + mutex_destroy(sock2->mutex); + free(sock2); + return -1; + } + + if(!(sock2->data.recv_cv = cond_create())) { + errno = ENOMEM; + mutex_unlock(sock->mutex); + cond_destroy(sock2->data.send_cv); + free(sock2->data.sndbuf); + free(sock2->data.rcvbuf); + mutex_destroy(sock2->mutex); + free(sock2); + return -1; + } + + /* Create a partial socket */ + if(!(newhnd = fs_socket_open_sock(&proto))) { + mutex_unlock(sock->mutex); + cond_destroy(sock2->data.recv_cv); + cond_destroy(sock2->data.send_cv); + free(sock2->data.sndbuf); + free(sock2->data.rcvbuf); + mutex_destroy(sock2->mutex); + free(sock2); + return -1; + } + + /* Fill in the important parts */ + sock2->domain = sock->domain; + sock2->sock = newhnd->fd; + sock2->state = TCP_STATE_SYN_RECEIVED; + sock2->local_addr = lsock.local_addr; + sock2->remote_addr = lsock.remote_addr; + + /* Fill in the address, if they asked for it. */ + if(addr != NULL) { + if(sock2->domain == AF_INET) { + struct sockaddr_in realaddr; + + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + sock2->remote_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock2->remote_addr.sin6_port; + + if(*addr_len < sizeof(struct sockaddr_in)) { + memcpy(addr, &realaddr, *addr_len); + } + else { + memcpy(addr, &realaddr, sizeof(struct sockaddr_in)); + *addr_len = sizeof(struct sockaddr_in); + } + } + else if(sock2->domain == AF_INET6) { + struct sockaddr_in6 realaddr6; + + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr = sock2->remote_addr.sin6_addr; + realaddr6.sin6_port = sock2->remote_addr.sin6_port; + + if(*addr_len < sizeof(struct sockaddr_in6)) { + memcpy(addr, &realaddr6, *addr_len); + } + else { + memcpy(addr, &realaddr6, sizeof(struct sockaddr_in6)); + *addr_len = sizeof(struct sockaddr_in6); + } + } + } + + if(irq_inside_int()) { + if(rwsem_write_trylock(tcp_sem)) { + /* Kabuki dance to clean things up... */ + mutex_unlock(sock->mutex); + + newhnd->protocol = NULL; + fs_close(sock2->sock); + cond_destroy(sock2->data.recv_cv); + cond_destroy(sock2->data.send_cv); + free(sock2->data.sndbuf); + free(sock2->data.rcvbuf); + mutex_destroy(sock2->mutex); + free(sock2); + errno = EWOULDBLOCK; + return -1; + } + } + /* Ugh... I really need to find a better way to deal with this... There is + a possibility (however slight) that between here and when the write lock + is locked that we might get a SYN packet again for this connection that + might end up screwing something up later. Honestly, I can't think of any + non-hackish way of dealing with this that would not result in a possible + deadlock. + + Anyone have any ideas? The only two possibilities that I can think of are + either doing the actual work of building sockets in the IRQ when the + listening socket gets the incoming SYN or holding the write lock through + this whole function. Both open up their own cans of worms, so to speak... + The first one means we need to be able to do socket() calls reliably in + an IRQ, which I really don't want to touch. The second would essentially + mean that during an accept() where we end up blocking waiting for an + incoming connection, no other socket write operations can take place. + That is absolutely unacceptable. Locking the write lock right here, + before releasing the socket lock would create the possibility of a + deadlock in bind() or close(). + + The hacked-up solution here basically means that the socket can't accept + any more SYNs for queueing until the socket actually gets added to the + list of sockets... Not really a very good solution, but it should do the + trick until I can come up with something else to do. Note that this also + means that calling accept() with the same socket in two threads is + unacceptable (and the second one will probably end up with an EINVAL + error because of this). */ + else { + sock->state |= TCP_STATE_ACCEPTING; + mutex_unlock(sock->mutex); + rwsem_write_lock(tcp_sem); + mutex_lock(sock->mutex); + } + + newhnd->data = sock2; + + /* Bad way of generating an initial sequence number, but techincally correct + by the wording of the RFC... */ + sock2->data.snd.iss = (uint32_t)(timer_us_gettime64() >> 2); + sock2->data.snd.nxt = sock2->data.snd.iss + 1; + sock2->data.snd.una = sock2->data.snd.iss; + sock2->data.snd.wnd = lsock.wnd; + sock2->data.snd.wl1 = sock2->data.snd.iss; + sock2->data.snd.mss = lsock.mss; + sock2->data.rcv.nxt = lsock.isn + 1; + sock2->data.rcv.irs = lsock.isn; + sock2->data.rcv.wnd = TCP_DEFAULT_WINDOW; + sock2->data.rcvbuf_sz = TCP_DEFAULT_WINDOW; + sock2->data.sndbuf_sz = TCP_DEFAULT_WINDOW; + + /* Since nothing else has a pointer to this socket, this will not fail. */ + mutex_trylock(sock2->mutex); + + /* Send the <SYN,ACK> packet now, add it to the list, and clean up. */ + tcp_send_syn(sock2, 1); + sock2->data.timer = timer_ms_gettime64(); + fd = sock2->sock; + LIST_INSERT_HEAD(&tcp_socks, sock2, sock_list); + mutex_unlock(sock2->mutex); + + sock->state &= ~TCP_STATE_ACCEPTING; + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + + return fd; } static int net_tcp_bind(net_socket_t *hnd, const struct sockaddr *addr, socklen_t addr_len) { - errno = EBADF; - return -1; + struct tcp_sock *sock, *iter; + struct sockaddr_in *realaddr4; + struct sockaddr_in6 realaddr6; + + /* Verify the parameters sent in first */ + if(addr == NULL) { + errno = EDESTADDRREQ; + return -1; + } + + switch(addr->sa_family) { + case AF_INET: + if(addr_len != sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Grab the IPv4 address struct and convert it to IPv6 */ + realaddr4 = (struct sockaddr_in *)addr; + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_port = realaddr4->sin_port; + + if(realaddr4->sin_addr.s_addr != INADDR_ANY) { + realaddr6.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + realaddr6.sin6_addr.__s6_addr.__s6_addr32[3] = + realaddr4->sin_addr.s_addr; + } + else { + realaddr6.sin6_addr = in6addr_any; + } + break; + + case AF_INET6: + if(addr_len != sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + realaddr6 = *((struct sockaddr_in6 *)addr); + break; + + default: + errno = EAFNOSUPPORT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_write_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_write_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_write_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + /* Make sure the socket is still in the closed state and hasn't already been + bound. */ + if(sock->state == TCP_STATE_LISTEN) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + else if(sock->state != TCP_STATE_CLOSED) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EISCONN; + return -1; + } + else if(sock->local_addr.sin6_port) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + /* Make sure the address family we're binding to matches that which is set + on the socket itself */ + if(addr->sa_family != sock->domain) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + /* See if we requested a specific port or not */ + if(realaddr6.sin6_port != 0) { + /* Make sure we don't already have a socket bound to the port + specified */ + LIST_FOREACH(iter, &tcp_socks, sock_list) { + if(iter == sock) + continue; + + if(irq_inside_int()) { + if(mutex_trylock(iter->mutex)) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(iter->mutex); + } + + if(iter->local_addr.sin6_port == realaddr6.sin6_port) { + mutex_unlock(iter->mutex); + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EADDRINUSE; + return -1; + } + + mutex_unlock(iter->mutex); + } + + sock->local_addr = realaddr6; + } + else { + uint16_t port = 1024, tmp = 0; + + /* Grab the first unused port >= 1024. This is, unfortunately, O(n^2) */ + while(tmp != port) { + tmp = port; + + LIST_FOREACH(iter, &tcp_socks, sock_list) { + if(iter == sock) + continue; + + if(irq_inside_int()) { + if(mutex_trylock(iter->mutex)) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(iter->mutex); + } + + if(iter->local_addr.sin6_port == port) { + ++port; + break; + } + + mutex_unlock(iter->mutex); + } + } + + sock->local_addr = realaddr6; + sock->local_addr.sin6_port = htons(port); + } + + /* Release the locks, we're done */ + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + + return 0; } static int net_tcp_connect(net_socket_t *hnd, const struct sockaddr *addr, socklen_t addr_len) { - errno = EBADF; - return -1; + struct tcp_sock *sock, *iter; + struct sockaddr_in *realaddr4; + struct sockaddr_in6 realaddr6; + + if(addr == NULL) { + errno = EDESTADDRREQ; + return -1; + } + + if(!net_default_dev) { + errno = ENETDOWN; + return -1; + } + + switch(addr->sa_family) { + case AF_INET: + if(addr_len != sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Grab the IPv4 address struct and convert it to IPv6 */ + realaddr4 = (struct sockaddr_in *)addr; + + if(realaddr4->sin_addr.s_addr == INADDR_ANY) { + errno = EADDRNOTAVAIL; + return -1; + } + + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_port = realaddr4->sin_port; + realaddr6.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + realaddr6.sin6_addr.__s6_addr.__s6_addr32[3] = + realaddr4->sin_addr.s_addr; + break; + + case AF_INET6: + if(addr_len != sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + realaddr6 = *((struct sockaddr_in6 *)addr); + break; + + default: + errno = EAFNOSUPPORT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_write_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_write_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_write_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + /* Make sure the socket is still in the CLOSED state */ + if(sock->state != TCP_STATE_CLOSED) { + if(sock->state == TCP_STATE_LISTEN) { + errno = EOPNOTSUPP; + } + else if(sock->state == TCP_STATE_SYN_SENT) { + errno = EALREADY; + } + else { + errno = EISCONN; + } + + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + return -1; + } + + /* Make sure the address family we're binding to matches that which is set + on the socket itself */ + if(addr->sa_family != sock->domain) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + /* Make sure we have a valid address to connect to */ + if(IN6_IS_ADDR_UNSPECIFIED(&realaddr6.sin6_addr) || + realaddr6.sin6_port == 0) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EADDRNOTAVAIL; + return -1; + } + + /* See if the socket is already bound to a local port */ + if(!sock->local_addr.sin6_port) { + uint16_t port = 1024, tmp = 0; + + /* Grab the first unused port >= 1024. This is, unfortunately, O(n^2) */ + while(tmp != port) { + tmp = port; + + LIST_FOREACH(iter, &tcp_socks, sock_list) { + if(iter == sock) + continue; + + if(irq_inside_int()) { + if(mutex_trylock(iter->mutex)) { + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(iter->mutex); + } + + if(iter->local_addr.sin6_port == port) { + ++port; + break; + } + + mutex_unlock(iter->mutex); + } + } + + sock->local_addr.sin6_port = htons(port); + + if(addr->sa_family == AF_INET) { + sock->local_addr.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + sock->local_addr.sin6_addr.__s6_addr.__s6_addr32[3] = + htonl(net_ipv4_address(net_default_dev->ip_addr)); + } + } + + /* Set the remote address on the socket and go to the SYN-SENT state (this + includes setting up all the data we need for that). */ + sock->remote_addr = realaddr6; + + if(!(sock->data.rcvbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + errno = ENOBUFS; + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + return -1; + } + + if(!(sock->data.sndbuf = (uint8_t *)malloc(TCP_DEFAULT_WINDOW))) { + errno = ENOBUFS; + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + free(sock->data.rcvbuf); + return -1; + } + + if(!(sock->data.send_cv = cond_create())) { + errno = ENOBUFS; + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + free(sock->data.sndbuf); + free(sock->data.rcvbuf); + return -1; + } + + if(!(sock->data.recv_cv = cond_create())) { + errno = ENOBUFS; + mutex_unlock(sock->mutex); + rwsem_write_unlock(tcp_sem); + cond_destroy(sock->data.send_cv); + free(sock->data.sndbuf); + free(sock->data.rcvbuf); + return -1; + } + + sock->data.rcv.wnd = TCP_DEFAULT_WINDOW; + sock->data.rcvbuf_sz = TCP_DEFAULT_WINDOW; + sock->data.sndbuf_sz = TCP_DEFAULT_WINDOW; + sock->data.rcvbuf_head = sock->data.rcvbuf_tail = 0; + sock->data.net = net_default_dev; + sock->data.snd.iss = timer_us_gettime64() >> 2; + sock->data.snd.una = sock->data.snd.iss; + sock->data.snd.nxt = sock->data.snd.iss + 1; + sock->state = TCP_STATE_SYN_SENT; + + /* Send a <SYN> packet */ + if(tcp_send_syn(sock, 0) == -1) { + rwsem_write_unlock(tcp_sem); + mutex_unlock(sock->mutex); + return -1; + } + + /* Release the write lock... */ + rwsem_write_unlock(tcp_sem); + + /* Now, lets see if this is socket is non-blocking... */ + if(sock->flags & FS_SOCKET_NONBLOCK || irq_inside_int()) { + /* We can't wait for the connection, so let them know it is in + progress... */ + mutex_unlock(sock->mutex); + errno = EINPROGRESS; + return -1; + } + + /* Block until the connection can be established... */ + if(cond_wait_timed(sock->data.send_cv, sock->mutex, 2 * TCP_DEFAULT_MSL)) { + errno = ETIMEDOUT; + sock->state = TCP_STATE_CLOSED; + mutex_unlock(sock->mutex); + return -1; + } + + if(sock->state & TCP_STATE_RESET) { + errno = ECONNREFUSED; + mutex_unlock(sock->mutex); + return -1; + } + + mutex_unlock(sock->mutex); + return 0; } static int net_tcp_listen(net_socket_t *hnd, int backlog) { - errno = EBADF; - return -1; + struct tcp_sock *sock; + + /* Clamp the backlog between some sane values */ + if(backlog > SOMAXCONN) + backlog = SOMAXCONN; + else if(backlog <= 0) + backlog = 1; + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + /* Lock the socket's mutex, since we're going to be manipulating its state + in here... */ + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + /* Make sure the socket is still in the closed state, otherwise we can't + actually move it to the listening state */ + if(sock->state != TCP_STATE_CLOSED) { + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + /* Make sure the socket has been bound */ + if(!sock->local_addr.sin6_port) { + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EDESTADDRREQ; + return -1; + } + + /* Allocate the queue and set up everything */ + sock->listen.queue = (struct lsock *)malloc(sizeof(struct lsock) * backlog); + if(!sock->listen.queue) { + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = ENOBUFS; + return -1; + } + + if(!(sock->listen.cv = cond_create())) { + free(sock->listen.queue); + sock->listen.queue = NULL; + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = ENOBUFS; + return -1; + } + + sock->listen.backlog = backlog; + sock->listen.head = sock->listen.tail = 0; + sock->state = TCP_STATE_LISTEN; + + /* We're done now, clean up the locks */ + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + + return 0; } static ssize_t net_tcp_recvfrom(net_socket_t *hnd, void *buffer, size_t length, int flags, struct sockaddr *addr, socklen_t *addr_len) { - errno = EBADF; - return -1; + struct tcp_sock *sock; + ssize_t size = 0; + uint8_t *buf = (uint8_t *)buffer; + uint8_t *rb; + int tmp; + + /* Check the parameters first */ + if(buffer == NULL || (addr != NULL && addr_len == NULL)) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + /* Lock the socket's mutex, since we're going to be manipulating its state + in here... */ + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + rwsem_read_unlock(tcp_sem); + + /* Make sure they haven't shut down the socket... */ + if(sock->flags & (SHUT_RD << 24)) { + goto out; + } + + /* Make sure its not reset already */ + if(sock->state & TCP_STATE_RESET) { + errno = ECONNRESET; + size = -1; + goto out; + } + + /* See if we have any data */ + if(!sock->data.rcvbuf_cur_sz) { + /* Check if we're in a state where there's not going to be any more + messages coming in. */ + if(sock->state == TCP_STATE_CLOSED || + sock->state == TCP_STATE_CLOSE_WAIT || + sock->state == TCP_STATE_CLOSING || + sock->state == TCP_STATE_LAST_ACK || + sock->state == TCP_STATE_TIME_WAIT) { + goto out; + } + + if(sock->flags & FS_SOCKET_NONBLOCK || irq_inside_int()) { + errno = EWOULDBLOCK; + size = -1; + goto out; + } + + cond_wait(sock->data.recv_cv, sock->mutex); + } + + /* Once we get here, we should have data, unless the other side has closed + the connection... */ + if(!sock->data.rcvbuf_cur_sz) { + if(sock->state & TCP_STATE_RESET) { + errno = ECONNRESET; + size = -1; + } + + goto out; + } + + /* Figure out how much we're going to give the user. */ + if(length > sock->data.rcvbuf_cur_sz) + size = sock->data.rcvbuf_cur_sz; + else + size = length; + + rb = sock->data.rcvbuf + sock->data.rcvbuf_head; + sock->data.rcv.wnd += size; + sock->data.rcvbuf_cur_sz -= size; + + if(sock->data.rcvbuf_head + size <= sock->data.rcvbuf_sz) { + memcpy(buf, rb, size); + sock->data.rcvbuf_head += size; + + if(sock->data.rcvbuf_head == sock->data.rcvbuf_sz) + sock->data.rcvbuf_head = 0; + } + else { + tmp = sock->data.rcvbuf_sz - sock->data.rcvbuf_head; + memcpy(buf, rb, tmp); + memcpy(buf + tmp, sock->data.rcvbuf, size - tmp); + sock->data.rcvbuf_head = size - tmp; + } + + /* If we've got nothing left, move the pointers back to the beginning */ + if(!sock->data.rcvbuf_cur_sz) { + sock->data.rcvbuf_head = sock->data.rcvbuf_tail = 0; + } + + if(addr != NULL) { + if(sock->domain == AF_INET) { + struct sockaddr_in realaddr; + + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + sock->remote_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock->remote_addr.sin6_port; + + if(*addr_len < sizeof(struct sockaddr_in)) { + memcpy(addr, &realaddr, *addr_len); + } + else { + memcpy(addr, &realaddr, sizeof(struct sockaddr_in)); + *addr_len = sizeof(struct sockaddr_in); + } + } + else if(sock->domain == AF_INET6) { + struct sockaddr_in6 realaddr6; + + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr = sock->remote_addr.sin6_addr; + realaddr6.sin6_port = sock->remote_addr.sin6_port; + + if(*addr_len < sizeof(struct sockaddr_in6)) { + memcpy(addr, &realaddr6, *addr_len); + } + else { + memcpy(addr, &realaddr6, sizeof(struct sockaddr_in6)); + *addr_len = sizeof(struct sockaddr_in6); + } + } + } + +out: + mutex_unlock(sock->mutex); + return size; } static ssize_t net_tcp_sendto(net_socket_t *hnd, const void *message, size_t length, int flags, const struct sockaddr *addr, socklen_t addr_len) { - errno = EBADF; - return -1; + struct tcp_sock *sock; + ssize_t size; + int bsz, tmp; + uint8_t *sb, *buf = (uint8_t *)message; + + /* Check the parameters first */ + if(message == NULL || (addr != NULL && addr_len == 0)) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + /* Lock the socket's mutex, since we're going to be manipulating its state + in here... */ + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + rwsem_read_unlock(tcp_sem); + + /* Check if the socket has been shut down for writing. */ + if(sock->flags & (SHUT_WR << 24)) { + errno = EPIPE; + size = -1; + goto out; + } + + /* Check to make sure the socket is connected. */ + switch(sock->state) { + case TCP_STATE_CLOSED | TCP_STATE_RESET: + errno = ECONNRESET; + size = -1; + goto out; + + case TCP_STATE_CLOSED: + case TCP_STATE_LISTEN: + case TCP_STATE_SYN_SENT: + errno = ENOTCONN; + size = -1; + goto out; + + case TCP_STATE_FIN_WAIT_1: + case TCP_STATE_FIN_WAIT_2: + case TCP_STATE_CLOSING: + case TCP_STATE_LAST_ACK: + case TCP_STATE_TIME_WAIT: + errno = EPIPE; + size = -1; + goto out; + } + + /* Check if there was an address specified, if so, return error. */ + if(addr) { + errno = EISCONN; + size = -1; + goto out; + } + + /* See if we have space to buffer at least some of the data... */ + if(sock->data.sndbuf_cur_sz == sock->data.sndbuf_sz) { + if((sock->flags & FS_SOCKET_NONBLOCK) || irq_inside_int()) { + errno = EWOULDBLOCK; + size = -1; + goto out; + } + + cond_wait(sock->data.send_cv, sock->mutex); + + /* If we still don't have any buffer space, its because the connection + has either been closed or reset by the other side... */ + if(sock->data.sndbuf_cur_sz == sock->data.sndbuf_sz) { + if(sock->state & TCP_STATE_RESET) { + errno = ECONNRESET; + size = -1; + goto out; + } + else { + errno = ENOTCONN; + size = -1; + goto out; + } + } + } + + /* Reset the pointers if there's nothing in the buffer */ + if(sock->data.sndbuf_cur_sz == 0) + sock->data.sndbuf_head = sock->data.sndbuf_acked = + sock->data.sndbuf_tail = 0; + + /* Figure out how much we can copy in */ + bsz = sock->data.sndbuf_sz - sock->data.sndbuf_cur_sz; + + if(length > bsz) + size = bsz; + else + size = length; + + sb = sock->data.sndbuf + sock->data.sndbuf_tail; + sock->data.sndbuf_cur_sz += size; + + if(sock->data.sndbuf_tail + size <= sock->data.sndbuf_sz) { + memcpy(sb, buf, size); + sock->data.sndbuf_tail += size; + + if(sock->data.sndbuf_tail == sock->data.sndbuf_sz) + sock->data.sndbuf_tail = 0; + } + else { + tmp = sock->data.sndbuf_sz - sock->data.sndbuf_tail; + memcpy(sb, buf, tmp); + memcpy(sock->data.sndbuf, buf + tmp, size - tmp); + sock->data.sndbuf_tail = size - tmp; + } + + /* Send some data! */ + tcp_send_data(sock, 0); + +out: + mutex_unlock(sock->mutex); + return size; } static int net_tcp_shutdownsock(net_socket_t *hnd, int how) { - errno = EBADF; - return -1; + struct tcp_sock *sock; + + if(irq_inside_int()) { + if(rwsem_read_trylock(tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } + else { + rwsem_read_lock(tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(sock->mutex)) { + rwsem_read_unlock(tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } + else { + mutex_lock(sock->mutex); + } + + if(how & 0xFFFFFFFC) { + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + errno = EINVAL; + return -1; + } + + sock->flags |= (how << 24); + + mutex_unlock(sock->mutex); + rwsem_read_unlock(tcp_sem); + + return 0; } -static void tcp_send_rst(netif_t *net, const struct in6_addr *src, +static void tcp_rst(netif_t *net, const struct in6_addr *src, + const struct in6_addr *dst, uint16_t src_port, + uint16_t dst_port, uint16_t flags, uint32_t seq, + uint32_t ack) { + tcp_hdr_t pkt; + uint16 c; + + /* Fill in the packet */ + pkt.src_port = src_port; + pkt.dst_port = dst_port; + pkt.seq = htonl(seq); + pkt.ack = htonl(ack); + pkt.off_flags = htons(flags | TCP_OFFSET(5)); + pkt.wnd = 0; + pkt.checksum = 0; + pkt.urg = 0; + + c = net_ipv6_checksum_pseudo(src, dst, sizeof(tcp_hdr_t), IPPROTO_TCP); + pkt.checksum = net_ipv4_checksum((const uint8 *)&pkt, sizeof(tcp_hdr_t), c); + + net_ipv6_send(net, (const uint8 *)&pkt, sizeof(tcp_hdr_t), 0, IPPROTO_TCP, + src, dst); +} + +static void tcp_bpkt_rst(netif_t *net, const struct in6_addr *src, const struct in6_addr *dst, const tcp_hdr_t *ohdr, int size) { tcp_hdr_t pkt; @@ -105,9 +1659,10 @@ pkt.src_port = ohdr->dst_port; pkt.dst_port = ohdr->src_port; - if(flags & TCP_FLAG_SYN) { + if(flags & TCP_FLAG_SYN) size += 1; - } + if(flags & TCP_FLAG_FIN) + size += 1; if(flags & TCP_FLAG_ACK) { pkt.seq = ohdr->ack; @@ -125,7 +1680,7 @@ pkt.checksum = 0; pkt.urg = 0; - cs = net_ipv6_checksum_pseudo(dst, src, IPPROTO_TCP, sizeof(tcp_hdr_t)); + cs = net_ipv6_checksum_pseudo(dst, src, sizeof(tcp_hdr_t), IPPROTO_TCP); pkt.checksum = net_ipv4_checksum((const uint8 *)&pkt, sizeof(tcp_hdr_t), cs); @@ -133,13 +1688,664 @@ dst, src); } +static int tcp_send_syn(struct tcp_sock *sock, int ack) { + uint8_t rawpkt[sizeof(tcp_hdr_t) + 4]; + tcp_hdr_t *hdr = (tcp_hdr_t *)rawpkt; + uint16_t cs; + + /* Fill in the base packet */ + hdr->src_port = sock->local_addr.sin6_port; + hdr->dst_port = sock->remote_addr.sin6_port; + hdr->seq = htonl(sock->data.snd.iss); + hdr->ack = htonl(sock->data.rcv.nxt); + + if(ack) { + hdr->off_flags = htons(TCP_FLAG_SYN | TCP_FLAG_ACK | TCP_OFFSET(6)); + } + else { + hdr->off_flags = htons(TCP_FLAG_SYN | TCP_OFFSET(6)); + } + + hdr->wnd = htons(sock->data.rcv.wnd); + hdr->checksum = 0; + hdr->urg = 0; + + /* Fill in our SYN options. The only one we worry about right now is MSS. */ + hdr->options[0] = TCP_OPT_MSS; + hdr->options[1] = 4; + hdr->options[2] = (TCP_DEFAULT_MSS >> 8) & 0xFF; + hdr->options[3] = TCP_DEFAULT_MSS & 0xFF; + + /* Calculate the real checksum */ + cs = net_ipv6_checksum_pseudo(&sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr, + sizeof(tcp_hdr_t) + 4, IPPROTO_TCP); + hdr->checksum = net_ipv4_checksum(rawpkt, sizeof(tcp_hdr_t) + 4, cs); + + return net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t) + 4, 0, + IPPROTO_TCP, &sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr); +} + +static void tcp_send_fin_ack(struct tcp_sock *sock) { + uint8_t rawpkt[sizeof(tcp_hdr_t)]; + tcp_hdr_t *hdr = (tcp_hdr_t *)rawpkt; + uint16_t cs; + + /* Fill in the base packet */ + hdr->src_port = sock->local_addr.sin6_port; + hdr->dst_port = sock->remote_addr.sin6_port; + hdr->seq = htonl(sock->data.snd.nxt); + hdr->ack = htonl(sock->data.rcv.nxt); + hdr->off_flags = htons(TCP_FLAG_FIN | TCP_FLAG_ACK | TCP_OFFSET(5)); + hdr->wnd = htons(sock->data.rcv.wnd); + hdr->checksum = 0; + hdr->urg = 0; + + /* Calculate the real checksum */ + cs = net_ipv6_checksum_pseudo(&sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr, + sizeof(tcp_hdr_t), IPPROTO_TCP); + hdr->checksum = net_ipv4_checksum(rawpkt, sizeof(tcp_hdr_t), cs); + + net_ipv6_send(sock->data.net, rawpkt, sizeof(tcp_hdr_t), 0, IPPROTO_TCP, + &sock->local_addr.sin6_addr, &sock->remote_addr.sin6_addr); +} + +static void tcp_send_ack(struct tcp_sock *sock) { + tcp_hdr_t hdr; + uint16_t c; + + /* Fill in the base packet */ + hdr.src_port = sock->local_addr.sin6_port; + hdr.dst_port = sock->remote_addr.sin6_port; + hdr.seq = htonl(sock->data.snd.nxt); + hdr.ack = htonl(sock->data.rcv.nxt); + hdr.off_flags = htons(TCP_FLAG_ACK | TCP_OFFSET(5)); + hdr.wnd = htons(sock->data.rcv.wnd); + hdr.checksum = 0; + hdr.urg = 0; + + /* Calculate the real checksum */ + c = net_ipv6_checksum_pseudo(&sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr, + sizeof(tcp_hdr_t), IPPROTO_TCP); + hdr.checksum = net_ipv4_checksum((const uint8 *)&hdr, sizeof(tcp_hdr_t), c); + + net_ipv6_send(sock->data.net, (const uint8 *)&hdr, sizeof(tcp_hdr_t), 0, + IPPROTO_TCP, &sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr); +} + +static void tcp_send_data(struct tcp_sock *sock, int resend) { + int wnd = sock->data.snd.wnd, snd; + int sz = sizeof(tcp_hdr_t); + uint8_t rawpkt[1500]; + tcp_hdr_t *hdr = (tcp_hdr_t *)rawpkt; + uint16_t cs; + uint8_t *sb, *buf; + uint32_t seq, unacked, head; + + if(!resend) { + seq = sock->data.snd.nxt; + unacked = sock->data.snd.nxt - sock->data.snd.una; + wnd -= unacked; + head = sock->data.sndbuf_head; + } + else { + seq = sock->data.snd.una; + unacked = 0; + head = sock->data.sndbuf_acked; + } + + if(!wnd) + wnd = 1; + + /* Fill in the base packet */ + hdr->src_port = sock->local_addr.sin6_port; + hdr->dst_port = sock->remote_addr.sin6_port; + hdr->ack = htonl(sock->data.rcv.nxt); + hdr->off_flags = htons(TCP_FLAG_ACK | TCP_OFFSET(5)); + hdr->wnd = htons(sock->data.rcv.wnd); + hdr->urg = 0; + + /* Put on some data if we should do so */ + while(sock->data.sndbuf_cur_sz - unacked && wnd) { + hdr->seq = htonl(seq); + hdr->checksum = 0; + buf = rawpkt + sizeof(tcp_hdr_t); + sb = sock->data.sndbuf + head; + snd = wnd; + + if(snd > sock->data.snd.mss - sizeof(tcp_hdr_t)) + snd = sock->data.snd.mss - sizeof(tcp_hdr_t); + if(snd > sock->data.sndbuf_cur_sz - unacked) + snd = sock->data.sndbuf_cur_sz - unacked; + + /* Copy in the data */ + if(head + snd <= sock->data.sndbuf_sz) { + memcpy(buf, sb, snd); + head += snd; + + if(head == sock->data.sndbuf_sz) + head = 0; + } + else { + sz = sock->data.sndbuf_sz - head; + memcpy(buf, sb, sz); + memcpy(buf + sz, sock->data.sndbuf, snd - sz); + head = snd - sz; + } + + sz = snd + sizeof(tcp_hdr_t); + wnd -= snd; + seq += snd; + unacked += snd; + + /* Calculate the checksum */ + cs = net_ipv6_checksum_pseudo(&sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr, sz, + IPPROTO_TCP); + hdr->checksum = net_ipv4_checksum(rawpkt, sz, cs); + + net_ipv6_send(sock->data.net, rawpkt, sz, 0, IPPROTO_TCP, + &sock->local_addr.sin6_addr, + &sock->remote_addr.sin6_addr); + } + + sock->data.timer = timer_ms_gettime64(); + sock->data.sndbuf_head = head; + sock->data.snd.nxt = seq; +} + +#define ADDR_EQUAL(a1, a2) \ + (((a1).__s6_addr.__s6_addr32[0] == (a2).__s6_addr.__s6_addr32[0]) && \ + ((a1).__s6_addr.__s6_addr32[1] == (a2).__s6_addr.__s6_addr32[1]) && \ + ((a1).__s6_addr.__s6_addr32[2] == (a2).__s6_addr.__s6_addr32[2]) && \ + ((a1).__s6_addr.__s6_addr32[3] == (a2).__s6_addr.__s6_addr32[3])) + +/* Match a socket to an incoming packet. If an actual socket is returned, it is + the caller's responsibility to release the socket's mutex when they're done + with it. */ +static struct tcp_sock *find_sock(const struct in6_addr *src, + const struct in6_addr *dst, + uint16_t sport, uint16_t dport, int domain) { + struct tcp_sock *i; + + LIST_FOREACH(i, &tcp_socks, sock_list) { + /* Ignore any closed sockets */ + if(i->state == TCP_STATE_CLOSED) + continue; + + /* Ignore any sockets that are IPv6 only when we have an incoming IPv4 + packet, or any that are IPv4 only when we have an incoming IPv6 + packet. */ + if((domain == AF_INET && (i->flags & FS_SOCKET_V6ONLY)) || + (domain == AF_INET6 && i->domain == AF_INET)) + continue; + + /* See if the remote end matches what's in the socket */ + if(!IN6_IS_ADDR_UNSPECIFIED(&i->remote_addr.sin6_addr) && + (!ADDR_EQUAL(i->remote_addr.sin6_addr, *src) || + i->remote_addr.sin6_port != sport)) + continue; + + /* See if it matches the local end */ + if((!IN6_IS_ADDR_UNSPECIFIED(&i->local_addr.sin6_addr) && + !ADDR_EQUAL(i->local_addr.sin6_addr, *dst)) || + i->local_addr.sin6_port != dport) + continue; + + if(irq_inside_int()) { + if(mutex_trylock(i->mutex)) + return (struct tcp_sock *)-1; + } + else { + mutex_lock(i->mutex); + } + + /* Because we always add new sockets to the head of the list, this + should be sufficient to match the socket. See the comment at the top + of the file for more discussion of this, if you're interested. */ + retur... [truncated message content] |
From: <ljs...@us...> - 2012-06-02 03:33:06
|
Revision: 793 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=793&view=rev Author: ljsebald Date: 2012-06-02 03:33:00 +0000 (Sat, 02 Jun 2012) Log Message: ----------- Have the echo server print out the IPv4 address as well, since IPv6 sockets work with IPv4 as well. Modified Paths: -------------- kos/examples/dreamcast/network/udpecho6/echo.c Modified: kos/examples/dreamcast/network/udpecho6/echo.c =================================================================== --- kos/examples/dreamcast/network/udpecho6/echo.c 2012-06-02 03:32:06 UTC (rev 792) +++ kos/examples/dreamcast/network/udpecho6/echo.c 2012-06-02 03:33:00 UTC (rev 793) @@ -69,6 +69,10 @@ inet_ntop(AF_INET6, &net_default_dev->ip6_lladdr, str1, INET6_ADDRSTRLEN); printf("Link-local address: %s\n", str1); + printf("IPv4 address: %d.%d.%d.%d\n", net_default_dev->ip_addr[0], + net_default_dev->ip_addr[1], net_default_dev->ip_addr[2], + net_default_dev->ip_addr[3]); + sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); if(sock < 0) { perror("socket"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |