Changeset f9c2714 in rtems-libbsd


Ignore:
Timestamp:
Oct 23, 2013, 7:47:09 AM (6 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, afaeccc05a556f6aa25ba044a7e49d6aa634a59e, freebsd-9.3, master
Children:
0967858
Parents:
24732b6
git-author:
Sebastian Huber <sebastian.huber@…> (10/23/13 07:47:09)
git-committer:
Sebastian Huber <sebastian.huber@…> (10/31/13 12:18:50)
Message:

SLEEP(8): New implementation

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • freebsd/sys/sys/proc.h

    r24732b6 rf9c2714  
    215215#endif /* __rtems__ */
    216216        struct seltd    *td_sel;        /* Select queue/channel. */
     217        struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
    217218#ifndef __rtems__
    218         struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
    219219        struct turnstile *td_turnstile; /* (k) Associated turnstile. */
    220220        struct umtx_q   *td_umtxq;      /* (c?) Link for when we're blocked. */
  • freebsd/sys/sys/systm.h

    r24732b6 rf9c2714  
    340340#define msleep(chan, mtx, pri, wmesg, timo)                             \
    341341        _sleep((chan), &(mtx)->lock_object, (pri), (wmesg), (timo))
     342#ifndef __rtems__
    342343int     msleep_spin(void *chan, struct mtx *mtx, const char *wmesg, int timo)
    343344            __nonnull(1);
     345#else /* __rtems__ */
     346#define msleep_spin(chan, mtx, wmesg, timo)                             \
     347        msleep((chan), (mtx), 0, (wmesg), (timo))
     348#endif /* __rtems__ */
    344349int     pause(const char *wmesg, int timo);
    345350#define tsleep(chan, pri, wmesg, timo)                                  \
  • rtemsbsd/include/machine/rtems-bsd-config.h.in

    r24732b6 rf9c2714  
    135135#define M_RTEMS_HEAP 0
    136136
    137 #define BSD_MAXIMUM_SLEEP_QUEUES 32
    138 
    139137#define BSD_DEFAULT_FIB 0
    140138
  • rtemsbsd/include/machine/rtems-bsd-thread.h

    r24732b6 rf9c2714  
    4444#include <rtems/bsd/sys/types.h>
    4545#include <sys/proc.h>
     46#include <sys/queue.h>
    4647
     48#include <rtems/score/threadq.h>
    4749#include <rtems.h>
    4850
     
    6062#define BSD_MINIMUM_TASK_STACK_SIZE ((size_t) 32 * 1024)
    6163
     64struct sleepqueue {
     65        Thread_queue_Control sq_blocked;
     66        LIST_ENTRY(sleepqueue) sq_hash;
     67        LIST_HEAD(, sleepqueue) sq_free;
     68        void *sq_wchan;
     69};
     70
    6271extern rtems_chain_control rtems_bsd_thread_chain;
    6372
  • rtemsbsd/rtems/rtems-bsd-kern_synch.c

    r24732b6 rf9c2714  
    88
    99/*
    10  * Copyright (c) 2009, 2010 embedded brains GmbH.  All rights reserved.
     10 * Copyright (c) 1982, 1986, 1990, 1991, 1993
     11 *      The Regents of the University of California.  All rights reserved.
     12 * (c) UNIX System Laboratories, Inc.
     13 * All or some portions of this file are derived from material licensed
     14 * to the University of California by American Telephone and Telegraph
     15 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     16 * the permission of UNIX System Laboratories, Inc.
     17 *
     18 * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
     19 * All rights reserved.
     20 *
     21 * Copyright (c) 2009-2013 embedded brains GmbH.  All rights reserved.
    1122 *
    1223 *  embedded brains GmbH
    13  *  Obere Lagerstr. 30
     24 *  Dornierstr. 4
    1425 *  82178 Puchheim
    1526 *  Germany
     
    2435 *    notice, this list of conditions and the following disclaimer in the
    2536 *    documentation and/or other materials provided with the distribution.
     37 * 4. Neither the name of the author nor the names of any co-contributors
     38 *    may be used to endorse or promote products derived from this software
     39 *    without specific prior written permission.
    2640 *
    2741 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     
    3650 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    3751 * SUCH DAMAGE.
    38  */
    39 
    40 /*
    41  * FIXME: This seems to be a completely broken implementation.
     52 *
     53 *      @(#)kern_synch.c        8.9 (Berkeley) 5/19/95
    4254 */
    4355
    4456#include <machine/rtems-bsd-config.h>
     57#include <machine/rtems-bsd-thread.h>
    4558
    4659#include <rtems/score/statesimpl.h>
     
    5366#include <sys/systm.h>
    5467#include <sys/kernel.h>
    55 #include <sys/ktr.h>
    5668#include <rtems/bsd/sys/lock.h>
    5769#include <sys/mutex.h>
    58 #include <sys/proc.h>
    59 #include <machine/pcpu.h>
    60 
    61 #define STATES_WAITING_FOR_SLEEP              0x40000
    6270
    6371static int pause_wchan;
    6472
    65 typedef struct
    66 {
    67   Chain_Node node;
    68   void *ident;
    69   Thread_queue_Control queue;
    70 }sleep_queue_control_t;
    71 
    72 sleep_queue_control_t sleep_queue[BSD_MAXIMUM_SLEEP_QUEUES]; //this memory allocation could use _Workspace_Allocate once inside RTEMS tree
    73 Chain_Control sleep_queue_inactive_nodes;  //chain of inactive nodes
    74 Chain_Control sleep_queue_active_nodes;    //chain of active nodes
    75 
    76 void
    77 sleepinit(void)
    78 {
    79   int ii;
    80 
    81   /* initialize the sleep queue */
    82   for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ )
    83   {
    84     sleep_queue[ii].ident = NULL;
    85     /*
    86      *  Initialize the queue we use to block for signals
    87      */
    88     _Thread_queue_Initialize(
    89       &sleep_queue[ii].queue,
    90       THREAD_QUEUE_DISCIPLINE_PRIORITY,
    91       STATES_WAITING_FOR_SLEEP | STATES_INTERRUPTIBLE_BY_SIGNAL,
    92       EAGAIN
    93     );
    94   }
    95   //initialize active chain
    96   _Chain_Initialize_empty( &sleep_queue_active_nodes );
    97   //initialize inactive chain
    98   _Chain_Initialize( &sleep_queue_inactive_nodes, sleep_queue, BSD_MAXIMUM_SLEEP_QUEUES, sizeof( sleep_queue_control_t ));
    99 }
    100 
    101 sleep_queue_control_t*
    102 sleep_queue_lookup(void *ident)
    103 {
    104   int ii;
    105 
    106   /* initialize the sleep queue */
    107   for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ )
    108   {
    109     if( sleep_queue[ii].ident == ident )
    110     {
    111       return &sleep_queue[ii];
    112     }
    113   }
    114   return NULL;
    115 }
    116 
    117 sleep_queue_control_t*
    118 sleep_queue_get(void *ident)
    119 {
    120   sleep_queue_control_t *sq;
    121 
    122   sq = sleep_queue_lookup( ident );
    123   if (sq == NULL)
    124   {
    125     KASSERT(!_Chain_Is_empty( &inactive_nodes ), ("sleep_queue_get"));
    126     //get a control from the inactive chain
    127     sq = ( sleep_queue_control_t * )_Chain_Get( &sleep_queue_inactive_nodes );
    128     sq->ident = ident;
    129     _Chain_Append( &sleep_queue_active_nodes, &sq->node );
    130   }
    131   return sq;
    132 }
    133 
    134 /*
    135  * Block the current thread until it is awakened from its sleep queue
    136  * or it times out while waiting.
    137  */
     73/*
     74 * Constants for the hash table of sleep queue chains.  These constants are
     75 * the same ones that 4BSD (and possibly earlier versions of BSD) used.
     76 * Basically, we ignore the lower 8 bits of the address since most wait
     77 * channel pointers are aligned and only look at the next 7 bits for the
     78 * hash.  SC_TABLESIZE must be a power of two for SC_MASK to work properly.
     79 */
     80#define SC_TABLESIZE    128                     /* Must be power of 2. */
     81#define SC_MASK         (SC_TABLESIZE - 1)
     82#define SC_SHIFT        8
     83#define SC_HASH(wc)     (((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK)
     84#define SC_LOOKUP(wc)   &sleepq_chains[SC_HASH(wc)]
     85
     86struct sleepqueue_chain {
     87        LIST_HEAD(, sleepqueue) sc_queues;      /* List of sleep queues. */
     88};
     89
     90static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE];
     91
     92static void
     93init_sleepqueues(void)
     94{
     95        size_t i;
     96
     97        for (i = 0; i < SC_TABLESIZE; i++) {
     98                LIST_INIT(&sleepq_chains[i].sc_queues);
     99        }
     100}
     101
     102SYSINIT(rtems_bsd_sleep, SI_SUB_INTRINSIC, SI_ORDER_FIRST, init_sleepqueues, NULL);
     103
     104/*
     105 * Look up the sleep queue associated with a given wait channel in the hash
     106 * table locking the associated sleep queue chain.  If no queue is found in
     107 * the table, NULL is returned.
     108 */
     109static struct sleepqueue *
     110sleepq_lookup(void *wchan)
     111{
     112        struct sleepqueue_chain *sc;
     113        struct sleepqueue *sq;
     114
     115        KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
     116        sc = SC_LOOKUP(wchan);
     117        LIST_FOREACH(sq, &sc->sc_queues, sq_hash)
     118                if (sq->sq_wchan == wchan)
     119                        return (sq);
     120        return (NULL);
     121}
     122
    138123int
    139 sleep_queue_timedwait(void *wchan, int pri, int timeout, int catch)
    140 {
    141   sleep_queue_control_t *sq;
    142   Thread_Control *executing;
    143   ISR_Level       level;
    144 
    145   _Thread_Disable_dispatch();
    146 
    147   sq = sleep_queue_get( wchan );
    148 
    149   executing = _Thread_Executing;
    150   if( timeout )
    151   {
    152     executing->Wait.return_code = EWOULDBLOCK;
    153   }
    154   else
    155   {
    156     executing->Wait.return_code = 0;
    157   }
    158   _ISR_Disable( level );
    159   _Thread_queue_Enter_critical_section( &sq->queue );
    160   if( catch )
    161   {
    162     sq->queue.state |= STATES_INTERRUPTIBLE_BY_SIGNAL;
    163   }
    164   else
    165   {
    166     sq->queue.state &= ~STATES_INTERRUPTIBLE_BY_SIGNAL;
    167   }
    168   executing->Wait.queue = &sq->queue;
    169   _ISR_Enable( level );
    170 
    171   _Thread_queue_Enqueue( &sq->queue, executing, timeout );
    172   _Thread_Enable_dispatch();
    173   return _Thread_Executing->Wait.return_code;
    174 }
    175 
    176 /*
    177  * General sleep call.  Suspends the current thread until a wakeup is
    178  * performed on the specified identifier.  The thread will then be made
    179  * runnable with the specified priority.  Sleeps at most timo/hz seconds
    180  * (0 means no timeout).  If pri includes PCATCH flag, signals are checked
    181  * before and after sleeping, else signals are not checked.  Returns 0 if
    182  * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
    183  * signal needs to be delivered, ERESTART is returned if the current system
    184  * call should be restarted if possible, and EINTR is returned if the system
    185  * call should be interrupted by the signal (return EINTR).
    186  *
    187  * The lock argument is unlocked before the caller is suspended, and
    188  * re-locked before _sleep() returns.  If priority includes the PDROP
    189  * flag the lock is not re-locked before returning.
    190  */
    191 int
    192 _sleep(void *ident, struct lock_object *lock, int priority, const char *wmesg, int timo)
    193 {
    194   struct thread *td;
    195   struct lock_class *class;
    196   int catch, flags, lock_state, pri, rval;
    197 
    198   td = curthread;
     124_sleep(void *wchan, struct lock_object *lock, int priority, const char *wmesg, int timo)
     125{
     126        Thread_Control *executing;
     127        struct thread *td;
     128        struct lock_class *class;
     129        int lock_state;
     130        int rval;
     131        struct sleepqueue *sq;
     132        struct sleepqueue_chain *sc;
     133
    199134#ifdef KTRACE
    200   if (KTRPOINT(td, KTR_CSW))
    201     ktrcsw(1, 0);
     135        if (KTRPOINT(td, KTR_CSW))
     136                ktrcsw(1, 0);
    202137#endif
    203   KASSERT(timo != 0 || mtx_owned(&Giant) || lock != NULL,
    204       ("sleeping without a lock"));
    205   KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep"));
    206   if (priority & PDROP)
    207     KASSERT(lock != NULL && lock != &Giant.lock_object,
    208         ("PDROP requires a non-Giant lock"));
    209   if (lock != NULL)
    210     class = LOCK_CLASS(lock);
    211   else
    212     class = NULL;
    213 
    214   if (cold) {
    215     /*
    216      * During autoconfiguration, just return;
    217      * don't run any other threads or panic below,
    218      * in case this is the idle thread and already asleep.
    219      * XXX: this used to do "s = splhigh(); splx(safepri);
    220      * splx(s);" to give interrupts a chance, but there is
    221      * no way to give interrupts a chance now.
    222      */
    223     if (lock != NULL && priority & PDROP)
    224       class->lc_unlock(lock);
    225     return (0);
    226   }
    227   catch = priority & PCATCH;
    228   pri = priority & PRIMASK;
    229 
    230   if (lock == &Giant.lock_object)
    231     mtx_assert(&Giant, MA_OWNED);
    232   DROP_GIANT();
    233   if (lock != NULL && lock != &Giant.lock_object &&
    234       !(class->lc_flags & LC_SLEEPABLE)) {
    235     lock_state = class->lc_unlock(lock);
    236   } else
    237     /* GCC needs to follow the Yellow Brick Road */
    238     lock_state = -1;
    239 
    240   if (lock != NULL && class->lc_flags & LC_SLEEPABLE) {
    241     lock_state = class->lc_unlock(lock);
    242   }
    243 
    244   rval = sleep_queue_timedwait(ident, pri, timo, catch);
    245 
    246 #ifdef KTRACE
    247   if (KTRPOINT(td, KTR_CSW))
    248     ktrcsw(0, 0);
    249 #endif
    250   PICKUP_GIANT();
    251   if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) {
    252     class->lc_lock(lock, lock_state);
    253   }
    254   return (rval);
     138        WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
     139            "Sleeping on \"%s\"", wmesg);
     140        KASSERT(timo != 0 || mtx_owned(&Giant) || lock != NULL,
     141            ("sleeping without a lock"));
     142        KASSERT(p != NULL, ("msleep1"));
     143        KASSERT(wchan != NULL && TD_IS_RUNNING(td), ("msleep"));
     144        if (priority & PDROP)
     145                KASSERT(lock != NULL && lock != &Giant.lock_object,
     146                    ("PDROP requires a non-Giant lock"));
     147        if (lock != NULL)
     148                class = LOCK_CLASS(lock);
     149        else
     150                class = NULL;
     151
     152        if (lock == &Giant.lock_object)
     153                mtx_assert(&Giant, MA_OWNED);
     154        DROP_GIANT();
     155
     156        td = curthread;
     157
     158        _Thread_Disable_dispatch();
     159
     160        if (lock != NULL) {
     161                lock_state = class->lc_unlock(lock);
     162        }
     163
     164        sc = SC_LOOKUP(wchan);
     165
     166        /* Look up the sleep queue associated with the wait channel 'wchan'. */
     167        sq = sleepq_lookup(wchan);
     168
     169        /*
     170         * If the wait channel does not already have a sleep queue, use
     171         * this thread's sleep queue.  Otherwise, insert the current thread
     172         * into the sleep queue already in use by this wait channel.
     173         */
     174        if (sq == NULL) {
     175                sq = td->td_sleepqueue;
     176                LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash);
     177                sq->sq_wchan = wchan;
     178        } else {
     179                LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash);
     180        }
     181        td->td_sleepqueue = NULL;
     182
     183        _Thread_queue_Enter_critical_section(&sq->sq_blocked);
     184        executing = _Thread_Executing;
     185        executing->Wait.queue = &sq->sq_blocked;
     186        _Thread_queue_Enqueue(&sq->sq_blocked, executing, (Watchdog_Interval) timo);
     187
     188        _Thread_Enable_dispatch();
     189
     190        rval = (int) executing->Wait.return_code;
     191
     192        _Thread_Disable_dispatch();
     193
     194        /*
     195         * Get a sleep queue for this thread.  If this is the last waiter,
     196         * use the queue itself and take it out of the chain, otherwise,
     197         * remove a queue from the free list.
     198         */
     199        if (LIST_EMPTY(&sq->sq_free)) {
     200                td->td_sleepqueue = sq;
     201        } else
     202                td->td_sleepqueue = LIST_FIRST(&sq->sq_free);
     203        LIST_REMOVE(td->td_sleepqueue, sq_hash);
     204
     205        _Thread_Enable_dispatch();
     206
     207        PICKUP_GIANT();
     208        if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) {
     209                class->lc_lock(lock, lock_state);
     210                WITNESS_RESTORE(lock, lock_witness);
     211        }
     212
     213        return (rval);
    255214}
    256215
     
    265224{
    266225
    267   KASSERT(timo != 0, ("pause: timeout required"));
    268   return (tsleep(&pause_wchan, 0, wmesg, timo));
    269 }
    270 
    271 /*
    272  * Make all threads sleeping on the specified identifier runnable.
    273  */
     226        KASSERT(timo != 0, ("pause: timeout required"));
     227        return (tsleep(&pause_wchan, 0, wmesg, timo));
     228}
     229
     230static void
     231rtems_bsd_sleepq_wakeup(struct sleepqueue *sq, Thread_Control *thread)
     232{
     233        thread->Wait.return_code = 0;
     234}
     235
    274236void
    275 wakeup(void *ident)
    276 {
    277   sleep_queue_control_t *sq;
    278   Thread_Control *the_thread;
    279 
    280   sq = sleep_queue_lookup( ident );
    281   if (sq == NULL)
    282   {
    283     return (0);
    284   }
    285 
    286   while ( (the_thread = _Thread_queue_Dequeue(&sq->queue)) )
    287   {
    288   }
    289   return 0;
    290 }
    291 
    292 /*
    293  * Make a thread sleeping on the specified identifier runnable.
    294  * May wake more than one thread if a target thread is currently
    295  * swapped out.
    296  */
     237wakeup(void *wchan)
     238{
     239        struct sleepqueue *sq;
     240
     241        _Thread_Disable_dispatch();
     242
     243        sq = sleepq_lookup(wchan);
     244        if (sq != NULL) {
     245                Thread_Control *thread;
     246
     247                while ((thread = _Thread_queue_Dequeue(&sq->sq_blocked)) != NULL) {
     248                        rtems_bsd_sleepq_wakeup(sq, thread);
     249                }
     250        }
     251
     252        _Thread_Enable_dispatch();
     253}
     254
    297255void
    298 wakeup_one(void *ident)
    299 {
    300   sleep_queue_control_t *sq;
    301   Thread_Control *the_thread;
    302 
    303   sq = sleep_queue_lookup( ident );
    304   if (sq == NULL)
    305   {
    306     return (0);
    307   }
    308   the_thread = _Thread_queue_Dequeue(&sq->queue);
    309   return 0;
    310 
    311 }
    312 
     256wakeup_one(void *wchan)
     257{
     258        struct sleepqueue *sq;
     259
     260        _Thread_Disable_dispatch();
     261
     262        sq = sleepq_lookup(wchan);
     263        if (sq != NULL) {
     264                Thread_Control *thread;
     265
     266                thread = _Thread_queue_Dequeue(&sq->sq_blocked);
     267                if (thread != NULL) {
     268                        rtems_bsd_sleepq_wakeup(sq, thread);
     269                }
     270        }
     271
     272        _Thread_Enable_dispatch();
     273}
  • rtemsbsd/rtems/rtems-bsd-mutex.c

    r24732b6 rf9c2714  
    5454static void assert_mtx(struct lock_object *lock, int what);
    5555static void lock_mtx(struct lock_object *lock, int how);
    56 static void lock_spin(struct lock_object *lock, int how);
    5756#ifdef KDTRACE_HOOKS
    5857static int  owner_mtx(struct lock_object *lock, struct thread **owner);
    5958#endif
    6059static int  unlock_mtx(struct lock_object *lock);
    61 static int  unlock_spin(struct lock_object *lock);
    6260
    6361RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_mtx_chain);
     
    8785  .lc_ddb_show = db_show_mtx,
    8886#endif
    89   .lc_lock = lock_spin,
    90   .lc_unlock = unlock_spin,
     87  .lc_lock = lock_mtx,
     88  .lc_unlock = unlock_mtx,
    9189#ifdef KDTRACE_HOOKS
    9290  .lc_owner = owner_mtx,
     
    107105
    108106  mtx_lock((struct mtx *)lock);
    109 }
    110 
    111 void
    112 lock_spin(struct lock_object *lock, int how)
    113 {
    114 
    115   panic("spin locks can only use msleep_spin");
    116107}
    117108
     
    127118}
    128119
    129 int
    130 unlock_spin(struct lock_object *lock)
    131 {
    132 
    133   panic("spin locks can only use msleep_spin");
    134 }
    135120
    136121#ifdef KDTRACE_HOOKS
  • rtemsbsd/rtems/rtems-bsd-thread.c

    r24732b6 rf9c2714  
    5050#include <sys/selinfo.h>
    5151
     52#include <rtems/score/objectimpl.h>
     53#include <rtems/score/statesimpl.h>
     54#include <rtems/score/threaddispatch.h>
     55#include <rtems/score/thread.h>
    5256#include <rtems/score/threadimpl.h>
    53 #include <rtems/score/objectimpl.h>
     57#include <rtems/score/threadqimpl.h>
    5458
    5559RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_thread_chain);
     
    9296{
    9397        struct thread *td = malloc(sizeof(*td), M_TEMP, M_ZERO | wait);
    94 
    95         if (td != NULL) {
     98        struct sleepqueue *sq = malloc(sizeof(*sq), M_TEMP, wait);
     99
     100        if (td != NULL && sq != NULL) {
    96101                td->td_thread = thread;
     102                td->td_sleepqueue = sq;
     103
     104                LIST_INIT(&sq->sq_free);
     105
     106                _Thread_queue_Initialize(
     107                        &sq->sq_blocked,
     108                        THREAD_QUEUE_DISCIPLINE_PRIORITY,
     109                        STATES_WAITING_FOR_BSD_WAKEUP,
     110                        EWOULDBLOCK
     111                );
     112        } else {
     113                free(td, M_TEMP);
     114                free(sq, M_TEMP);
     115                td = NULL;
    97116        }
    98117
     
    168187                }
    169188
     189                free(td->td_sleepqueue, M_TEMP);
    170190                free(td, M_TEMP);
    171191        }
Note: See TracChangeset for help on using the changeset viewer.