Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/waitq.c

    r1d432f9 r6c4a56f  
    3333/**
    3434 * @file
    35  * @brief Wait queue.
     35 * @brief       Wait queue.
    3636 *
    3737 * Wait queue is the basic synchronization primitive upon which all
     
    4141 * fashion. Conditional operation as well as timeouts and interruptions
    4242 * are supported.
    43  *
    4443 */
    4544
     
    5049#include <proc/scheduler.h>
    5150#include <arch/asm.h>
    52 #include <typedefs.h>
     51#include <arch/types.h>
    5352#include <time/timeout.h>
    5453#include <arch.h>
    5554#include <context.h>
    5655#include <adt/list.h>
    57 #include <arch/cycle.h>
    58 
    59 static void waitq_sleep_timed_out(void *);
     56
     57static void waitq_sleep_timed_out(void *data);
    6058
    6159/** Initialize wait queue
     
    6361 * Initialize wait queue.
    6462 *
    65  * @param wq Pointer to wait queue to be initialized.
    66  *
     63 * @param wq            Pointer to wait queue to be initialized.
    6764 */
    6865void waitq_initialize(waitq_t *wq)
    6966{
    70         irq_spinlock_initialize(&wq->lock, "wq.lock");
     67        spinlock_initialize(&wq->lock, "waitq_lock");
    7168        list_initialize(&wq->head);
    7269        wq->missed_wakeups = 0;
     
    8380 * timeout at all.
    8481 *
    85  * @param data Pointer to the thread that called waitq_sleep_timeout().
    86  *
     82 * @param data          Pointer to the thread that called waitq_sleep_timeout().
    8783 */
    8884void waitq_sleep_timed_out(void *data)
    8985{
    90         thread_t *thread = (thread_t *) data;
     86        thread_t *t = (thread_t *) data;
     87        waitq_t *wq;
    9188        bool do_wakeup = false;
    9289        DEADLOCK_PROBE_INIT(p_wqlock);
    93        
    94         irq_spinlock_lock(&threads_lock, false);
    95         if (!thread_exists(thread))
     90
     91        spinlock_lock(&threads_lock);
     92        if (!thread_exists(t))
    9693                goto out;
    97        
     94
    9895grab_locks:
    99         irq_spinlock_lock(&thread->lock, false);
    100        
    101         waitq_t *wq;
    102         if ((wq = thread->sleep_queue)) {  /* Assignment */
    103                 if (!irq_spinlock_trylock(&wq->lock)) {
    104                         irq_spinlock_unlock(&thread->lock, false);
     96        spinlock_lock(&t->lock);
     97        if ((wq = t->sleep_queue)) {            /* assignment */
     98                if (!spinlock_trylock(&wq->lock)) {
     99                        spinlock_unlock(&t->lock);
    105100                        DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
    106                         /* Avoid deadlock */
    107                         goto grab_locks;
    108                 }
    109                
    110                 list_remove(&thread->wq_link);
    111                 thread->saved_context = thread->sleep_timeout_context;
     101                        goto grab_locks;        /* avoid deadlock */
     102                }
     103
     104                list_remove(&t->wq_link);
     105                t->saved_context = t->sleep_timeout_context;
    112106                do_wakeup = true;
    113                 thread->sleep_queue = NULL;
    114                 irq_spinlock_unlock(&wq->lock, false);
    115         }
    116        
    117         thread->timeout_pending = false;
    118         irq_spinlock_unlock(&thread->lock, false);
     107                t->sleep_queue = NULL;
     108                spinlock_unlock(&wq->lock);
     109        }
     110       
     111        t->timeout_pending = false;
     112        spinlock_unlock(&t->lock);
    119113       
    120114        if (do_wakeup)
    121                 thread_ready(thread);
    122        
     115                thread_ready(t);
     116
    123117out:
    124         irq_spinlock_unlock(&threads_lock, false);
     118        spinlock_unlock(&threads_lock);
    125119}
    126120
     
    130124 * If the thread is not found sleeping, no action is taken.
    131125 *
    132  * @param thread Thread to be interrupted.
    133  *
    134  */
    135 void waitq_interrupt_sleep(thread_t *thread)
    136 {
     126 * @param t             Thread to be interrupted.
     127 */
     128void waitq_interrupt_sleep(thread_t *t)
     129{
     130        waitq_t *wq;
    137131        bool do_wakeup = false;
     132        ipl_t ipl;
    138133        DEADLOCK_PROBE_INIT(p_wqlock);
    139        
    140         irq_spinlock_lock(&threads_lock, true);
    141         if (!thread_exists(thread))
     134
     135        ipl = interrupts_disable();
     136        spinlock_lock(&threads_lock);
     137        if (!thread_exists(t))
    142138                goto out;
    143        
     139
    144140grab_locks:
    145         irq_spinlock_lock(&thread->lock, false);
    146        
    147         waitq_t *wq;
    148         if ((wq = thread->sleep_queue)) {  /* Assignment */
    149                 if (!(thread->sleep_interruptible)) {
     141        spinlock_lock(&t->lock);
     142        if ((wq = t->sleep_queue)) {            /* assignment */
     143                if (!(t->sleep_interruptible)) {
    150144                        /*
    151145                         * The sleep cannot be interrupted.
    152                          *
    153146                         */
    154                         irq_spinlock_unlock(&thread->lock, false);
     147                        spinlock_unlock(&t->lock);
    155148                        goto out;
    156149                }
    157                
    158                 if (!irq_spinlock_trylock(&wq->lock)) {
    159                         irq_spinlock_unlock(&thread->lock, false);
     150                       
     151                if (!spinlock_trylock(&wq->lock)) {
     152                        spinlock_unlock(&t->lock);
    160153                        DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
    161                         /* Avoid deadlock */
    162                         goto grab_locks;
    163                 }
    164                
    165                 if ((thread->timeout_pending) &&
    166                     (timeout_unregister(&thread->sleep_timeout)))
    167                         thread->timeout_pending = false;
    168                
    169                 list_remove(&thread->wq_link);
    170                 thread->saved_context = thread->sleep_interruption_context;
     154                        goto grab_locks;        /* avoid deadlock */
     155                }
     156
     157                if (t->timeout_pending && timeout_unregister(&t->sleep_timeout))
     158                        t->timeout_pending = false;
     159
     160                list_remove(&t->wq_link);
     161                t->saved_context = t->sleep_interruption_context;
    171162                do_wakeup = true;
    172                 thread->sleep_queue = NULL;
    173                 irq_spinlock_unlock(&wq->lock, false);
    174         }
    175         irq_spinlock_unlock(&thread->lock, false);
    176        
     163                t->sleep_queue = NULL;
     164                spinlock_unlock(&wq->lock);
     165        }
     166        spinlock_unlock(&t->lock);
     167
    177168        if (do_wakeup)
    178                 thread_ready(thread);
    179        
     169                thread_ready(t);
     170
    180171out:
    181         irq_spinlock_unlock(&threads_lock, true);
     172        spinlock_unlock(&threads_lock);
     173        interrupts_restore(ipl);
    182174}
    183175
     
    187179 * is sleeping interruptibly.
    188180 *
    189  * @param wq Pointer to wait queue.
    190  *
     181 * @param wq            Pointer to wait queue.
    191182 */
    192183void waitq_unsleep(waitq_t *wq)
    193184{
    194         irq_spinlock_lock(&wq->lock, true);
    195        
     185        ipl_t ipl;
     186
     187        ipl = interrupts_disable();
     188        spinlock_lock(&wq->lock);
     189
    196190        if (!list_empty(&wq->head)) {
    197                 thread_t *thread = list_get_instance(wq->head.next, thread_t, wq_link);
     191                thread_t *t;
    198192               
    199                 irq_spinlock_lock(&thread->lock, false);
    200                
    201                 ASSERT(thread->sleep_interruptible);
    202                
    203                 if ((thread->timeout_pending) &&
    204                     (timeout_unregister(&thread->sleep_timeout)))
    205                         thread->timeout_pending = false;
    206                
    207                 list_remove(&thread->wq_link);
    208                 thread->saved_context = thread->sleep_interruption_context;
    209                 thread->sleep_queue = NULL;
    210                
    211                 irq_spinlock_unlock(&thread->lock, false);
    212                 thread_ready(thread);
    213         }
    214        
    215         irq_spinlock_unlock(&wq->lock, true);
    216 }
    217 
    218 #define PARAM_NON_BLOCKING(flags, usec) \
    219         (((flags) & SYNCH_FLAGS_NON_BLOCKING) && ((usec) == 0))
     193                t = list_get_instance(wq->head.next, thread_t, wq_link);
     194                spinlock_lock(&t->lock);
     195                ASSERT(t->sleep_interruptible);
     196                if (t->timeout_pending && timeout_unregister(&t->sleep_timeout))
     197                        t->timeout_pending = false;
     198                list_remove(&t->wq_link);
     199                t->saved_context = t->sleep_interruption_context;
     200                t->sleep_queue = NULL;
     201                spinlock_unlock(&t->lock);
     202                thread_ready(t);
     203        }
     204
     205        spinlock_unlock(&wq->lock);
     206        interrupts_restore(ipl);
     207}
    220208
    221209/** Sleep until either wakeup, timeout or interruption occurs
     
    229217 * and all the *_timeout() functions use it.
    230218 *
    231  * @param wq    Pointer to wait queue.
    232  * @param usec  Timeout in microseconds.
    233  * @param flags Specify mode of the sleep.
     219 * @param wq            Pointer to wait queue.
     220 * @param usec          Timeout in microseconds.
     221 * @param flags         Specify mode of the sleep.
    234222 *
    235223 * The sleep can be interrupted only if the
    236224 * SYNCH_FLAGS_INTERRUPTIBLE bit is specified in flags.
    237  *
     225 * 
    238226 * If usec is greater than zero, regardless of the value of the
    239227 * SYNCH_FLAGS_NON_BLOCKING bit in flags, the call will not return until either
    240  * timeout, interruption or wakeup comes.
     228 * timeout, interruption or wakeup comes. 
    241229 *
    242230 * If usec is zero and the SYNCH_FLAGS_NON_BLOCKING bit is not set in flags,
     
    246234 * call will immediately return, reporting either success or failure.
    247235 *
    248  * @return ESYNCH_WOULD_BLOCK, meaning that the sleep failed because at the
    249  *         time of the call there was no pending wakeup
    250  * @return ESYNCH_TIMEOUT, meaning that the sleep timed out.
    251  * @return ESYNCH_INTERRUPTED, meaning that somebody interrupted the sleeping
    252  *         thread.
    253  * @return ESYNCH_OK_ATOMIC, meaning that the sleep succeeded and that there
    254  *         was a pending wakeup at the time of the call. The caller was not put
    255  *         asleep at all.
    256  * @return ESYNCH_OK_BLOCKED, meaning that the sleep succeeded; the full sleep
    257  *         was attempted.
    258  *
    259  */
    260 int waitq_sleep_timeout(waitq_t *wq, uint32_t usec, unsigned int flags)
    261 {
    262         ASSERT((!PREEMPTION_DISABLED) || (PARAM_NON_BLOCKING(flags, usec)));
    263        
    264         ipl_t ipl = waitq_sleep_prepare(wq);
    265         int rc = waitq_sleep_timeout_unsafe(wq, usec, flags);
     236 * @return              Returns one of ESYNCH_WOULD_BLOCK, ESYNCH_TIMEOUT,
     237 *                      ESYNCH_INTERRUPTED, ESYNCH_OK_ATOMIC and
     238 *                      ESYNCH_OK_BLOCKED.
     239 *
     240 * @li  ESYNCH_WOULD_BLOCK means that the sleep failed because at the time of
     241 *      the call there was no pending wakeup.
     242 *
     243 * @li  ESYNCH_TIMEOUT means that the sleep timed out.
     244 *
     245 * @li  ESYNCH_INTERRUPTED means that somebody interrupted the sleeping thread.
     246 *
     247 * @li  ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was
     248 *      a pending wakeup at the time of the call. The caller was not put
     249 *      asleep at all.
     250 *
     251 * @li  ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was
     252 *      attempted.
     253 */
     254int waitq_sleep_timeout(waitq_t *wq, uint32_t usec, int flags)
     255{
     256        ipl_t ipl;
     257        int rc;
     258       
     259        ipl = waitq_sleep_prepare(wq);
     260        rc = waitq_sleep_timeout_unsafe(wq, usec, flags);
    266261        waitq_sleep_finish(wq, rc, ipl);
    267262        return rc;
     
    273268 * and interrupts disabled.
    274269 *
    275  * @param wq Wait queue.
    276  *
    277  * @return Interrupt level as it existed on entry to this function.
    278  *
     270 * @param wq            Wait queue.
     271 *
     272 * @return              Interrupt level as it existed on entry to this function.
    279273 */
    280274ipl_t waitq_sleep_prepare(waitq_t *wq)
     
    284278restart:
    285279        ipl = interrupts_disable();
    286        
    287         if (THREAD) {  /* Needed during system initiailzation */
     280
     281        if (THREAD) {   /* needed during system initiailzation */
    288282                /*
    289283                 * Busy waiting for a delayed timeout.
     
    292286                 * Simply, the thread is not allowed to go to sleep if
    293287                 * there are timeouts in progress.
    294                  *
    295288                 */
    296                 irq_spinlock_lock(&THREAD->lock, false);
    297                
     289                spinlock_lock(&THREAD->lock);
    298290                if (THREAD->timeout_pending) {
    299                         irq_spinlock_unlock(&THREAD->lock, false);
     291                        spinlock_unlock(&THREAD->lock);
    300292                        interrupts_restore(ipl);
    301293                        goto restart;
    302294                }
    303                
    304                 irq_spinlock_unlock(&THREAD->lock, false);
    305         }
    306        
    307         irq_spinlock_lock(&wq->lock, false);
     295                spinlock_unlock(&THREAD->lock);
     296        }
     297                                                                                                       
     298        spinlock_lock(&wq->lock);
    308299        return ipl;
    309300}
     
    315306 * lock is released.
    316307 *
    317  * @param wq  Wait queue.
    318  * @param rc  Return code of waitq_sleep_timeout_unsafe().
    319  * @param ipl Interrupt level returned by waitq_sleep_prepare().
    320  *
     308 * @param wq            Wait queue.
     309 * @param rc            Return code of waitq_sleep_timeout_unsafe().
     310 * @param ipl           Interrupt level returned by waitq_sleep_prepare().
    321311 */
    322312void waitq_sleep_finish(waitq_t *wq, int rc, ipl_t ipl)
     
    325315        case ESYNCH_WOULD_BLOCK:
    326316        case ESYNCH_OK_ATOMIC:
    327                 irq_spinlock_unlock(&wq->lock, false);
     317                spinlock_unlock(&wq->lock);
    328318                break;
    329319        default:
    330320                break;
    331321        }
    332        
    333322        interrupts_restore(ipl);
    334323}
     
    340329 * and followed by a call to waitq_sleep_finish().
    341330 *
    342  * @param wq    See waitq_sleep_timeout().
    343  * @param usec  See waitq_sleep_timeout().
    344  * @param flags See waitq_sleep_timeout().
    345  *
    346  * @return See waitq_sleep_timeout().
    347  *
    348  */
    349 int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, unsigned int flags)
    350 {
    351         /* Checks whether to go to sleep at all */
     331 * @param wq            See waitq_sleep_timeout().
     332 * @param usec          See waitq_sleep_timeout().
     333 * @param flags         See waitq_sleep_timeout().
     334 *
     335 * @return              See waitq_sleep_timeout().
     336 */
     337int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, int flags)
     338{
     339        /* checks whether to go to sleep at all */
    352340        if (wq->missed_wakeups) {
    353341                wq->missed_wakeups--;
    354342                return ESYNCH_OK_ATOMIC;
    355         } else {
    356                 if (PARAM_NON_BLOCKING(flags, usec)) {
    357                         /* Return immediatelly instead of going to sleep */
     343        }
     344        else {
     345                if ((flags & SYNCH_FLAGS_NON_BLOCKING) && (usec == 0)) {
     346                        /* return immediatelly instead of going to sleep */
    358347                        return ESYNCH_WOULD_BLOCK;
    359348                }
     
    362351        /*
    363352         * Now we are firmly decided to go to sleep.
    364          *
    365353         */
    366         irq_spinlock_lock(&THREAD->lock, false);
    367        
     354        spinlock_lock(&THREAD->lock);
     355
    368356        if (flags & SYNCH_FLAGS_INTERRUPTIBLE) {
     357
    369358                /*
    370359                 * If the thread was already interrupted,
    371360                 * don't go to sleep at all.
    372                  *
    373361                 */
    374362                if (THREAD->interrupted) {
    375                         irq_spinlock_unlock(&THREAD->lock, false);
    376                         irq_spinlock_unlock(&wq->lock, false);
     363                        spinlock_unlock(&THREAD->lock);
     364                        spinlock_unlock(&wq->lock);
    377365                        return ESYNCH_INTERRUPTED;
    378366                }
    379                
     367
    380368                /*
    381369                 * Set context that will be restored if the sleep
    382370                 * of this thread is ever interrupted.
    383                  *
    384371                 */
    385372                THREAD->sleep_interruptible = true;
    386373                if (!context_save(&THREAD->sleep_interruption_context)) {
    387374                        /* Short emulation of scheduler() return code. */
    388                         THREAD->last_cycle = get_cycle();
    389                         irq_spinlock_unlock(&THREAD->lock, false);
     375                        spinlock_unlock(&THREAD->lock);
    390376                        return ESYNCH_INTERRUPTED;
    391377                }
    392         } else
     378
     379        } else {
    393380                THREAD->sleep_interruptible = false;
    394        
     381        }
     382
    395383        if (usec) {
    396384                /* We use the timeout variant. */
    397385                if (!context_save(&THREAD->sleep_timeout_context)) {
    398386                        /* Short emulation of scheduler() return code. */
    399                         THREAD->last_cycle = get_cycle();
    400                         irq_spinlock_unlock(&THREAD->lock, false);
     387                        spinlock_unlock(&THREAD->lock);
    401388                        return ESYNCH_TIMEOUT;
    402389                }
    403                
    404390                THREAD->timeout_pending = true;
    405391                timeout_register(&THREAD->sleep_timeout, (uint64_t) usec,
    406392                    waitq_sleep_timed_out, THREAD);
    407393        }
    408        
     394
    409395        list_append(&THREAD->wq_link, &wq->head);
    410        
     396
    411397        /*
    412398         * Suspend execution.
    413          *
    414399         */
    415400        THREAD->state = Sleeping;
    416401        THREAD->sleep_queue = wq;
    417        
    418         irq_spinlock_unlock(&THREAD->lock, false);
    419        
     402
     403        spinlock_unlock(&THREAD->lock);
     404
    420405        /* wq->lock is released in scheduler_separated_stack() */
    421         scheduler();
     406        scheduler(); 
    422407       
    423408        return ESYNCH_OK_BLOCKED;
    424409}
     410
    425411
    426412/** Wake up first thread sleeping in a wait queue
     
    432418 * timeout.
    433419 *
    434  * @param wq   Pointer to wait queue.
    435  * @param mode Wakeup mode.
    436  *
     420 * @param wq            Pointer to wait queue.
     421 * @param mode          Wakeup mode.
    437422 */
    438423void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode)
    439424{
    440         irq_spinlock_lock(&wq->lock, true);
     425        ipl_t ipl;
     426
     427        ipl = interrupts_disable();
     428        spinlock_lock(&wq->lock);
     429
    441430        _waitq_wakeup_unsafe(wq, mode);
    442         irq_spinlock_unlock(&wq->lock, true);
     431
     432        spinlock_unlock(&wq->lock);
     433        interrupts_restore(ipl);
    443434}
    444435
     
    448439 * assumes wq->lock is already locked and interrupts are already disabled.
    449440 *
    450  * @param wq   Pointer to wait queue.
    451  * @param mode If mode is WAKEUP_FIRST, then the longest waiting
    452  *             thread, if any, is woken up. If mode is WAKEUP_ALL, then
    453  *             all waiting threads, if any, are woken up. If there are
    454  *             no waiting threads to be woken up, the missed wakeup is
    455  *             recorded in the wait queue.
    456  *
     441 * @param wq            Pointer to wait queue.
     442 * @param mode          If mode is WAKEUP_FIRST, then the longest waiting
     443 *                      thread, if any, is woken up. If mode is WAKEUP_ALL, then
     444 *                      all waiting threads, if any, are woken up. If there are
     445 *                      no waiting threads to be woken up, the missed wakeup is
     446 *                      recorded in the wait queue.
    457447 */
    458448void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode)
    459449{
     450        thread_t *t;
    460451        size_t count = 0;
    461452
    462         ASSERT(interrupts_disabled());
    463         ASSERT(irq_spinlock_locked(&wq->lock));
    464        
    465 loop:
     453loop:   
    466454        if (list_empty(&wq->head)) {
    467455                wq->missed_wakeups++;
    468                 if ((count) && (mode == WAKEUP_ALL))
     456                if (count && mode == WAKEUP_ALL)
    469457                        wq->missed_wakeups--;
    470                
    471458                return;
    472459        }
    473        
     460
    474461        count++;
    475         thread_t *thread = list_get_instance(wq->head.next, thread_t, wq_link);
     462        t = list_get_instance(wq->head.next, thread_t, wq_link);
    476463       
    477464        /*
     
    485472         * invariant must hold:
    486473         *
    487          * thread->sleep_queue != NULL <=> thread sleeps in a wait queue
     474         * t->sleep_queue != NULL <=> t sleeps in a wait queue
    488475         *
    489476         * For an observer who locks the thread, the invariant
    490477         * holds only when the lock is held prior to removing
    491478         * it from the wait queue.
    492          *
    493479         */
    494         irq_spinlock_lock(&thread->lock, false);
    495         list_remove(&thread->wq_link);
    496        
    497         if ((thread->timeout_pending) &&
    498             (timeout_unregister(&thread->sleep_timeout)))
    499                 thread->timeout_pending = false;
    500        
    501         thread->sleep_queue = NULL;
    502         irq_spinlock_unlock(&thread->lock, false);
    503        
    504         thread_ready(thread);
    505        
     480        spinlock_lock(&t->lock);
     481        list_remove(&t->wq_link);
     482       
     483        if (t->timeout_pending && timeout_unregister(&t->sleep_timeout))
     484                t->timeout_pending = false;
     485        t->sleep_queue = NULL;
     486        spinlock_unlock(&t->lock);
     487
     488        thread_ready(t);
     489
    506490        if (mode == WAKEUP_ALL)
    507491                goto loop;
    508492}
    509493
    510 /** Get the missed wakeups count.
    511  *
    512  * @param wq    Pointer to wait queue.
    513  * @return      The wait queue's missed_wakeups count.
    514  */
    515 int waitq_count_get(waitq_t *wq)
    516 {
    517         int cnt;
    518 
    519         irq_spinlock_lock(&wq->lock, true);
    520         cnt = wq->missed_wakeups;
    521         irq_spinlock_unlock(&wq->lock, true);
    522 
    523         return cnt;
    524 }
    525 
    526 /** Set the missed wakeups count.
    527  *
    528  * @param wq    Pointer to wait queue.
    529  * @param val   New value of the missed_wakeups count.
    530  */
    531 void waitq_count_set(waitq_t *wq, int val)
    532 {
    533         irq_spinlock_lock(&wq->lock, true);
    534         wq->missed_wakeups = val;
    535         irq_spinlock_unlock(&wq->lock, true);
    536 }
    537 
    538494/** @}
    539495 */
Note: See TracChangeset for help on using the changeset viewer.