Annotation of XNU/osfmk/kern/wait_queue.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_FREE_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: /*
                     53:  *     File:   wait_queue.c (adapted from sched_prim.c)
                     54:  *     Author: Avadis Tevanian, Jr.
                     55:  *     Date:   1986
                     56:  *
                     57:  *     Primitives for manipulating wait queues: either global
                     58:  *     ones from sched_prim.c, or private ones associated with
                     59:  *     particular structures(pots, semaphores, etc..).
                     60:  */
                     61: 
                     62: #include <kern/kern_types.h>
                     63: #include <kern/simple_lock.h>
                     64: #include <kern/queue.h>
                     65: #include <kern/spl.h>
                     66: 
                     67: #include <mach/sync_policy.h>
                     68: 
                     69: #include <kern/sched_prim.h>
                     70: #include <kern/wait_queue.h>
                     71: 
                     72: void
                     73: wait_queue_init(
                     74:         wait_queue_t wq,
                     75:        int policy)
                     76: {
                     77:        wq->wq_fifo = (policy == SYNC_POLICY_FIFO);
                     78:        wq->wq_issub = FALSE;
                     79:        queue_init(&wq->wq_queue);
                     80:        hw_lock_init(&wq->wq_interlock);
                     81: }
                     82: 
                     83: void
                     84: wait_queue_sub_init(
                     85:         wait_queue_sub_t wqsub,
                     86:        int policy)
                     87: {
                     88:        wait_queue_init(&wqsub->wqs_wait_queue, policy);
                     89:        wqsub->wqs_wait_queue.wq_issub = TRUE;
                     90:        queue_init(&wqsub->wqs_sublinks);
                     91: }
                     92: 
                     93: void
                     94: wait_queue_link_init(
                     95:        wait_queue_link_t wql)
                     96: {
                     97:        queue_init(&wql->wql_links);
                     98:        queue_init(&wql->wql_sublinks);
                     99:        wql->wql_queue = WAIT_QUEUE_NULL;
                    100:        wql->wql_subqueue = WAIT_QUEUE_SUB_NULL;
                    101:        wql->wql_event = NO_EVENT;
                    102: }
                    103: 
                    104: 
                    105: /*
                    106:  *     Routine:        wait_queue_lock
                    107:  *     Purpose:
                    108:  *             Lock the wait queue.
                    109:  *     Conditions:
                    110:  *             the appropriate spl level (if any) is already raised.
                    111:  */
                    112: void
                    113: wait_queue_lock(
                    114:         wait_queue_t wq)
                    115: {
                    116: #ifdef __ppc__
                    117:        vm_offset_t pc;
                    118: 
                    119:        pc = GET_RETURN_PC(&wq);
                    120:        if (!hw_lock_to(&wq->wq_interlock, LockTimeOut)) {
                    121:                panic("wait queue deadlock detection - wq=0x%x, cpu=%d, ret=0x%x\n", wq, cpu_number(), pc);
                    122:        }
                    123: #else
                    124:        hw_lock_lock(&wq->wq_interlock);
                    125: #endif
                    126: }
                    127: 
                    128: /*
                    129:  *     Routine:        wait_queue_lock_try
                    130:  *     Purpose:
                    131:  *             Try to lock the wait queue without waiting
                    132:  *     Conditions:
                    133:  *             the appropriate spl level (if any) is already raised.
                    134:  *  Returns:
                    135:  *             TRUE if the lock was acquired
                    136:  *             FALSE if we would have needed to wait
                    137:  */
                    138: boolean_t
                    139: wait_queue_lock_try(
                    140:         wait_queue_t wq)
                    141: {
                    142:        return hw_lock_try(&wq->wq_interlock);
                    143: }
                    144: 
                    145: /*
                    146:  *     Routine:        wait_queue_unlock
                    147:  *     Purpose:
                    148:  *             unlock the wait queue
                    149:  *     Conditions:
                    150:  *             The wait queue is assumed locked.
                    151:  *             appropriate spl level is still maintained
                    152:  */
                    153: void
                    154: wait_queue_unlock(
                    155:        wait_queue_t wq)
                    156: {
                    157:        assert(hw_lock_held(&wq->wq_interlock));
                    158: 
                    159:        hw_lock_unlock(&wq->wq_interlock);
                    160: }
                    161: 
                    162: int _wait_queue_subordinate; /* phoney event for subordinate wait q elements */
                    163: 
                    164:        
                    165: /*
                    166:  *     Routine:        wait_queue_member_locked
                    167:  *     Purpose:
                    168:  *             Indicate if this sub queue is a member of the queue
                    169:  *     Conditions:
                    170:  *             The wait queue is locked
                    171:  *             The sub queue is just that, a sub queue
                    172:  */
                    173: boolean_t
                    174: wait_queue_member_locked(
                    175:        wait_queue_t wq,
                    176:        wait_queue_sub_t wq_sub)
                    177: {
                    178:        wait_queue_element_t wq_element;
                    179:        queue_t q;
                    180: 
                    181:        assert(wait_queue_held(wq));
                    182:        assert(wait_queue_is_sub(wq_sub));
                    183: 
                    184:        q = &wq->wq_queue;
                    185: 
                    186:        wq_element = (wait_queue_element_t) queue_first(q);
                    187:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    188: 
                    189:                if ((wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE)) {
                    190:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    191: 
                    192:                        if (wql->wql_subqueue == wq_sub)
                    193:                                return TRUE;
                    194:                }
                    195:                wq_element = (wait_queue_element_t)
                    196:                             queue_next((queue_t) wq_element);
                    197:        }
                    198:        return FALSE;
                    199: }
                    200:        
                    201: 
                    202: /*
                    203:  *     Routine:        wait_queue_member
                    204:  *     Purpose:
                    205:  *             Indicate if this sub queue is a member of the queue
                    206:  *     Conditions:
                    207:  *             The sub queue is just that, a sub queue
                    208:  */
                    209: boolean_t
                    210: wait_queue_member(
                    211:        wait_queue_t wq,
                    212:        wait_queue_sub_t wq_sub)
                    213: {
                    214:        boolean_t ret;
                    215: 
                    216:        assert(wait_queue_is_sub(wq_sub));
                    217: 
                    218:        wait_queue_lock(wq);
                    219:        ret = wait_queue_member_locked(wq, wq_sub);
                    220:        wait_queue_unlock(wq);
                    221:        return ret;
                    222: }
                    223: 
                    224: /*
                    225:  *     Routine:        wait_queue_link
                    226:  *     Purpose:
                    227:  *             Insert a subordinate wait queue into a wait queue.  This
                    228:  *             requires us to link the two together using a wait_queue_link
                    229:  *             structure that we allocate.
                    230:  *     Conditions:
                    231:  *             The wait queue being inserted must be inited as a sub queue
                    232:  *             The sub waitq is not already linked
                    233:  *
                    234:  */
                    235: kern_return_t
                    236: wait_queue_link(
                    237:        wait_queue_t wq,
                    238:        wait_queue_sub_t wq_sub)
                    239: {
                    240:        wait_queue_link_t wql;
                    241: 
                    242:        assert(wait_queue_is_sub(wq_sub));
                    243:        assert(!wait_queue_member(wq, wq_sub));
                    244: 
                    245:        wql = (wait_queue_link_t) kalloc(sizeof(struct wait_queue_link));
                    246:        if (wql == WAIT_QUEUE_LINK_NULL)
                    247:                return KERN_RESOURCE_SHORTAGE;
                    248:        
                    249:        wait_queue_link_init(wql);
                    250: 
                    251:        wait_queue_lock(wq);
                    252:        wqs_lock(wq_sub);
                    253: 
                    254:        wql->wql_queue = wq;
                    255:        wql->wql_subqueue = wq_sub;
                    256:        wql->wql_event = WAIT_QUEUE_SUBORDINATE;
                    257:        queue_enter(&wq->wq_queue, wql, wait_queue_link_t, wql_links);
                    258:        queue_enter(&wq_sub->wqs_sublinks, wql, wait_queue_link_t, wql_sublinks);
                    259:        
                    260:        wqs_unlock(wq_sub);
                    261:        wait_queue_unlock(wq);
                    262: 
                    263:        return KERN_SUCCESS;
                    264: }      
                    265: 
                    266: /*
                    267:  *     Routine:        wait_queue_unlink
                    268:  *     Purpose:
                    269:  *             Remove the linkage between a wait queue and its subordinate.
                    270:  *     Conditions:
                    271:  *             The wait queue being must be a member sub queue
                    272:  */
                    273: kern_return_t
                    274: wait_queue_unlink(
                    275:        wait_queue_t wq,
                    276:        wait_queue_sub_t wq_sub)
                    277: {
                    278:        wait_queue_element_t wq_element;
                    279:        queue_t q;
                    280: 
                    281:        assert(wait_queue_is_sub(wq_sub));
                    282:        assert(wait_queue_member(wq, wq_sub));
                    283: 
                    284:        wait_queue_lock(wq);
                    285:        wqs_lock(wq_sub);
                    286: 
                    287:        q = &wq->wq_queue;
                    288: 
                    289:        wq_element = (wait_queue_element_t) queue_first(q);
                    290:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    291: 
                    292:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    293:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    294:                        queue_t sq;
                    295:                        
                    296:                        if (wql->wql_subqueue == wq_sub) {
                    297:                                sq = &wq_sub->wqs_sublinks;
                    298:                                queue_remove(q, wql, wait_queue_link_t, wql_links);
                    299:                                queue_remove(sq, wql, wait_queue_link_t, wql_sublinks);
                    300:                                wqs_unlock(wq_sub);
                    301:                                wait_queue_unlock(wq);
                    302:                                kfree((vm_offset_t)wql,sizeof(struct wait_queue_link));
                    303:                                return;
                    304:                        }
                    305:                }
                    306: 
                    307:                wq_element = (wait_queue_element_t)
                    308:                             queue_next((queue_t) wq_element);
                    309:        }
                    310:        panic("wait_queue_unlink");
                    311: }      
                    312: 
                    313: /*
                    314:  *     Routine:        wait_queue_unlink_one
                    315:  *     Purpose:
                    316:  *             Find and unlink one subordinate wait queue
                    317:  *     Conditions:
                    318:  *             Nothing of interest locked.
                    319:  */
                    320: void
                    321: wait_queue_unlink_one(
                    322:        wait_queue_t wq,
                    323:        wait_queue_sub_t *wq_subp)
                    324: {
                    325:        wait_queue_element_t wq_element;
                    326:        queue_t q;
                    327: 
                    328:        wait_queue_lock(wq);
                    329: 
                    330:        q = &wq->wq_queue;
                    331: 
                    332:        wq_element = (wait_queue_element_t) queue_first(q);
                    333:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    334: 
                    335:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    336:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    337:                        wait_queue_sub_t wq_sub = wql->wql_subqueue;
                    338:                        queue_t sq;
                    339: 
                    340:                        wqs_lock(wq_sub);
                    341:                        sq = &wq_sub->wqs_sublinks;
                    342:                        queue_remove(q, wql, wait_queue_link_t, wql_links);
                    343:                        queue_remove(sq, wql, wait_queue_link_t, wql_sublinks);
                    344:                        wqs_unlock(wq_sub);
                    345:                        wait_queue_unlock(wq);
                    346:                        kfree((vm_offset_t)wql,sizeof(struct wait_queue_link));
                    347:                        *wq_subp = wq_sub;
                    348:                        return;
                    349:                }
                    350: 
                    351:                wq_element = (wait_queue_element_t)
                    352:                             queue_next((queue_t) wq_element);
                    353:        }
                    354:        wait_queue_unlock(wq);
                    355:        *wq_subp = WAIT_QUEUE_SUB_NULL;
                    356: }      
                    357: 
                    358: /*
                    359:  *     Routine:        wait_queue_assert_wait_locked
                    360:  *     Purpose:
                    361:  *             Insert the current thread into the supplied wait queue
                    362:  *             waiting for a particular event to be posted to that queue.
                    363:  *
                    364:  *     Conditions:
                    365:  *             The wait queue is assumed locked.
                    366:  *
                    367:  */
                    368: void
                    369: wait_queue_assert_wait_locked(
                    370:        wait_queue_t wq,
                    371:        event_t event,
                    372:        int interruptible,
                    373:        boolean_t unlock)
                    374: {
                    375:        thread_t thread = current_thread();
                    376:        spl_t s;
                    377: 
                    378:        s = splsched();
                    379:        thread_lock(thread);
                    380: 
                    381:        /*
                    382:         * This is the extent to which we currently take scheduling attributes
                    383:         * into account.  If the thread is vm priviledged, we stick it at
                    384:         * the front of the queue.  Later, these queues will honor the policy
                    385:         * value set at wait_queue_init time.
                    386:         */
                    387:        if (thread->vm_privilege)
                    388:                enqueue_head(&wq->wq_queue, (queue_entry_t) thread);
                    389:        else
                    390:                enqueue_tail(&wq->wq_queue, (queue_entry_t) thread);
                    391:        thread->wait_event = event;
                    392:        thread->wait_queue = wq;
                    393:        thread_mark_wait_locked(thread, interruptible);
                    394:        thread_unlock(thread);
                    395:        splx(s);
                    396:        if (unlock)
                    397:                wait_queue_unlock(wq);
                    398: }
                    399: 
                    400: /*
                    401:  *     Routine:        wait_queue_assert_wait
                    402:  *     Purpose:
                    403:  *             Insert the current thread into the supplied wait queue
                    404:  *             waiting for a particular event to be posted to that queue.
                    405:  *
                    406:  *     Conditions:
                    407:  *             nothing of interest locked.
                    408:  */
                    409: void
                    410: wait_queue_assert_wait(
                    411:        wait_queue_t wq,
                    412:        event_t event,
                    413:        int interruptible)
                    414: {
                    415:        spl_t s;
                    416: 
                    417:        s = splsched();
                    418:        wait_queue_lock(wq);
                    419:        wait_queue_assert_wait_locked(wq, event, interruptible, TRUE);
                    420:        /* wait queue unlocked */
                    421:        splx(s);
                    422: }
                    423: 
                    424: 
                    425: /*
                    426:  *     Routine:        wait_queue_select_all
                    427:  *     Purpose:
                    428:  *             Select all threads off a wait queue that meet the
                    429:  *             supplied criteria.
                    430:  *
                    431:  *     Conditions:
                    432:  *             at splsched
                    433:  *             wait queue locked
                    434:  *             wake_queue initialized and ready for insertion
                    435:  *             possibly recursive
                    436:  *
                    437:  *     Returns:
                    438:  *             a queue of locked threads
                    439:  */
                    440: void
                    441: _wait_queue_select_all(
                    442:        wait_queue_t wq,
                    443:        event_t event,
                    444:        queue_t wake_queue)
                    445: {
                    446:        wait_queue_element_t wq_element;
                    447:        wait_queue_element_t wqe_next;
                    448:        queue_t q;
                    449: 
                    450:        q = &wq->wq_queue;
                    451: 
                    452:        wq_element = (wait_queue_element_t) queue_first(q);
                    453:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    454:                wqe_next = (wait_queue_element_t)
                    455:                           queue_next((queue_t) wq_element);
                    456: 
                    457:                /*
                    458:                 * We may have to recurse if this is a compound wait queue.
                    459:                 */
                    460:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    461:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    462:                        wait_queue_t sub_queue;
                    463: 
                    464:                        /*
                    465:                         * We have to check the subordinate wait queue.
                    466:                         */
                    467:                        sub_queue = (wait_queue_t)wql->wql_subqueue;
                    468:                        wait_queue_lock(sub_queue);
                    469:                        if (! wait_queue_empty(sub_queue)) 
                    470:                                _wait_queue_select_all(sub_queue, event, wake_queue);
                    471:                        wait_queue_unlock(sub_queue);
                    472:                } else {
                    473:                        
                    474:                        /*
                    475:                         * Otherwise, its a thread.  If it is waiting on
                    476:                         * the event we are posting to this queue, pull
                    477:                         * it off the queue and stick it in out wake_queue.
                    478:                         */
                    479:                        thread_t t = (thread_t)wq_element;
                    480: 
                    481:                        if (t->wait_event == event) {
                    482:                                thread_lock(t);
                    483:                                remqueue(q, (queue_entry_t) t);
                    484:                                enqueue (wake_queue, (queue_entry_t) t);
                    485:                                t->wait_queue = WAIT_QUEUE_NULL;
                    486:                                t->wait_event = NO_EVENT;
                    487:                                t->at_safe_point = FALSE;
                    488:                                /* returned locked */
                    489:                        }
                    490:                }
                    491:                wq_element = wqe_next;
                    492:        }
                    493: }
                    494: 
                    495: /*
                    496:  *      Routine:        wait_queue_wakeup_all_locked
                    497:  *      Purpose:
                    498:  *              Wakeup some number of threads that are in the specified
                    499:  *              wait queue and waiting on the specified event.
                    500:  *      Conditions:
                    501:  *              wait queue already locked (may be released).
                    502:  *      Returns:
                    503:  *              KERN_SUCCESS - Threads were woken up
                    504:  *              KERN_NOT_WAITING - No threads were waiting <wq,event> pair
                    505:  */
                    506: kern_return_t
                    507: wait_queue_wakeup_all_locked(
                    508:         wait_queue_t wq,
                    509:         event_t event,
                    510:         int result,
                    511:         boolean_t unlock)
                    512: {
                    513:         queue_head_t wake_queue_head;
                    514:         queue_t q = &wake_queue_head;
                    515:         kern_return_t ret = KERN_NOT_WAITING;
                    516:         spl_t s;
                    517: 
                    518:         assert(wait_queue_held(wq));
                    519: 
                    520:         queue_init(q);
                    521: 
                    522:         /*
                    523:          * Select the threads that we will wake up.  The threads
                    524:          * are returned to us locked and cleanly removed from the
                    525:          * wait queue.
                    526:          */
                    527:         s = splsched();
                    528:         _wait_queue_select_all(wq, event, q);
                    529:         if (unlock)
                    530:             wait_queue_unlock(wq);
                    531: 
                    532:         /*
                    533:          * For each thread, set it running.
                    534:          */
                    535:         while (!queue_empty (q)) {
                    536:                 thread_t thread = (thread_t) dequeue(q);
                    537:                 thread_go_locked(thread, result);
                    538:                 thread_unlock(thread);
                    539:                 ret = KERN_SUCCESS;
                    540:         }
                    541:         splx(s);
                    542:         return ret;
                    543: }
                    544: 
                    545: 
                    546: /*
                    547:  *      Routine:        wait_queue_wakeup_all
                    548:  *      Purpose:
                    549:  *              Wakeup some number of threads that are in the specified
                    550:  *              wait queue and waiting on the specified event.
                    551:  *
                    552:  *      Conditions:
                    553:  *              Nothing locked
                    554:  *
                    555:  *      Returns:
                    556:  *              KERN_SUCCESS - Threads were woken up
                    557:  *              KERN_NOT_WAITING - No threads were waiting <wq,event> pair
                    558:  */
                    559: kern_return_t
                    560: wait_queue_wakeup_all(
                    561:         wait_queue_t wq,
                    562:         event_t event,
                    563:         int result)
                    564: {
                    565:         kern_return_t ret;
                    566:         spl_t s;
                    567: 
                    568:         s = splsched();
                    569:         wait_queue_lock(wq);
                    570:         ret = wait_queue_wakeup_all_locked(wq, event, result, TRUE);
                    571:         /* lock released */
                    572:         splx(s);
                    573: 
                    574:         return ret;
                    575: }
                    576: 
                    577: /*
                    578:  *     Routine:        wait_queue_select_one
                    579:  *     Purpose:
                    580:  *             Select the best thread off a wait queue that meet the
                    581:  *             supplied criteria.
                    582:  *     Conditions:
                    583:  *             at splsched
                    584:  *             wait queue locked
                    585:  *             possibly recursive
                    586:  *     Returns:
                    587:  *             a locked thread - if one found
                    588:  *     Note:
                    589:  *             This is where the sync policy of the wait queue comes
                    590:  *             into effect.  For now, we just assume FIFO.
                    591:  */
                    592: thread_t
                    593: _wait_queue_select_one(
                    594:        wait_queue_t wq,
                    595:        event_t event)
                    596: {
                    597:        wait_queue_element_t wq_element;
                    598:        wait_queue_element_t wqe_next;
                    599:        thread_t t = THREAD_NULL;
                    600:        queue_t q;
                    601: 
                    602:        assert(wq->wq_fifo);
                    603: 
                    604:        q = &wq->wq_queue;
                    605: 
                    606:        wq_element = (wait_queue_element_t) queue_first(q);
                    607:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    608:                wqe_next = (wait_queue_element_t)
                    609:                               queue_next((queue_t) wq_element);
                    610: 
                    611:                /*
                    612:                 * We may have to recurse if this is a compound wait queue.
                    613:                 */
                    614:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    615:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    616:                        wait_queue_t sub_queue;
                    617: 
                    618:                        /*
                    619:                         * We have to check the subordinate wait queue.
                    620:                         */
                    621:                        sub_queue = (wait_queue_t)wql->wql_subqueue;
                    622:                        wait_queue_lock(sub_queue);
                    623:                        if (! wait_queue_empty(sub_queue)) {
                    624:                                t = _wait_queue_select_one(sub_queue, event);
                    625:                        }
                    626:                        wait_queue_unlock(sub_queue);
                    627:                        if (t != THREAD_NULL)
                    628:                                return t;
                    629:                } else {
                    630:                        
                    631:                        /*
                    632:                         * Otherwise, its a thread.  If it is waiting on
                    633:                         * the event we are posting to this queue, pull
                    634:                         * it off the queue and stick it in out wake_queue.
                    635:                         */
                    636:                        thread_t t = (thread_t)wq_element;
                    637: 
                    638:                        if (t->wait_event == event) {
                    639:                                thread_lock(t);
                    640:                                remqueue(q, (queue_entry_t) t);
                    641:                                t->wait_queue = WAIT_QUEUE_NULL;
                    642:                                t->wait_event = NO_EVENT;
                    643:                                t->at_safe_point = FALSE;
                    644:                                return t;       /* still locked */
                    645:                        }
                    646:                }
                    647:                wq_element = wqe_next;
                    648:        }
                    649:        return THREAD_NULL;
                    650: }
                    651: 
                    652: /*
                    653:  *     Routine:        wait_queue_peek_locked
                    654:  *     Purpose:
                    655:  *             Select the best thread from a wait queue that meet the
                    656:  *             supplied criteria, but leave it on the queue you it was
                    657:  *             found on.  The thread, and the actual wait_queue the
                    658:  *             thread was found on are identified.
                    659:  *     Conditions:
                    660:  *             at splsched
                    661:  *             wait queue locked
                    662:  *             possibly recursive
                    663:  *     Returns:
                    664:  *             a locked thread - if one found
                    665:  *             a locked waitq - the one the thread was found on
                    666:  *     Note:
                    667:  *             Only the waitq the thread was actually found on is locked
                    668:  *             after this.
                    669:  */
                    670: void
                    671: wait_queue_peek_locked(
                    672:        wait_queue_t wq,
                    673:        event_t event,
                    674:        thread_t *tp,
                    675:        wait_queue_t *wqp)
                    676: {
                    677:        wait_queue_element_t wq_element;
                    678:        wait_queue_element_t wqe_next;
                    679:        thread_t t;
                    680:        queue_t q;
                    681: 
                    682:        assert(wq->wq_fifo);
                    683: 
                    684:        *tp = THREAD_NULL;
                    685: 
                    686:        q = &wq->wq_queue;
                    687: 
                    688:        wq_element = (wait_queue_element_t) queue_first(q);
                    689:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    690:                wqe_next = (wait_queue_element_t)
                    691:                               queue_next((queue_t) wq_element);
                    692: 
                    693:                /*
                    694:                 * We may have to recurse if this is a compound wait queue.
                    695:                 */
                    696:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    697:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    698:                        wait_queue_t sub_queue;
                    699: 
                    700:                        /*
                    701:                         * We have to check the subordinate wait queue.
                    702:                         */
                    703:                        sub_queue = (wait_queue_t)wql->wql_subqueue;
                    704:                        wait_queue_lock(sub_queue);
                    705:                        if (! wait_queue_empty(sub_queue)) {
                    706:                                wait_queue_peek_locked(sub_queue, event, tp, wqp);
                    707:                        }
                    708:                        if (*tp != THREAD_NULL)
                    709:                                return;  /* thread and its waitq locked */
                    710: 
                    711:                        wait_queue_unlock(sub_queue);
                    712:                } else {
                    713:                        
                    714:                        /*
                    715:                         * Otherwise, its a thread.  If it is waiting on
                    716:                         * the event we are posting to this queue, return
                    717:                         * it locked, but leave it on the queue.
                    718:                         */
                    719:                        thread_t t = (thread_t)wq_element;
                    720: 
                    721:                        if (t->wait_event == event) {
                    722:                                thread_lock(t);
                    723:                                *tp = t;
                    724:                                *wqp = wq;
                    725:                                return;
                    726:                        }
                    727:                }
                    728:                wq_element = wqe_next;
                    729:        }
                    730: }
                    731: 
                    732: /*
                    733:  *     Routine:        wait_queue_pull_thread_locked
                    734:  *     Purpose:
                    735:  *             Pull a thread that was previously "peeked" off the wait
                    736:  *             queue and (possibly) unlock the waitq.
                    737:  *     Conditions:
                    738:  *             at splsched
                    739:  *             wait queue locked
                    740:  *             thread locked
                    741:  *     Returns:
                    742:  *             with the thread still locked.
                    743:  */
                    744: void
                    745: wait_queue_pull_thread_locked(
                    746:        wait_queue_t waitq,
                    747:        thread_t thread,
                    748:        boolean_t unlock)
                    749: {
                    750: 
                    751:        assert(thread->wait_queue == waitq);
                    752: 
                    753:        remqueue(&waitq->wq_queue, (queue_entry_t)thread );
                    754:        thread->wait_queue = WAIT_QUEUE_NULL;
                    755:        thread->wait_event = NO_EVENT;
                    756:        thread->at_safe_point = FALSE;
                    757:        if (unlock)
                    758:                wait_queue_unlock(waitq);
                    759: }
                    760: 
                    761: 
                    762: /*
                    763:  *     Routine:        wait_queue_select_thread
                    764:  *     Purpose:
                    765:  *             Look for a thread and remove it from the queues, if
                    766:  *             (and only if) the thread is waiting on the supplied
                    767:  *             <wait_queue, event> pair.
                    768:  *     Conditions:
                    769:  *             at splsched
                    770:  *             wait queue locked
                    771:  *             possibly recursive
                    772:  *     Returns:
                    773:  *             KERN_NOT_WAITING: Thread is not waiting here.
                    774:  *             KERN_SUCCESS: It was, and is now removed (returned locked)
                    775:  */
                    776: kern_return_t
                    777: _wait_queue_select_thread(
                    778:        wait_queue_t wq,
                    779:        event_t event,
                    780:        thread_t thread)
                    781: {
                    782:        wait_queue_element_t wq_element;
                    783:        wait_queue_element_t wqe_next;
                    784:        kern_return_t res = KERN_NOT_WAITING;
                    785:        queue_t q = &wq->wq_queue;
                    786: 
                    787:        assert(wq->wq_fifo);
                    788: 
                    789:        thread_lock(thread);
                    790:        if ((thread->wait_queue == wq) && (thread->wait_event == event)) {
                    791:                remqueue(q, (queue_entry_t) thread);
                    792:                thread->at_safe_point = FALSE;
                    793:                thread->wait_event = NO_EVENT;
                    794:                thread->wait_queue = WAIT_QUEUE_NULL;
                    795:                /* thread still locked */
                    796:                return KERN_SUCCESS;
                    797:        }
                    798:        thread_unlock(thread);
                    799:        
                    800:        /*
                    801:         * The wait_queue associated with the thread may be one of this
                    802:         * wait queue's subordinates.  Go see.  If so, removing it from
                    803:         * there is like removing it from here.
                    804:         */
                    805:        wq_element = (wait_queue_element_t) queue_first(q);
                    806:        while (!queue_end(q, (queue_entry_t)wq_element)) {
                    807:                wqe_next = (wait_queue_element_t)
                    808:                               queue_next((queue_t) wq_element);
                    809: 
                    810:                if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
                    811:                        wait_queue_link_t wql = (wait_queue_link_t)wq_element;
                    812:                        wait_queue_t sub_queue;
                    813: 
                    814:                        sub_queue = (wait_queue_t)wql->wql_subqueue;
                    815:                        wait_queue_lock(sub_queue);
                    816:                        if (! wait_queue_empty(sub_queue)) {
                    817:                                res = _wait_queue_select_thread(sub_queue,
                    818:                                                                event,
                    819:                                                                thread);
                    820:                        }
                    821:                        wait_queue_unlock(sub_queue);
                    822:                        if (res == KERN_SUCCESS)
                    823:                                return KERN_SUCCESS;
                    824:                }
                    825:                wq_element = wqe_next;
                    826:        }
                    827:        return res;
                    828: }
                    829: 
                    830: 
                    831: /*
                    832:  *     Routine:        wait_queue_wakeup_identity_locked
                    833:  *     Purpose:
                    834:  *             Select a single thread that is most-eligible to run and set
                    835:  *             set it running.  But return the thread locked.
                    836:  *
                    837:  *     Conditions:
                    838:  *             at splsched
                    839:  *             wait queue locked
                    840:  *             possibly recursive
                    841:  *     Returns:
                    842:  *             a pointer to the locked thread that was awoken
                    843:  */
                    844: thread_t
                    845: wait_queue_wakeup_identity_locked(
                    846:        wait_queue_t wq,
                    847:        event_t event,
                    848:        int result,
                    849:        boolean_t unlock)
                    850: {
                    851:        thread_t thread;
                    852:        spl_t s;
                    853: 
                    854:        assert(wait_queue_held(wq));
                    855: 
                    856:        s = splsched();
                    857:        thread = _wait_queue_select_one(wq, event);
                    858:        if (unlock)
                    859:                wait_queue_unlock(wq);
                    860: 
                    861:        if (thread) {
                    862:                thread_go_locked(thread, result);
                    863:                splx(s);
                    864:                return thread;  /* still locked */
                    865:        }
                    866:        splx(s);
                    867:        return THREAD_NULL;
                    868: }
                    869: 
                    870: 
                    871: /*
                    872:  *     Routine:        wait_queue_wakeup_one_locked
                    873:  *     Purpose:
                    874:  *             Select a single thread that is most-eligible to run and set
                    875:  *             set it runnings.
                    876:  *
                    877:  *     Conditions:
                    878:  *             at splsched
                    879:  *             wait queue locked
                    880:  *             possibly recursive
                    881:  *     Returns:
                    882:  *             KERN_SUCCESS: It was, and is, now removed.
                    883:  *             KERN_NOT_WAITING - No thread was waiting <wq,event> pair
                    884:  */
                    885: kern_return_t
                    886: wait_queue_wakeup_one_locked(
                    887:        wait_queue_t wq,
                    888:        event_t event,
                    889:        int result,
                    890:        boolean_t unlock)
                    891: {
                    892:        thread_t thread;
                    893:        spl_t s;
                    894: 
                    895:        assert(wait_queue_held(wq));
                    896: 
                    897:        s = splsched();
                    898:        thread = _wait_queue_select_one(wq, event);
                    899:        if (unlock)
                    900:                wait_queue_unlock(wq);
                    901: 
                    902:        if (thread) {
                    903:                thread_go_locked(thread, result);
                    904:                thread_unlock(thread);
                    905:                splx(s);
                    906:                return KERN_SUCCESS;
                    907:        }
                    908: 
                    909:        splx(s);
                    910:        return KERN_NOT_WAITING;
                    911: }
                    912: 
                    913: /*
                    914:  *     Routine:        wait_queue_wakeup_one
                    915:  *     Purpose:
                    916:  *             Wakeup the most appropriate thread that is in the specified
                    917:  *             wait queue for the specified event.
                    918:  *
                    919:  *     Conditions:
                    920:  *             Nothing locked
                    921:  *
                    922:  *     Returns:
                    923:  *             KERN_SUCCESS - Thread was woken up
                    924:  *             KERN_NOT_WAITING - No thread was waiting <wq,event> pair
                    925:  */
                    926: kern_return_t
                    927: wait_queue_wakeup_one(
                    928:        wait_queue_t wq,
                    929:        event_t event,
                    930:        int result)
                    931: {
                    932:        thread_t thread;
                    933:        spl_t s;
                    934: 
                    935:        s = splsched();
                    936:        wait_queue_lock(wq);
                    937:        thread = _wait_queue_select_one(wq, event);
                    938:        wait_queue_unlock(wq);
                    939: 
                    940:        if (thread) {
                    941:                thread_go_locked(thread, result);
                    942:                thread_unlock(thread);
                    943:                splx(s);
                    944:                return KERN_SUCCESS;
                    945:        }
                    946: 
                    947:        splx(s);
                    948:        return KERN_NOT_WAITING;
                    949: }
                    950: 
                    951: 
                    952: 
                    953: /*
                    954:  *     Routine:        wait_queue_wakeup_thread_locked
                    955:  *     Purpose:
                    956:  *             Wakeup the particular thread that was specified if and only
                    957:  *             it was in this wait queue (or one of it's subordinate queues)
                    958:  *             and waiting on the specified event.
                    959:  *
                    960:  *             This is much safer than just removing the thread from
                    961:  *             whatever wait queue it happens to be on.  For instance, it
                    962:  *             may have already been awoken from the wait you intended to
                    963:  *             interrupt and waited on something else (like another
                    964:  *             semaphore).
                    965:  *     Conditions:
                    966:  *             wait queue already locked (may be released).
                    967:  *     Returns:
                    968:  *             KERN_SUCCESS - the thread was found waiting and awakened
                    969:  *             KERN_NOT_WAITING - the thread was not waiting here
                    970:  */
                    971: kern_return_t
                    972: wait_queue_wakeup_thread_locked(
                    973:        wait_queue_t wq,
                    974:        event_t event,
                    975:        thread_t thread,
                    976:        int result,
                    977:        boolean_t unlock)
                    978: {
                    979:        kern_return_t res;
                    980:        spl_t s;
                    981: 
                    982:        assert(wait_queue_held(wq));
                    983: 
                    984:        /*
                    985:         * See if the thread was still waiting there.  If so, it got
                    986:         * dequeued and returned locked.
                    987:         */
                    988:        s = splsched();
                    989:        res = _wait_queue_select_thread(wq, event, thread);
                    990:        if (unlock)
                    991:            wait_queue_unlock(wq);
                    992: 
                    993:        if (res != KERN_SUCCESS) {
                    994:                splx(s);
                    995:                return KERN_NOT_WAITING;
                    996:        }
                    997: 
                    998:        thread_go_locked(thread, result);
                    999:        thread_unlock(thread);
                   1000:        splx(s);
                   1001:        return KERN_SUCCESS;
                   1002: }
                   1003: 
                   1004: /*
                   1005:  *     Routine:        wait_queue_wakeup_thread
                   1006:  *     Purpose:
                   1007:  *             Wakeup the particular thread that was specified if and only
                   1008:  *             it was in this wait queue (or one of it's subordinate queues)
                   1009:  *             and waiting on the specified event.
                   1010:  *
                   1011:  *             This is much safer than just removing the thread from
                   1012:  *             whatever wait queue it happens to be on.  For instance, it
                   1013:  *             may have already been awoken from the wait you intended to
                   1014:  *             interrupt and waited on something else (like another
                   1015:  *             semaphore).
                   1016:  *     Conditions:
                   1017:  *             nothing of interest locked
                   1018:  *             we need to assume spl needs to be raised
                   1019:  *     Returns:
                   1020:  *             KERN_SUCCESS - the thread was found waiting and awakened
                   1021:  *             KERN_NOT_WAITING - the thread was not waiting here
                   1022:  */
                   1023: kern_return_t
                   1024: wait_queue_wakeup_thread(
                   1025:        wait_queue_t wq,
                   1026:        event_t event,
                   1027:        thread_t thread,
                   1028:        int result)
                   1029: {
                   1030:        kern_return_t res;
                   1031:        spl_t s;
                   1032: 
                   1033:        s = splsched();
                   1034:        wait_queue_lock(wq);
                   1035:        res = _wait_queue_select_thread(wq, event, thread);
                   1036:        wait_queue_unlock(wq);
                   1037: 
                   1038:        if (res == KERN_SUCCESS) {
                   1039:                thread_go_locked(thread, result);
                   1040:                thread_unlock(thread);
                   1041:                splx(s);
                   1042:                return KERN_SUCCESS;
                   1043:        }
                   1044:        splx(s);
                   1045:        return KERN_NOT_WAITING;
                   1046: }
                   1047: 
                   1048: 
                   1049: /*
                   1050:  *     Routine:        wait_queue_remove
                   1051:  *     Purpose:
                   1052:  *             Normal removal operations from wait queues drive from the
                   1053:  *             wait queue to select a thread.  However, if a thread is
                   1054:  *             interrupted out of a wait, this routine is called to
                   1055:  *             remove it from whatever wait queue it may be in.
                   1056:  *
                   1057:  *     Conditions:
                   1058:  *             splsched
                   1059:  *             thread locked on entry and exit, but may be dropped.
                   1060:  *
                   1061:  *     Returns:
                   1062:  *             KERN_SUCCESS - if thread was in a wait queue
                   1063:  *             KERN_NOT_WAITING - it was not
                   1064:  */
                   1065: kern_return_t
                   1066: wait_queue_remove(
                   1067:         thread_t thread)
                   1068: {
                   1069:        wait_queue_t wq = thread->wait_queue;
                   1070: 
                   1071:        if (wq == WAIT_QUEUE_NULL)
                   1072:                return KERN_NOT_WAITING;
                   1073: 
                   1074:        /*
                   1075:         * have to get the locks again in the right order.
                   1076:         */
                   1077:        thread_unlock(thread);
                   1078:        wait_queue_lock(wq);
                   1079:        thread_lock(thread);
                   1080:        
                   1081:        if (thread->wait_queue == wq) {
                   1082:                remqueue(&wq->wq_queue, (queue_entry_t)thread);
                   1083:                thread->wait_queue = WAIT_QUEUE_NULL;
                   1084:                thread->wait_event = NO_EVENT;
                   1085:                thread->at_safe_point = FALSE;
                   1086:                wait_queue_unlock(wq);
                   1087:                return KERN_SUCCESS;
                   1088:        } else {
                   1089:                wait_queue_unlock(wq);
                   1090:                return KERN_NOT_WAITING; /* anymore */
                   1091:        }
                   1092: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.