diff options
-rw-r--r-- | freebsd/sys/sys/proc.h | 2 | ||||
-rw-r--r-- | freebsd/sys/sys/systm.h | 5 | ||||
-rw-r--r-- | rtemsbsd/include/machine/rtems-bsd-config.h.in | 2 | ||||
-rw-r--r-- | rtemsbsd/include/machine/rtems-bsd-thread.h | 9 | ||||
-rw-r--r-- | rtemsbsd/rtems/rtems-bsd-kern_synch.c | 399 | ||||
-rw-r--r-- | rtemsbsd/rtems/rtems-bsd-mutex.c | 19 | ||||
-rw-r--r-- | rtemsbsd/rtems/rtems-bsd-thread.c | 24 |
7 files changed, 219 insertions, 241 deletions
diff --git a/freebsd/sys/sys/proc.h b/freebsd/sys/sys/proc.h index 6dbc88c5..ba40e259 100644 --- a/freebsd/sys/sys/proc.h +++ b/freebsd/sys/sys/proc.h @@ -214,8 +214,8 @@ struct thread { struct cpuset *td_cpuset; /* (t) CPU affinity mask. */ #endif /* __rtems__ */ struct seltd *td_sel; /* Select queue/channel. */ -#ifndef __rtems__ struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */ +#ifndef __rtems__ struct turnstile *td_turnstile; /* (k) Associated turnstile. */ struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */ lwpid_t td_tid; /* (b) Thread ID. */ diff --git a/freebsd/sys/sys/systm.h b/freebsd/sys/sys/systm.h index e464356a..9fce4b4a 100644 --- a/freebsd/sys/sys/systm.h +++ b/freebsd/sys/sys/systm.h @@ -339,8 +339,13 @@ int _sleep(void *chan, struct lock_object *lock, int pri, const char *wmesg, int timo) __nonnull(1); #define msleep(chan, mtx, pri, wmesg, timo) \ _sleep((chan), &(mtx)->lock_object, (pri), (wmesg), (timo)) +#ifndef __rtems__ int msleep_spin(void *chan, struct mtx *mtx, const char *wmesg, int timo) __nonnull(1); +#else /* __rtems__ */ +#define msleep_spin(chan, mtx, wmesg, timo) \ + msleep((chan), (mtx), 0, (wmesg), (timo)) +#endif /* __rtems__ */ int pause(const char *wmesg, int timo); #define tsleep(chan, pri, wmesg, timo) \ _sleep((chan), NULL, (pri), (wmesg), (timo)) diff --git a/rtemsbsd/include/machine/rtems-bsd-config.h.in b/rtemsbsd/include/machine/rtems-bsd-config.h.in index b6738991..ea14b835 100644 --- a/rtemsbsd/include/machine/rtems-bsd-config.h.in +++ b/rtemsbsd/include/machine/rtems-bsd-config.h.in @@ -134,8 +134,6 @@ void rtems_bsd_assert_func(const char *file, int line, const char *func, const c #define M_RTEMS_HEAP 0 -#define BSD_MAXIMUM_SLEEP_QUEUES 32 - #define BSD_DEFAULT_FIB 0 #define BSD_DEFAULT_PID 0 diff --git a/rtemsbsd/include/machine/rtems-bsd-thread.h b/rtemsbsd/include/machine/rtems-bsd-thread.h index b8088b50..81aef32e 100644 --- a/rtemsbsd/include/machine/rtems-bsd-thread.h +++ b/rtemsbsd/include/machine/rtems-bsd-thread.h @@ -43,7 +43,9 @@ #include <rtems/bsd/sys/param.h> #include <rtems/bsd/sys/types.h> #include <sys/proc.h> +#include <sys/queue.h> +#include <rtems/score/threadq.h> #include <rtems.h> #define BSD_TASK_NAME rtems_build_name('_', 'B', 'S', 'D') @@ -59,6 +61,13 @@ /* FIXME */ #define BSD_MINIMUM_TASK_STACK_SIZE ((size_t) 32 * 1024) +struct sleepqueue { + Thread_queue_Control sq_blocked; + LIST_ENTRY(sleepqueue) sq_hash; + LIST_HEAD(, sleepqueue) sq_free; + void *sq_wchan; +}; + extern rtems_chain_control rtems_bsd_thread_chain; struct thread * diff --git a/rtemsbsd/rtems/rtems-bsd-kern_synch.c b/rtemsbsd/rtems/rtems-bsd-kern_synch.c index 19ab0971..40f3280a 100644 --- a/rtemsbsd/rtems/rtems-bsd-kern_synch.c +++ b/rtemsbsd/rtems/rtems-bsd-kern_synch.c @@ -7,10 +7,21 @@ */ /* - * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved. + * Copyright (c) 1982, 1986, 1990, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org> + * All rights reserved. + * + * Copyright (c) 2009-2013 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * <rtems@embedded-brains.de> @@ -23,6 +34,9 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -35,13 +49,12 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ - -/* - * FIXME: This seems to be a completely broken implementation. + * + * @(#)kern_synch.c 8.9 (Berkeley) 5/19/95 */ #include <machine/rtems-bsd-config.h> +#include <machine/rtems-bsd-thread.h> #include <rtems/score/statesimpl.h> #include <rtems/score/threaddispatch.h> @@ -52,206 +65,152 @@ #include <rtems/bsd/sys/types.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/ktr.h> #include <rtems/bsd/sys/lock.h> #include <sys/mutex.h> -#include <sys/proc.h> -#include <machine/pcpu.h> - -#define STATES_WAITING_FOR_SLEEP 0x40000 static int pause_wchan; -typedef struct -{ - Chain_Node node; - void *ident; - Thread_queue_Control queue; -}sleep_queue_control_t; +/* + * Constants for the hash table of sleep queue chains. These constants are + * the same ones that 4BSD (and possibly earlier versions of BSD) used. + * Basically, we ignore the lower 8 bits of the address since most wait + * channel pointers are aligned and only look at the next 7 bits for the + * hash. SC_TABLESIZE must be a power of two for SC_MASK to work properly. + */ +#define SC_TABLESIZE 128 /* Must be power of 2. */ +#define SC_MASK (SC_TABLESIZE - 1) +#define SC_SHIFT 8 +#define SC_HASH(wc) (((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK) +#define SC_LOOKUP(wc) &sleepq_chains[SC_HASH(wc)] -sleep_queue_control_t sleep_queue[BSD_MAXIMUM_SLEEP_QUEUES]; //this memory allocation could use _Workspace_Allocate once inside RTEMS tree -Chain_Control sleep_queue_inactive_nodes; //chain of inactive nodes -Chain_Control sleep_queue_active_nodes; //chain of active nodes +struct sleepqueue_chain { + LIST_HEAD(, sleepqueue) sc_queues; /* List of sleep queues. */ +}; -void -sleepinit(void) -{ - int ii; - - /* initialize the sleep queue */ - for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ ) - { - sleep_queue[ii].ident = NULL; - /* - * Initialize the queue we use to block for signals - */ - _Thread_queue_Initialize( - &sleep_queue[ii].queue, - THREAD_QUEUE_DISCIPLINE_PRIORITY, - STATES_WAITING_FOR_SLEEP | STATES_INTERRUPTIBLE_BY_SIGNAL, - EAGAIN - ); - } - //initialize active chain - _Chain_Initialize_empty( &sleep_queue_active_nodes ); - //initialize inactive chain - _Chain_Initialize( &sleep_queue_inactive_nodes, sleep_queue, BSD_MAXIMUM_SLEEP_QUEUES, sizeof( sleep_queue_control_t )); -} +static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE]; -sleep_queue_control_t* -sleep_queue_lookup(void *ident) +static void +init_sleepqueues(void) { - int ii; - - /* initialize the sleep queue */ - for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ ) - { - if( sleep_queue[ii].ident == ident ) - { - return &sleep_queue[ii]; - } - } - return NULL; -} + size_t i; -sleep_queue_control_t* -sleep_queue_get(void *ident) -{ - sleep_queue_control_t *sq; - - sq = sleep_queue_lookup( ident ); - if (sq == NULL) - { - KASSERT(!_Chain_Is_empty( &inactive_nodes ), ("sleep_queue_get")); - //get a control from the inactive chain - sq = ( sleep_queue_control_t * )_Chain_Get( &sleep_queue_inactive_nodes ); - sq->ident = ident; - _Chain_Append( &sleep_queue_active_nodes, &sq->node ); - } - return sq; + for (i = 0; i < SC_TABLESIZE; i++) { + LIST_INIT(&sleepq_chains[i].sc_queues); + } } +SYSINIT(rtems_bsd_sleep, SI_SUB_INTRINSIC, SI_ORDER_FIRST, init_sleepqueues, NULL); + /* - * Block the current thread until it is awakened from its sleep queue - * or it times out while waiting. + * Look up the sleep queue associated with a given wait channel in the hash + * table locking the associated sleep queue chain. If no queue is found in + * the table, NULL is returned. */ -int -sleep_queue_timedwait(void *wchan, int pri, int timeout, int catch) +static struct sleepqueue * +sleepq_lookup(void *wchan) { - sleep_queue_control_t *sq; - Thread_Control *executing; - ISR_Level level; - - _Thread_Disable_dispatch(); - - sq = sleep_queue_get( wchan ); - - executing = _Thread_Executing; - if( timeout ) - { - executing->Wait.return_code = EWOULDBLOCK; - } - else
- { - executing->Wait.return_code = 0; - } - _ISR_Disable( level ); - _Thread_queue_Enter_critical_section( &sq->queue ); - if( catch ) - { - sq->queue.state |= STATES_INTERRUPTIBLE_BY_SIGNAL; - } - else - { - sq->queue.state &= ~STATES_INTERRUPTIBLE_BY_SIGNAL; - } - executing->Wait.queue = &sq->queue; - _ISR_Enable( level ); - - _Thread_queue_Enqueue( &sq->queue, executing, timeout ); - _Thread_Enable_dispatch(); - return _Thread_Executing->Wait.return_code; + struct sleepqueue_chain *sc; + struct sleepqueue *sq; + + KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); + sc = SC_LOOKUP(wchan); + LIST_FOREACH(sq, &sc->sc_queues, sq_hash) + if (sq->sq_wchan == wchan) + return (sq); + return (NULL); } -/* - * General sleep call. Suspends the current thread until a wakeup is - * performed on the specified identifier. The thread will then be made - * runnable with the specified priority. Sleeps at most timo/hz seconds - * (0 means no timeout). If pri includes PCATCH flag, signals are checked - * before and after sleeping, else signals are not checked. Returns 0 if - * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a - * signal needs to be delivered, ERESTART is returned if the current system - * call should be restarted if possible, and EINTR is returned if the system - * call should be interrupted by the signal (return EINTR). - * - * The lock argument is unlocked before the caller is suspended, and - * re-locked before _sleep() returns. If priority includes the PDROP - * flag the lock is not re-locked before returning. - */ int -_sleep(void *ident, struct lock_object *lock, int priority, const char *wmesg, int timo) +_sleep(void *wchan, struct lock_object *lock, int priority, const char *wmesg, int timo) { - struct thread *td; - struct lock_class *class; - int catch, flags, lock_state, pri, rval; + Thread_Control *executing; + struct thread *td; + struct lock_class *class; + int lock_state; + int rval; + struct sleepqueue *sq; + struct sleepqueue_chain *sc; - td = curthread; #ifdef KTRACE - if (KTRPOINT(td, KTR_CSW)) - ktrcsw(1, 0); + if (KTRPOINT(td, KTR_CSW)) + ktrcsw(1, 0); #endif - KASSERT(timo != 0 || mtx_owned(&Giant) || lock != NULL, - ("sleeping without a lock")); - KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep")); - if (priority & PDROP) - KASSERT(lock != NULL && lock != &Giant.lock_object, - ("PDROP requires a non-Giant lock")); - if (lock != NULL) - class = LOCK_CLASS(lock); - else - class = NULL; - - if (cold) { - /* - * During autoconfiguration, just return; - * don't run any other threads or panic below, - * in case this is the idle thread and already asleep. - * XXX: this used to do "s = splhigh(); splx(safepri); - * splx(s);" to give interrupts a chance, but there is - * no way to give interrupts a chance now. - */ - if (lock != NULL && priority & PDROP) - class->lc_unlock(lock); - return (0); - } - catch = priority & PCATCH; - pri = priority & PRIMASK; - - if (lock == &Giant.lock_object) - mtx_assert(&Giant, MA_OWNED); - DROP_GIANT(); - if (lock != NULL && lock != &Giant.lock_object && - !(class->lc_flags & LC_SLEEPABLE)) { - lock_state = class->lc_unlock(lock); - } else - /* GCC needs to follow the Yellow Brick Road */ - lock_state = -1; - - if (lock != NULL && class->lc_flags & LC_SLEEPABLE) { - lock_state = class->lc_unlock(lock); - } - - rval = sleep_queue_timedwait(ident, pri, timo, catch); - -#ifdef KTRACE - if (KTRPOINT(td, KTR_CSW)) - ktrcsw(0, 0); -#endif - PICKUP_GIANT(); - if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) { - class->lc_lock(lock, lock_state); - } - return (rval); + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, + "Sleeping on \"%s\"", wmesg); + KASSERT(timo != 0 || mtx_owned(&Giant) || lock != NULL, + ("sleeping without a lock")); + KASSERT(p != NULL, ("msleep1")); + KASSERT(wchan != NULL && TD_IS_RUNNING(td), ("msleep")); + if (priority & PDROP) + KASSERT(lock != NULL && lock != &Giant.lock_object, + ("PDROP requires a non-Giant lock")); + if (lock != NULL) + class = LOCK_CLASS(lock); + else + class = NULL; + + if (lock == &Giant.lock_object) + mtx_assert(&Giant, MA_OWNED); + DROP_GIANT(); + + td = curthread; + + _Thread_Disable_dispatch(); + + if (lock != NULL) { + lock_state = class->lc_unlock(lock); + } + + sc = SC_LOOKUP(wchan); + + /* Look up the sleep queue associated with the wait channel 'wchan'. */ + sq = sleepq_lookup(wchan); + + /* + * If the wait channel does not already have a sleep queue, use + * this thread's sleep queue. Otherwise, insert the current thread + * into the sleep queue already in use by this wait channel. + */ + if (sq == NULL) { + sq = td->td_sleepqueue; + LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash); + sq->sq_wchan = wchan; + } else { + LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash); + } + td->td_sleepqueue = NULL; + + _Thread_queue_Enter_critical_section(&sq->sq_blocked); + executing = _Thread_Executing; + executing->Wait.queue = &sq->sq_blocked; + _Thread_queue_Enqueue(&sq->sq_blocked, executing, (Watchdog_Interval) timo); + + _Thread_Enable_dispatch(); + + rval = (int) executing->Wait.return_code; + + _Thread_Disable_dispatch(); + + /* + * Get a sleep queue for this thread. If this is the last waiter, + * use the queue itself and take it out of the chain, otherwise, + * remove a queue from the free list. + */ + if (LIST_EMPTY(&sq->sq_free)) { + td->td_sleepqueue = sq; + } else + td->td_sleepqueue = LIST_FIRST(&sq->sq_free); + LIST_REMOVE(td->td_sleepqueue, sq_hash); + + _Thread_Enable_dispatch(); + + PICKUP_GIANT(); + if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) { + class->lc_lock(lock, lock_state); + WITNESS_RESTORE(lock, lock_witness); + } + + return (rval); } /* @@ -264,49 +223,51 @@ int pause(const char *wmesg, int timo) { - KASSERT(timo != 0, ("pause: timeout required")); - return (tsleep(&pause_wchan, 0, wmesg, timo)); + KASSERT(timo != 0, ("pause: timeout required")); + return (tsleep(&pause_wchan, 0, wmesg, timo)); } -/* - * Make all threads sleeping on the specified identifier runnable. - */ -void -wakeup(void *ident) +static void +rtems_bsd_sleepq_wakeup(struct sleepqueue *sq, Thread_Control *thread) { - sleep_queue_control_t *sq; - Thread_Control *the_thread; - - sq = sleep_queue_lookup( ident ); - if (sq == NULL) - { - return (0); - } - - while ( (the_thread = _Thread_queue_Dequeue(&sq->queue)) ) - { - } - return 0; + thread->Wait.return_code = 0; } -/* - * Make a thread sleeping on the specified identifier runnable. - * May wake more than one thread if a target thread is currently - * swapped out. - */ void -wakeup_one(void *ident) +wakeup(void *wchan) { - sleep_queue_control_t *sq; - Thread_Control *the_thread; + struct sleepqueue *sq; - sq = sleep_queue_lookup( ident ); - if (sq == NULL) - { - return (0); - } - the_thread = _Thread_queue_Dequeue(&sq->queue); - return 0; + _Thread_Disable_dispatch(); + sq = sleepq_lookup(wchan); + if (sq != NULL) { + Thread_Control *thread; + + while ((thread = _Thread_queue_Dequeue(&sq->sq_blocked)) != NULL) { + rtems_bsd_sleepq_wakeup(sq, thread); + } + } + + _Thread_Enable_dispatch(); } +void +wakeup_one(void *wchan) +{ + struct sleepqueue *sq; + + _Thread_Disable_dispatch(); + + sq = sleepq_lookup(wchan); + if (sq != NULL) { + Thread_Control *thread; + + thread = _Thread_queue_Dequeue(&sq->sq_blocked); + if (thread != NULL) { + rtems_bsd_sleepq_wakeup(sq, thread); + } + } + + _Thread_Enable_dispatch(); +} diff --git a/rtemsbsd/rtems/rtems-bsd-mutex.c b/rtemsbsd/rtems/rtems-bsd-mutex.c index fe01bc48..1c79bd28 100644 --- a/rtemsbsd/rtems/rtems-bsd-mutex.c +++ b/rtemsbsd/rtems/rtems-bsd-mutex.c @@ -53,12 +53,10 @@ static void assert_mtx(struct lock_object *lock, int what); static void lock_mtx(struct lock_object *lock, int how); -static void lock_spin(struct lock_object *lock, int how); #ifdef KDTRACE_HOOKS static int owner_mtx(struct lock_object *lock, struct thread **owner); #endif static int unlock_mtx(struct lock_object *lock); -static int unlock_spin(struct lock_object *lock); RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_mtx_chain); @@ -86,8 +84,8 @@ struct lock_class lock_class_mtx_spin = { #ifdef DDB .lc_ddb_show = db_show_mtx, #endif - .lc_lock = lock_spin, - .lc_unlock = unlock_spin, + .lc_lock = lock_mtx, + .lc_unlock = unlock_mtx, #ifdef KDTRACE_HOOKS .lc_owner = owner_mtx, #endif @@ -108,13 +106,6 @@ lock_mtx(struct lock_object *lock, int how) mtx_lock((struct mtx *)lock); } -void -lock_spin(struct lock_object *lock, int how) -{ - - panic("spin locks can only use msleep_spin"); -} - int unlock_mtx(struct lock_object *lock) { @@ -126,12 +117,6 @@ unlock_mtx(struct lock_object *lock) return (0); } -int -unlock_spin(struct lock_object *lock) -{ - - panic("spin locks can only use msleep_spin"); -} #ifdef KDTRACE_HOOKS int diff --git a/rtemsbsd/rtems/rtems-bsd-thread.c b/rtemsbsd/rtems/rtems-bsd-thread.c index cbf33cf1..b3bdb842 100644 --- a/rtemsbsd/rtems/rtems-bsd-thread.c +++ b/rtemsbsd/rtems/rtems-bsd-thread.c @@ -49,8 +49,12 @@ #include <sys/malloc.h> #include <sys/selinfo.h> -#include <rtems/score/threadimpl.h> #include <rtems/score/objectimpl.h> +#include <rtems/score/statesimpl.h> +#include <rtems/score/threaddispatch.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadimpl.h> +#include <rtems/score/threadqimpl.h> RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_thread_chain); @@ -91,9 +95,24 @@ struct thread * rtems_bsd_thread_create(Thread_Control *thread, int wait) { struct thread *td = malloc(sizeof(*td), M_TEMP, M_ZERO | wait); + struct sleepqueue *sq = malloc(sizeof(*sq), M_TEMP, wait); - if (td != NULL) { + if (td != NULL && sq != NULL) { td->td_thread = thread; + td->td_sleepqueue = sq; + + LIST_INIT(&sq->sq_free); + + _Thread_queue_Initialize( + &sq->sq_blocked, + THREAD_QUEUE_DISCIPLINE_PRIORITY, + STATES_WAITING_FOR_BSD_WAKEUP, + EWOULDBLOCK + ); + } else { + free(td, M_TEMP); + free(sq, M_TEMP); + td = NULL; } thread->extensions[rtems_bsd_extension_index] = td; @@ -167,6 +186,7 @@ rtems_bsd_extension_thread_delete( rtems_chain_explicit_extract(&rtems_bsd_thread_chain, &td->td_node); } + free(td->td_sleepqueue, M_TEMP); free(td, M_TEMP); } } |