Annotation of XNU/osfmk/kern/wait_queue.c, revision 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.