Annotation of XNU/osfmk/kern/sync_lock.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_COPYRIGHT@
                     24:  * 
                     25:  */
                     26: /*
                     27:  *     File:   kern/sync_lock.c
                     28:  *     Author: Joseph CaraDonna
                     29:  *
                     30:  *     Contains RT distributed lock synchronization services.
                     31:  */
                     32: 
                     33: #include <kern/etap_macros.h>
                     34: #include <kern/misc_protos.h>
                     35: #include <kern/sync_lock.h>
                     36: #include <kern/sched_prim.h>
                     37: #include <kern/ipc_kobject.h>
                     38: #include <kern/ipc_sync.h>
                     39: #include <kern/etap_macros.h>
                     40: #include <kern/thread.h>
                     41: #include <kern/task.h>
                     42: #include <ipc/ipc_port.h>
                     43: #include <ipc/ipc_space.h>
                     44: 
                     45: /*
                     46:  *     Ulock ownership MACROS
                     47:  *
                     48:  *     Assumes: ulock internal lock is held 
                     49:  */
                     50: 
                     51: #define ulock_ownership_set(ul, th)                            \
                     52:        MACRO_BEGIN                                             \
                     53:        thread_act_t _th_act;                                   \
                     54:        _th_act = (th)->top_act;                                \
                     55:        act_lock(_th_act);                                      \
                     56:        enqueue (&_th_act->held_ulocks, (queue_entry_t) (ul));  \
                     57:        act_unlock(_th_act);                                    \
                     58:        (ul)->holder = _th_act;                                 \
                     59:        MACRO_END
                     60: 
                     61: #define ulock_ownership_clear(ul)                              \
                     62:        MACRO_BEGIN                                             \
                     63:        thread_act_t _th_act;                                   \
                     64:        _th_act = (ul)->holder;                                 \
                     65:         if (_th_act->active) {                                 \
                     66:                act_lock(_th_act);                              \
                     67:                remqueue(&_th_act->held_ulocks,                 \
                     68:                         (queue_entry_t) (ul));                 \
                     69:                act_unlock(_th_act);                            \
                     70:        } else {                                                \
                     71:                remqueue(&_th_act->held_ulocks,                 \
                     72:                         (queue_entry_t) (ul));                 \
                     73:        }                                                       \
                     74:        (ul)->holder = THR_ACT_NULL;                            \
                     75:        MACRO_END
                     76: 
                     77: /*
                     78:  *     Lock set ownership MACROS
                     79:  */
                     80: 
                     81: #define lock_set_ownership_set(ls, t)                          \
                     82:        MACRO_BEGIN                                             \
                     83:        task_lock((t));                                         \
                     84:        enqueue_head(&(t)->lock_set_list, (queue_entry_t) (ls));\
                     85:        (t)->lock_sets_owned++;                                 \
                     86:        task_unlock((t));                                       \
                     87:        (ls)->owner = (t);                                      \
                     88:        MACRO_END
                     89: 
                     90: #define lock_set_ownership_clear(ls, t)                                \
                     91:        MACRO_BEGIN                                             \
                     92:        task_lock((t));                                         \
                     93:        remqueue(&(t)->lock_set_list, (queue_entry_t) (ls));    \
                     94:        (t)->lock_sets_owned--;                                 \
                     95:        task_unlock((t));                                       \
                     96:        MACRO_END
                     97: 
                     98: unsigned int lock_set_event;
                     99: #define LOCK_SET_EVENT ((event_t)&lock_set_event)
                    100: 
                    101: unsigned int lock_set_handoff;
                    102: #define LOCK_SET_HANDOFF ((event_t)&lock_set_handoff)
                    103: 
                    104: /*
                    105:  *     ROUTINE:        lock_set_create         [exported]
                    106:  *
                    107:  *     Creates a lock set.
                    108:  *     The port representing the lock set is returned as a parameter.
                    109:  */      
                    110: kern_return_t
                    111: lock_set_create (
                    112:        task_t          task,
                    113:        lock_set_t      *new_lock_set,
                    114:        int             n_ulocks,
                    115:        int             policy)
                    116: {
                    117:        lock_set_t      lock_set = LOCK_SET_NULL;
                    118:        ulock_t         ulock;
                    119:        int             size;
                    120:        int             x;
                    121: 
                    122:        *new_lock_set = LOCK_SET_NULL;
                    123: 
                    124:        if (task == TASK_NULL || n_ulocks <= 0 || policy > SYNC_POLICY_MAX)
                    125:                return KERN_INVALID_ARGUMENT;
                    126: 
                    127:        size = sizeof(struct lock_set) + (sizeof(struct ulock) * (n_ulocks-1));
                    128:        lock_set = (lock_set_t) kalloc (size);
                    129: 
                    130:        if (lock_set == LOCK_SET_NULL)
                    131:                return KERN_RESOURCE_SHORTAGE; 
                    132: 
                    133: 
                    134:        lock_set_lock_init(lock_set);
                    135:        lock_set->n_ulocks = n_ulocks;
                    136:        lock_set->ref_count = 1;
                    137: 
                    138:        /*
                    139:         *  Create and initialize the lock set port
                    140:         */
                    141:        lock_set->port = ipc_port_alloc_kernel();
                    142:        if (lock_set->port == IP_NULL) {        
                    143:                /* This will deallocate the lock set */
                    144:                lock_set_dereference(lock_set);
                    145:                return KERN_RESOURCE_SHORTAGE; 
                    146:        }
                    147: 
                    148:        ipc_kobject_set (lock_set->port,
                    149:                        (ipc_kobject_t) lock_set,
                    150:                        IKOT_LOCK_SET);
                    151: 
                    152:        /*
                    153:         *  Initialize each ulock in the lock set
                    154:         */
                    155: 
                    156:        for (x=0; x < n_ulocks; x++) {
                    157:                ulock = (ulock_t) &lock_set->ulock_list[x];
                    158:                ulock_lock_init(ulock);
                    159:                ulock->lock_set  = lock_set;
                    160:                ulock->holder    = THR_ACT_NULL;
                    161:                ulock->blocked   = FALSE;
                    162:                ulock->unstable  = FALSE;
                    163:                ulock->ho_wait   = FALSE;
                    164:                wait_queue_init(&ulock->wait_queue, policy);
                    165:        }
                    166: 
                    167:        lock_set_ownership_set(lock_set, task);
                    168: 
                    169:        lock_set->active = TRUE;
                    170:        *new_lock_set = lock_set;
                    171: 
                    172:        return KERN_SUCCESS;
                    173: }
                    174: 
                    175: /*
                    176:  *     ROUTINE:        lock_set_destroy        [exported]
                    177:  *     
                    178:  *     Destroys a lock set.  This call will only succeed if the
                    179:  *     specified task is the SAME task name specified at the lock set's
                    180:  *     creation.
                    181:  *
                    182:  *     NOTES:
                    183:  *     - All threads currently blocked on the lock set's ulocks are awoken.
                    184:  *     - These threads will return with the KERN_LOCK_SET_DESTROYED error.
                    185:  */
                    186: kern_return_t
                    187: lock_set_destroy (task_t task, lock_set_t lock_set)
                    188: {
                    189:        thread_t        thread;
                    190:        ulock_t         ulock;
                    191:        int             i;
                    192: 
                    193:        if (task == TASK_NULL || lock_set == LOCK_SET_NULL)
                    194:                return KERN_INVALID_ARGUMENT;
                    195: 
                    196:        if (lock_set->owner != task)
                    197:                return KERN_INVALID_RIGHT;
                    198: 
                    199:        lock_set_lock(lock_set);
                    200:        if (!lock_set->active) {
                    201:                lock_set_unlock(lock_set);
                    202:                return KERN_LOCK_SET_DESTROYED;
                    203:        }
                    204: 
                    205:        /*
                    206:         *  Deactivate lock set
                    207:         */
                    208:        lock_set->active = FALSE;
                    209: 
                    210:        /*
                    211:         *  If a ulock is currently held in the target lock set:
                    212:         *
                    213:         *  1) Wakeup all threads blocked on the ulock (if any).  Threads
                    214:         *     may be blocked waiting normally, or waiting for a handoff.
                    215:         *     Blocked threads will return with KERN_LOCK_SET_DESTROYED.
                    216:         *
                    217:         *  2) ulock ownership is cleared.
                    218:         *     The thread currently holding the ulock is revoked of its
                    219:         *     ownership.
                    220:         */
                    221:        for (i = 0; i < lock_set->n_ulocks; i++) {
                    222:                ulock = &lock_set->ulock_list[i];
                    223: 
                    224:                ulock_lock(ulock);
                    225: 
                    226:                if (ulock->accept_wait) {
                    227:                        ulock->accept_wait = FALSE;
                    228:                        wait_queue_wakeup_one(&ulock->wait_queue,
                    229:                                              LOCK_SET_HANDOFF,
                    230:                                              THREAD_RESTART);
                    231:                }
                    232:                                          
                    233:                if (ulock->holder) {
                    234:                        if (ulock->blocked) {
                    235:                                ulock->blocked = FALSE;
                    236:                                wait_queue_wakeup_all(&ulock->wait_queue,
                    237:                                                      LOCK_SET_EVENT,
                    238:                                                      THREAD_RESTART);
                    239:                        }
                    240:                        if (ulock->ho_wait) {
                    241:                                ulock->ho_wait = FALSE;
                    242:                                wait_queue_wakeup_one(&ulock->wait_queue,
                    243:                                                      LOCK_SET_HANDOFF,
                    244:                                                      THREAD_RESTART);
                    245:                        }
                    246:                        ulock_ownership_clear(ulock);
                    247:                }
                    248:                
                    249:                ulock_unlock(ulock);
                    250:        }
                    251: 
                    252:        lock_set_unlock(lock_set);
                    253:        lock_set_ownership_clear(lock_set, task);
                    254: 
                    255:        /*
                    256:         *  Deallocate  
                    257:         *
                    258:         *  Drop the lock set reference, which inturn destroys the
                    259:         *  lock set structure if the reference count goes to zero.
                    260:         */
                    261: 
                    262:        ipc_port_dealloc_kernel(lock_set->port);
                    263:        lock_set_dereference(lock_set);
                    264: 
                    265:        return KERN_SUCCESS;
                    266: }
                    267: 
                    268: kern_return_t
                    269: lock_acquire (lock_set_t lock_set, int lock_id)
                    270: {
                    271:        ulock_t   ulock;
                    272: 
                    273:        if (lock_set == LOCK_SET_NULL)
                    274:                return KERN_INVALID_ARGUMENT;
                    275: 
                    276:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    277:                return KERN_INVALID_ARGUMENT;
                    278: 
                    279:  retry:
                    280:        lock_set_lock(lock_set);
                    281:        if (!lock_set->active) {
                    282:                lock_set_unlock(lock_set);
                    283:                return KERN_LOCK_SET_DESTROYED;
                    284:        }
                    285: 
                    286:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    287:        ulock_lock(ulock);
                    288:        lock_set_unlock(lock_set);
                    289: 
                    290:        /*
                    291:         *  Block the current thread if the lock is already held.
                    292:         */
                    293: 
                    294:        if (ulock->holder != THR_ACT_NULL) {
                    295:                int wait_result;
                    296: 
                    297:                lock_set_unlock(lock_set);
                    298: 
                    299:                if (ulock->holder == current_act()) {
                    300:                        ulock_unlock(ulock);
                    301:                        return KERN_LOCK_OWNED_SELF;
                    302:                }
                    303: 
                    304:                ulock->blocked = TRUE;
                    305:                wait_queue_assert_wait(&ulock->wait_queue,
                    306:                                       LOCK_SET_EVENT,
                    307:                                       THREAD_ABORTSAFE);
                    308:                ulock_unlock(ulock);
                    309: 
                    310:                /*
                    311:                 *  Block - Wait for lock to become available.
                    312:                 */
                    313: 
                    314:                wait_result = thread_block((void (*)(void))0);
                    315: 
                    316:                /*
                    317:                 *  Check the result status:
                    318:                 *
                    319:                 *  Check to see why thread was woken up.  In all cases, we
                    320:                 *  already have been removed from the queue.
                    321:                 */
                    322:                switch (wait_result) {
                    323:                case THREAD_AWAKENED:
                    324:                        /* lock transitioned from old locker to us */
                    325:                        /* he already made us owner */
                    326:                        return (ulock->unstable) ? KERN_LOCK_UNSTABLE :
                    327:                                                   KERN_SUCCESS;
                    328: 
                    329:                case THREAD_INTERRUPTED:
                    330:                        return KERN_ABORTED;
                    331: 
                    332:                case THREAD_RESTART:
                    333:                        goto retry;  /* probably a dead lock_set */
                    334: 
                    335:                default:
                    336:                        panic("lock_acquire\n");
                    337:                }
                    338:        }
                    339: 
                    340:        /*
                    341:         *  Assign lock ownership
                    342:         */
                    343:        ulock_ownership_set(ulock, current_thread());
                    344:        ulock_unlock(ulock);
                    345: 
                    346:        return (ulock->unstable) ? KERN_LOCK_UNSTABLE : KERN_SUCCESS;
                    347: }
                    348: 
                    349: kern_return_t
                    350: lock_release (lock_set_t lock_set, int lock_id)
                    351: {
                    352:        ulock_t  ulock;
                    353: 
                    354:        if (lock_set == LOCK_SET_NULL)
                    355:                return KERN_INVALID_ARGUMENT;
                    356: 
                    357:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    358:                return KERN_INVALID_ARGUMENT;
                    359: 
                    360:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    361: 
                    362:        return (lock_release_internal(ulock, current_act()));
                    363: }
                    364: 
                    365: kern_return_t
                    366: lock_try (lock_set_t lock_set, int lock_id)
                    367: {
                    368:        ulock_t   ulock;
                    369: 
                    370: 
                    371:        if (lock_set == LOCK_SET_NULL)
                    372:                return KERN_INVALID_ARGUMENT;
                    373: 
                    374:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    375:                return KERN_INVALID_ARGUMENT;
                    376: 
                    377: 
                    378:        lock_set_lock(lock_set);
                    379:        if (!lock_set->active) {
                    380:                lock_set_unlock(lock_set);
                    381:                return KERN_LOCK_SET_DESTROYED;
                    382:        }
                    383: 
                    384:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    385:        ulock_lock(ulock);
                    386:        lock_set_unlock(lock_set);
                    387: 
                    388:        /*
                    389:         *  If the lock is already owned, we return without blocking.
                    390:         *
                    391:         *  An ownership status is returned to inform the caller as to
                    392:         *  whether it already holds the lock or another thread does.
                    393:         */
                    394: 
                    395:        if (ulock->holder != THR_ACT_NULL) {
                    396:                lock_set_unlock(lock_set);
                    397: 
                    398:                if (ulock->holder == current_act()) {
                    399:                        ulock_unlock(ulock);
                    400:                        return KERN_LOCK_OWNED_SELF;
                    401:                }
                    402:                
                    403:                ulock_unlock(ulock);
                    404:                return KERN_LOCK_OWNED;
                    405:        }
                    406: 
                    407:        /*
                    408:         *  Add the ulock to the lock set's held_ulocks list.
                    409:         */
                    410: 
                    411:        ulock_ownership_set(ulock, current_thread());
                    412:        ulock_unlock(ulock);
                    413: 
                    414:        return (ulock->unstable) ? KERN_LOCK_UNSTABLE : KERN_SUCCESS;
                    415: }
                    416: 
                    417: kern_return_t
                    418: lock_make_stable (lock_set_t lock_set, int lock_id)
                    419: {
                    420:        ulock_t  ulock;
                    421: 
                    422: 
                    423:        if (lock_set == LOCK_SET_NULL)
                    424:                return KERN_INVALID_ARGUMENT;
                    425: 
                    426:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    427:                return KERN_INVALID_ARGUMENT;
                    428: 
                    429: 
                    430:        lock_set_lock(lock_set);
                    431:        if (!lock_set->active) {
                    432:                lock_set_unlock(lock_set);
                    433:                return KERN_LOCK_SET_DESTROYED;
                    434:        }
                    435: 
                    436:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    437:        ulock_lock(ulock);
                    438:        lock_set_unlock(lock_set);
                    439: 
                    440:        if (ulock->holder != current_act()) {
                    441:                ulock_unlock(ulock);
                    442:                return KERN_INVALID_RIGHT;
                    443:        }
                    444: 
                    445:        ulock->unstable = FALSE;
                    446:        ulock_unlock(ulock);
                    447: 
                    448:        return KERN_SUCCESS;
                    449: }
                    450: 
                    451: /*
                    452:  *     ROUTINE:        lock_make_unstable      [internal]
                    453:  *
                    454:  *     Marks the lock as unstable.
                    455:  *
                    456:  *     NOTES:
                    457:  *     - All future acquisitions of the lock will return with a
                    458:  *       KERN_LOCK_UNSTABLE status, until the lock is made stable again.
                    459:  */
                    460: kern_return_t
                    461: lock_make_unstable (ulock_t ulock, thread_act_t thr_act)
                    462: {
                    463:        lock_set_t      lock_set;
                    464: 
                    465: 
                    466:        lock_set = ulock->lock_set;
                    467:        lock_set_lock(lock_set);
                    468:        if (!lock_set->active) {
                    469:                lock_set_unlock(lock_set);
                    470:                return KERN_LOCK_SET_DESTROYED;
                    471:        }
                    472: 
                    473:        ulock_lock(ulock);
                    474:        lock_set_unlock(lock_set);
                    475: 
                    476:        if (ulock->holder != thr_act) {
                    477:                ulock_unlock(ulock);
                    478:                return KERN_INVALID_RIGHT;
                    479:        }
                    480: 
                    481:        ulock->unstable = TRUE;
                    482:        ulock_unlock(ulock);
                    483: 
                    484:        return KERN_SUCCESS;
                    485: }
                    486: 
                    487: /*
                    488:  *     ROUTINE:        lock_release_internal   [internal]
                    489:  *
                    490:  *     Releases the ulock.
                    491:  *     If any threads are blocked waiting for the ulock, one is woken-up.
                    492:  *
                    493:  */
                    494: kern_return_t
                    495: lock_release_internal (ulock_t ulock, thread_act_t thr_act)
                    496: {
                    497:        lock_set_t      lock_set;
                    498:        int             result;
                    499: 
                    500: 
                    501:        if ((lock_set = ulock->lock_set) == LOCK_SET_NULL)
                    502:                return KERN_INVALID_ARGUMENT;
                    503: 
                    504:        lock_set_lock(lock_set);
                    505:        if (!lock_set->active) {
                    506:                lock_set_unlock(lock_set);
                    507:                return KERN_LOCK_SET_DESTROYED;
                    508:        }
                    509:        ulock_lock(ulock);
                    510:        lock_set_unlock(lock_set);              
                    511: 
                    512:        if (ulock->holder != thr_act) {
                    513:                ulock_unlock(ulock);
                    514:                lock_set_unlock(lock_set);
                    515:                return KERN_INVALID_RIGHT;
                    516:        }
                    517: 
                    518:        /*
                    519:         *  If we have a hint that threads might be waiting,
                    520:         *  try to transfer the lock ownership to a waiting thread
                    521:         *  and wake it up.
                    522:         */
                    523:        if (ulock->blocked) {
                    524:                wait_queue_t    wq = &ulock->wait_queue;
                    525:                thread_t        thread;
                    526:                spl_t           s;
                    527: 
                    528:                s = splsched();
                    529:                wait_queue_lock(wq);
                    530:                thread = wait_queue_wakeup_identity_locked(wq,
                    531:                                                           LOCK_SET_EVENT,
                    532:                                                           THREAD_AWAKENED,
                    533:                                                           TRUE);
                    534:                /* wait_queue now unlocked, thread locked */
                    535: 
                    536:                if (thread != THREAD_NULL) {
                    537:                        /*
                    538:                         * JMM - These ownership transfer macros have a
                    539:                         * locking/race problem.  To keep the thread from
                    540:                         * changing states on us (nullifying the ownership
                    541:                         * assignment) we need to keep the thread locked
                    542:                         * during the assignment.  But we can't because the
                    543:                         * macros take an activation lock, which is a mutex.
                    544:                         * Since this code was already broken before I got
                    545:                         * here, I will leave it for now.
                    546:                         */
                    547:                        thread_unlock(thread);
                    548: 
                    549:                        /*
                    550:                         *  Transfer ulock ownership
                    551:                         *  from the current thread to the acquisition thread.
                    552:                         */
                    553:                        ulock_ownership_clear(ulock);
                    554:                        ulock_ownership_set(ulock, thread);
                    555:                        ulock_unlock(ulock);
                    556:                        
                    557:                        return KERN_SUCCESS;
                    558:                } else {
                    559:                        ulock->blocked = FALSE;
                    560:                }
                    561:        }
                    562: 
                    563:        /*
                    564:         *  Disown ulock
                    565:         */
                    566:        ulock_ownership_clear(ulock);
                    567:        ulock_unlock(ulock);
                    568: 
                    569:        return KERN_SUCCESS;
                    570: }
                    571: 
                    572: kern_return_t
                    573: lock_handoff (lock_set_t lock_set, int lock_id)
                    574: {
                    575:        ulock_t   ulock;
                    576:        int       wait_result;
                    577: 
                    578: 
                    579:        if (lock_set == LOCK_SET_NULL)
                    580:                return KERN_INVALID_ARGUMENT;
                    581: 
                    582:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    583:                return KERN_INVALID_ARGUMENT;
                    584: 
                    585:  retry:
                    586:        lock_set_lock(lock_set);
                    587: 
                    588:        if (!lock_set->active) {
                    589:                lock_set_unlock(lock_set);
                    590:                return KERN_LOCK_SET_DESTROYED;
                    591:        }
                    592: 
                    593:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    594:        ulock_lock(ulock);
                    595:        lock_set_unlock(lock_set);
                    596: 
                    597:        if (ulock->holder != current_act()) {
                    598:                ulock_unlock(ulock);
                    599:                lock_set_unlock(lock_set);
                    600:                return KERN_INVALID_RIGHT;
                    601:        }
                    602:        
                    603:        /*
                    604:         *  If the accepting thread (the receiver) is already waiting
                    605:         *  to accept the lock from the handoff thread (the sender),
                    606:         *  then perform the hand-off now.
                    607:         */
                    608: 
                    609:        if (ulock->accept_wait) {
                    610:                wait_queue_t    wq = &ulock->wait_queue;
                    611:                thread_t        thread;
                    612:                spl_t           s;
                    613: 
                    614:                /*
                    615:                 *  See who the lucky devil is, if he is still there waiting.
                    616:                 */
                    617:                s = splsched();
                    618:                wait_queue_lock(wq);
                    619:                thread = wait_queue_wakeup_identity_locked(
                    620:                                           wq,
                    621:                                           LOCK_SET_HANDOFF,
                    622:                                           THREAD_AWAKENED,
                    623:                                           TRUE);
                    624:                /* wait queue unlocked, thread locked */
                    625: 
                    626:                /*
                    627:                 *  Transfer lock ownership
                    628:                 */
                    629:                if (thread != THREAD_NULL) {
                    630:                        /*
                    631:                         * JMM - These ownership transfer macros have a
                    632:                         * locking/race problem.  To keep the thread from
                    633:                         * changing states on us (nullifying the ownership
                    634:                         * assignment) we need to keep the thread locked
                    635:                         * during the assignment.  But we can't because the
                    636:                         * macros take an activation lock, which is a mutex.
                    637:                         * Since this code was already broken before I got
                    638:                         * here, I will leave it for now.
                    639:                         */
                    640:                        thread_unlock(thread);
                    641:                        splx(s);
                    642:                        
                    643:                        ulock_ownership_clear(ulock);
                    644:                        ulock_ownership_set(ulock, thread);
                    645:                        ulock->accept_wait = FALSE;
                    646:                        ulock_unlock(ulock);
                    647:                        return KERN_SUCCESS;
                    648:                } else {
                    649: 
                    650:                        /*
                    651:                         * OOPS.  The accepting thread must have been aborted.
                    652:                         * and is racing back to clear the flag that says is
                    653:                         * waiting for an accept.  He will clear it when we
                    654:                         * release the lock, so just fall thru and wait for
                    655:                         * the next accept thread (that's the way it is
                    656:                         * specified).
                    657:                         */
                    658:                        splx(s);
                    659:                }
                    660:        }
                    661: 
                    662:        /*
                    663:         * Indicate that there is a hand-off thread waiting, and then wait
                    664:         * for an accepting thread.
                    665:         */
                    666:        ulock->ho_wait = TRUE;
                    667:        wait_queue_assert_wait(&ulock->wait_queue,
                    668:                               LOCK_SET_HANDOFF,
                    669:                               THREAD_ABORTSAFE);
                    670:        ulock_unlock(ulock);
                    671: 
                    672:        ETAP_SET_REASON(current_thread(), BLOCKED_ON_LOCK_HANDOFF);
                    673:        wait_result = thread_block((void (*)(void))0);
                    674: 
                    675:        /*
                    676:         *  If the thread was woken-up via some action other than
                    677:         *  lock_handoff_accept or lock_set_destroy (i.e. thread_terminate),
                    678:         *  then we need to clear the ulock's handoff state.
                    679:         */
                    680:        switch (wait_result) {
                    681: 
                    682:        case THREAD_AWAKENED:
                    683:                return KERN_SUCCESS;
                    684: 
                    685:        case THREAD_INTERRUPTED:
                    686:                ulock_lock(ulock);
                    687:                assert(ulock->holder == current_act());
                    688:                ulock->ho_wait = FALSE;
                    689:                ulock_unlock(ulock);
                    690:                return KERN_ABORTED;
                    691: 
                    692:        case THREAD_RESTART:
                    693:                goto retry;
                    694: 
                    695:        default:
                    696:                panic("lock_handoff");
                    697:        }
                    698: }
                    699: 
                    700: kern_return_t
                    701: lock_handoff_accept (lock_set_t lock_set, int lock_id)
                    702: {
                    703:        ulock_t   ulock;
                    704:        int       wait_result;
                    705: 
                    706: 
                    707:        if (lock_set == LOCK_SET_NULL)
                    708:                return KERN_INVALID_ARGUMENT;
                    709: 
                    710:        if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
                    711:                return KERN_INVALID_ARGUMENT;
                    712: 
                    713:  retry:
                    714:        lock_set_lock(lock_set);
                    715:        if (!lock_set->active) {
                    716:                lock_set_unlock(lock_set);
                    717:                return KERN_LOCK_SET_DESTROYED;
                    718:        }
                    719: 
                    720:        ulock = (ulock_t) &lock_set->ulock_list[lock_id];
                    721:        ulock_lock(ulock);
                    722:        lock_set_unlock(lock_set);
                    723: 
                    724:        /*
                    725:         * If there is another accepting thread that beat us, just
                    726:         * return with an error.
                    727:         */
                    728:        if (ulock->accept_wait) {
                    729:                ulock_unlock(ulock);
                    730:                return KERN_ALREADY_WAITING;
                    731:        }
                    732: 
                    733:        if (ulock->holder == current_act()) {
                    734:                ulock_unlock(ulock);
                    735:                return KERN_LOCK_OWNED_SELF;
                    736:        }
                    737: 
                    738:        /*
                    739:         *  If the handoff thread (the sender) is already waiting to
                    740:         *  hand-off the lock to the accepting thread (the receiver),
                    741:         *  then perform the hand-off now.
                    742:         */
                    743:        if (ulock->ho_wait) {
                    744:                wait_queue_t    wq = &ulock->wait_queue;
                    745:                thread_t        thread;
                    746:                spl_t           s;
                    747: 
                    748:                /*
                    749:                 *  See who the lucky devil is, if he is still there waiting.
                    750:                 */
                    751:                assert(ulock->holder != THR_ACT_NULL);
                    752:                thread = ulock->holder->thread;
                    753: 
                    754:                wait_queue_lock(wq);
                    755:                if (wait_queue_wakeup_thread_locked(wq,
                    756:                                                    LOCK_SET_HANDOFF,
                    757:                                                    thread,
                    758:                                                    THREAD_AWAKENED,
                    759:                                /* unlock? */       TRUE) == KERN_SUCCESS) {
                    760:                        /*
                    761:                         * Holder thread was still waiting to give it
                    762:                         * away.  Take over ownership.
                    763:                         */
                    764:                        ulock_ownership_clear(ulock);
                    765:                        ulock_ownership_set(ulock, current_thread());
                    766:                        ulock->ho_wait = FALSE;
                    767:                        ulock_unlock(ulock);
                    768:                        return (ulock->unstable) ? KERN_LOCK_UNSTABLE :
                    769:                                                   KERN_SUCCESS;
                    770:                }
                    771:                        
                    772:                /*
                    773:                 * OOPS.  The owner was aborted out of the handoff.
                    774:                 * He will clear his own flag when he gets back.
                    775:                 * in the meantime, we will wait as if we didn't
                    776:                 * even see his flag (by falling thru).
                    777:                 */
                    778:        }               
                    779: 
                    780:        ulock->accept_wait = TRUE;
                    781:        wait_queue_assert_wait(&ulock->wait_queue,
                    782:                               LOCK_SET_HANDOFF,
                    783:                               THREAD_ABORTSAFE);
                    784:        ulock_unlock(ulock);
                    785: 
                    786:        ETAP_SET_REASON(current_thread(), BLOCKED_ON_LOCK_HANDOFF);
                    787:        wait_result = thread_block((void (*)(void))0);
                    788: 
                    789:        /*
                    790:         *  If the thread was woken-up via some action other than
                    791:         *  lock_handoff_accept or lock_set_destroy (i.e. thread_terminate),
                    792:         *  then we need to clear the ulock's handoff state.
                    793:         */
                    794:        switch (wait_result) {
                    795: 
                    796:        case THREAD_AWAKENED:
                    797:                return KERN_SUCCESS;
                    798: 
                    799:        case THREAD_INTERRUPTED:
                    800:                ulock_lock(ulock);
                    801:                ulock->accept_wait = FALSE;
                    802:                ulock_unlock(ulock);
                    803:                return KERN_ABORTED;
                    804: 
                    805:        case THREAD_RESTART:
                    806:                goto retry;
                    807: 
                    808:        default:
                    809:                panic("lock_handoff_accept");
                    810:        }
                    811: }
                    812: 
                    813: /*
                    814:  *     Routine:        lock_set_reference
                    815:  *
                    816:  *     Take out a reference on a lock set.  This keeps the data structure
                    817:  *     in existence (but the lock set may be deactivated).
                    818:  */
                    819: void
                    820: lock_set_reference(lock_set_t lock_set)
                    821: {
                    822:        lock_set_lock(lock_set);
                    823:        lock_set->ref_count++;
                    824:        lock_set_unlock(lock_set);
                    825: }
                    826: 
                    827: /*
                    828:  *     Routine:        lock_set_dereference
                    829:  *
                    830:  *     Release a reference on a lock set.  If this is the last reference,
                    831:  *     the lock set data structure is deallocated.
                    832:  */
                    833: void
                    834: lock_set_dereference(lock_set_t lock_set)
                    835: {
                    836:        int     ref_count;
                    837:        int     size;
                    838: 
                    839:        lock_set_lock(lock_set);
                    840:        ref_count = --(lock_set->ref_count);
                    841:        lock_set_unlock(lock_set);
                    842: 
                    843:        if (ref_count == 0) {
                    844:                size =  sizeof(struct lock_set) +
                    845:                        (sizeof(struct ulock) * (lock_set->n_ulocks - 1));
                    846:                kfree((vm_offset_t) lock_set, size);
                    847:        }
                    848: }

unix.superglobalmegacorp.com

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