Annotation of XNU/osfmk/kern/sync_sema.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_sema.c
                     28:  *     Author: Joseph CaraDonna
                     29:  *
                     30:  *     Contains RT distributed semaphore synchronization services.
                     31:  */
                     32: /*
                     33:  *     Semaphores: Rule of Thumb
                     34:  *
                     35:  *     A non-negative semaphore count means that the blocked threads queue is
                     36:  *     empty.  A semaphore count of negative n means that the blocked threads
                     37:  *     queue contains n blocked threads.
                     38:  */
                     39: 
                     40: #include <kern/misc_protos.h>
                     41: #include <kern/sync_sema.h>
                     42: #include <kern/spl.h>
                     43: #include <kern/ipc_kobject.h>
                     44: #include <kern/ipc_sync.h>
                     45: #include <kern/thread.h>
                     46: #include <kern/clock.h>
                     47: #include <ipc/ipc_port.h>
                     48: #include <ipc/ipc_space.h>
                     49: #include <kern/host.h>
                     50: #include <kern/wait_queue.h>
                     51: 
                     52: unsigned int semaphore_event;
                     53: #define SEMAPHORE_EVENT ((event_t)&semaphore_event)
                     54: 
                     55: /*
                     56:  * forward declaration
                     57:  */
                     58: void   semaphore_dereference(
                     59:                        semaphore_t             semaphore);
                     60: 
                     61: /*
                     62:  *     Routine:        semaphore_create
                     63:  *
                     64:  *     Creates a semaphore.
                     65:  *     The port representing the semaphore is returned as a parameter.
                     66:  */
                     67: kern_return_t
                     68: semaphore_create(
                     69:        task_t                  task,
                     70:        semaphore_t             *new_semaphore,
                     71:        int                             policy,
                     72:        int                             value)
                     73: {
                     74:        semaphore_t              s = SEMAPHORE_NULL;
                     75: 
                     76:        *new_semaphore = SEMAPHORE_NULL;
                     77: 
                     78: 
                     79:        if (task == TASK_NULL || value < 0 || policy > SYNC_POLICY_MAX)
                     80:                return KERN_INVALID_ARGUMENT;
                     81: 
                     82:        s = (semaphore_t) kalloc (sizeof(struct semaphore));
                     83: 
                     84:        if (s == SEMAPHORE_NULL)
                     85:                return KERN_RESOURCE_SHORTAGE; 
                     86: 
                     87:        wait_queue_init(&s->wait_queue, policy); /* also inits lock */
                     88:        s->count = value;
                     89:        s->ref_count = 1;
                     90: 
                     91:        /*
                     92:         *  Create and initialize the semaphore port
                     93:         */
                     94:        s->port = ipc_port_alloc_kernel();
                     95:        if (s->port == IP_NULL) {       
                     96:                /* This will deallocate the semaphore */        
                     97:                semaphore_dereference(s);
                     98:                return KERN_RESOURCE_SHORTAGE; 
                     99:        }
                    100: 
                    101:        ipc_kobject_set (s->port, (ipc_kobject_t) s, IKOT_SEMAPHORE);
                    102: 
                    103:        /*
                    104:         *  Associate the new semaphore with the task by adding
                    105:         *  the new semaphore to the task's semaphore list.
                    106:         *
                    107:         *  Associate the task with the new semaphore by having the
                    108:         *  semaphores task pointer point to the owning task's structure.
                    109:         */
                    110:        task_lock(task);
                    111:        enqueue_head(&task->semaphore_list, (queue_entry_t) s);
                    112:        task->semaphores_owned++;
                    113:        task_unlock(task);
                    114:        s->owner = task;
                    115: 
                    116:        /*
                    117:         *  Activate semaphore
                    118:         */
                    119:        s->active = TRUE;
                    120:        *new_semaphore = s;
                    121: 
                    122:        return KERN_SUCCESS;
                    123: }                
                    124: 
                    125: /*
                    126:  *     Routine:        semaphore_destroy
                    127:  *
                    128:  *     Destroys a semaphore.  This call will only succeed if the
                    129:  *     specified task is the SAME task name specified at the semaphore's
                    130:  *     creation.
                    131:  *
                    132:  *     All threads currently blocked on the semaphore are awoken.  These
                    133:  *     threads will return with the KERN_TERMINATED error.
                    134:  */
                    135: kern_return_t
                    136: semaphore_destroy(
                    137:        task_t                  task,
                    138:        semaphore_t             semaphore)
                    139: {
                    140:        int                             old_count;
                    141:        thread_t                thread;
                    142:        spl_t                   spl_level;
                    143: 
                    144: 
                    145:        if (task == TASK_NULL || semaphore == SEMAPHORE_NULL)
                    146:                return KERN_INVALID_ARGUMENT;
                    147: 
                    148:        if (semaphore->owner != task)
                    149:                return KERN_INVALID_RIGHT;
                    150: 
                    151:        
                    152:        spl_level = splsched();
                    153:        wait_queue_lock(&semaphore->wait_queue);
                    154: 
                    155:        if (!semaphore->active) {
                    156:                wait_queue_unlock(&semaphore->wait_queue);
                    157:                splx(spl_level);
                    158:                return KERN_TERMINATED;
                    159:        }
                    160: 
                    161:        /*
                    162:         *  Deactivate semaphore
                    163:         */
                    164:        semaphore->active = FALSE;
                    165: 
                    166:        /*
                    167:         *  Wakeup blocked threads  
                    168:         */
                    169:        old_count = semaphore->count;
                    170:        semaphore->count = 0;
                    171: 
                    172:        if (old_count < 0) {
                    173:                wait_queue_wakeup_all_locked(&semaphore->wait_queue,
                    174:                                             SEMAPHORE_EVENT,
                    175:                                             THREAD_RESTART,
                    176:                                             TRUE);             /* unlock? */
                    177:        } else {
                    178:                wait_queue_unlock(&semaphore->wait_queue);
                    179:        }
                    180: 
                    181:        /*
                    182:         *  Disown semaphore
                    183:         */
                    184:        task_lock(task);
                    185:        remqueue(&task->semaphore_list, (queue_entry_t) semaphore);
                    186:        task->semaphores_owned--;
                    187:        task_unlock(task);
                    188: 
                    189:        splx(spl_level);
                    190: 
                    191:        /*
                    192:         *  Deallocate
                    193:         *
                    194:         *  Drop the semaphore reference, which inturn deallocates the
                    195:         *  semaphore structure if the reference count goes to zero.
                    196:         */
                    197:        ipc_port_dealloc_kernel(semaphore->port);
                    198:        semaphore_dereference(semaphore);
                    199: 
                    200:        return KERN_SUCCESS;
                    201: }
                    202: 
                    203: /*
                    204:  *     Routine:        semaphore_signal_thread
                    205:  *
                    206:  *     If the specified thread_act is blocked on the semaphore, it is
                    207:  *     woken up.  Otherwise the caller gets KERN_NOT_WAITING and the
                    208:  *     semaphore is unchanged.
                    209:  */
                    210: kern_return_t
                    211: semaphore_signal_thread(
                    212:        semaphore_t             semaphore,
                    213:        thread_act_t    thread_act)
                    214: {
                    215:        kern_return_t           ret = KERN_NOT_WAITING;
                    216:        spl_t                   spl_level;
                    217: 
                    218:        if (semaphore == SEMAPHORE_NULL)
                    219:                return KERN_INVALID_ARGUMENT;
                    220: 
                    221:        spl_level = splsched();
                    222:        wait_queue_lock(&semaphore->wait_queue);
                    223: 
                    224:        if (!semaphore->active) {
                    225:                wait_queue_unlock(&semaphore->wait_queue);
                    226:                splx(spl_level);
                    227:                return KERN_TERMINATED;
                    228:        }
                    229:        if (semaphore->count < 0) {
                    230:                ret = wait_queue_wakeup_thread_locked(&semaphore->wait_queue,
                    231:                                                      SEMAPHORE_EVENT,
                    232:                                                      thread_act->thread,
                    233:                                                      THREAD_AWAKENED,
                    234:                                                      TRUE);  /* unlock? */
                    235:        } else {
                    236:                wait_queue_unlock(&semaphore->wait_queue);
                    237:        }
                    238:        splx(spl_level);
                    239: 
                    240:        return(ret);
                    241: }
                    242: 
                    243: /*
                    244:  *     Routine:        semaphore_signal
                    245:  *
                    246:  *     Increments the semaphore count by one.  If any threads are blocked
                    247:  *     on the semaphore ONE is woken up.
                    248:  */
                    249: kern_return_t
                    250: semaphore_signal(
                    251:        semaphore_t             semaphore)
                    252: {
                    253:        spl_t                   spl_level;
                    254: 
                    255:        if (semaphore == SEMAPHORE_NULL)
                    256:                return KERN_INVALID_ARGUMENT;
                    257: 
                    258:        spl_level = splsched();
                    259:        wait_queue_lock(&semaphore->wait_queue);
                    260: 
                    261:        if (!semaphore->active) {
                    262:                wait_queue_unlock(&semaphore->wait_queue);
                    263:                splx(spl_level);
                    264:                return KERN_TERMINATED;
                    265:        }
                    266:        if (semaphore->count < 0) {
                    267:                if (wait_queue_wakeup_one_locked(&semaphore->wait_queue,
                    268:                                                 SEMAPHORE_EVENT,
                    269:                                                 THREAD_AWAKENED,
                    270:                                                 FALSE) == KERN_NOT_WAITING) {
                    271: 
                    272:                        semaphore->count = 1;  /* waiters have busted out */
                    273:                                               /* becomes a pre-signal. */
                    274:                }
                    275:        } else {
                    276:                semaphore->count++;
                    277:        }
                    278:        wait_queue_unlock(&semaphore->wait_queue);
                    279:        splx(spl_level);
                    280: 
                    281:        return KERN_SUCCESS;
                    282: }
                    283: 
                    284: /*
                    285:  *     Routine:        semaphore_signal_all
                    286:  *
                    287:  *     Awakens ALL threads currently blocked on the semaphore.
                    288:  *     The semaphore count returns to zero.
                    289:  */
                    290: kern_return_t
                    291: semaphore_signal_all(
                    292:        semaphore_t             semaphore)
                    293: {
                    294:        int old_count;
                    295:        spl_t spl_level;
                    296: 
                    297:        if (semaphore == SEMAPHORE_NULL)
                    298:                return KERN_INVALID_ARGUMENT;
                    299: 
                    300:        spl_level = splsched();
                    301:        wait_queue_lock(&semaphore->wait_queue);
                    302: 
                    303:        if (!semaphore->active) {
                    304:                wait_queue_unlock(&semaphore->wait_queue);
                    305:                splx(spl_level);
                    306:                return KERN_TERMINATED;
                    307:        }
                    308: 
                    309:        old_count = semaphore->count;
                    310:        semaphore->count = 0;  /* always reset */
                    311: 
                    312:        if (old_count < 0) {
                    313:                wait_queue_wakeup_all_locked(&semaphore->wait_queue,
                    314:                                             SEMAPHORE_EVENT,
                    315:                                             THREAD_AWAKENED,
                    316:                                             TRUE);             /* unlock? */
                    317:        } else {
                    318:                wait_queue_unlock(&semaphore->wait_queue);
                    319:        }
                    320:        splx(spl_level);
                    321: 
                    322:        return KERN_SUCCESS;
                    323: }
                    324: 
                    325: 
                    326: /*
                    327:  *     Routine:        semaphore_wait_common
                    328:  *
                    329:  *  Wait on a semaphore.  If the semaphore has been pre-posted, it just
                    330:  *     claims one count, and returns success.  Otherwise, set up to block.
                    331:  */
                    332: kern_return_t
                    333: semaphore_wait_common(
                    334:        semaphore_t                     semaphore,
                    335:        mach_timespec_t         *wait_time)
                    336: {
                    337:        AbsoluteTime            abstime, nsinterval;
                    338:        int                                     wait_result;
                    339:        spl_t                           spl_level;
                    340: 
                    341:        if (semaphore == SEMAPHORE_NULL)
                    342:                return KERN_INVALID_ARGUMENT;
                    343: 
                    344:        if (wait_time != 0) {
                    345:                if (BAD_MACH_TIMESPEC(wait_time))
                    346:                        return KERN_INVALID_VALUE;
                    347: 
                    348:                clock_interval_to_absolutetime_interval(
                    349:                                                        wait_time->tv_sec, NSEC_PER_SEC, &abstime);
                    350:                clock_interval_to_absolutetime_interval(
                    351:                                                        wait_time->tv_nsec, 1, &nsinterval);
                    352:                ADD_ABSOLUTETIME(&abstime, &nsinterval);
                    353:                clock_absolutetime_interval_to_deadline(abstime, &abstime);
                    354:        }
                    355: 
                    356:  restart:
                    357:        spl_level = splsched();
                    358:        wait_queue_lock(&semaphore->wait_queue);
                    359: 
                    360:        if (!semaphore->active) {
                    361:                wait_queue_unlock(&semaphore->wait_queue);
                    362:                splx(spl_level);
                    363:                return KERN_TERMINATED;
                    364:        }
                    365: 
                    366:        if (semaphore->count > 0) {
                    367:                semaphore->count--;
                    368:                wait_queue_unlock(&semaphore->wait_queue);
                    369:                splx(spl_level);
                    370:                return KERN_SUCCESS;
                    371:        }
                    372: 
                    373:        if (wait_time != 0 && wait_time->tv_sec == 0 && wait_time->tv_nsec == 0) {
                    374:                wait_queue_unlock(&semaphore->wait_queue);
                    375:                splx(spl_level);
                    376:                return KERN_OPERATION_TIMED_OUT;
                    377:        }
                    378: 
                    379:        semaphore->count = -1;  /* we don't keep an actual count */
                    380: 
                    381:        wait_queue_assert_wait_locked(&semaphore->wait_queue,
                    382:                                      SEMAPHORE_EVENT,
                    383:                                      THREAD_ABORTSAFE,
                    384:                                      TRUE); /* unlock? */
                    385:        /* semaphore->wait_queue is unlocked */
                    386: 
                    387:        splx(spl_level);
                    388: 
                    389:        if (wait_time != 0)
                    390:                thread_set_timer_deadline(abstime);
                    391: 
                    392:        wait_result = thread_block((void (*)(void))0);
                    393:        
                    394:        if (wait_time != 0) {
                    395:                thread_cancel_timer();
                    396:        }
                    397: 
                    398:        switch (wait_result) {
                    399:                case THREAD_AWAKENED:
                    400:                        return KERN_SUCCESS;
                    401: 
                    402:                case THREAD_TIMED_OUT:
                    403:                        return KERN_OPERATION_TIMED_OUT;
                    404: 
                    405:                case THREAD_INTERRUPTED:
                    406:                        return KERN_ABORTED;
                    407: 
                    408:                case THREAD_RESTART:
                    409:                        goto restart;
                    410: 
                    411:                default:
                    412:                        panic("semaphore_wait_common\n");
                    413:                        break;
                    414:                }
                    415: }
                    416: 
                    417: 
                    418: /*
                    419:  *     Routine:        semaphore_wait
                    420:  *
                    421:  *     Decrements the semaphore count by one.  If the count is negative
                    422:  *     after the decrement, the calling thread blocks.
                    423:  *
                    424:  *     Assumes: Never called from interrupt context.
                    425:  */
                    426: kern_return_t
                    427: semaphore_wait(
                    428:        semaphore_t                     semaphore)
                    429: {      
                    430:        return (semaphore_wait_common(semaphore, (mach_timespec_t *) 0));
                    431: }
                    432: 
                    433: /*
                    434:  *     Routine:        semaphore_timedwait
                    435:  *
                    436:  *     Decrements the semaphore count by one.  If the count is negative
                    437:  *     after the decrement, the calling thread blocks.  
                    438:  *     Sleep for max 'wait_time' (0=>forever)
                    439:  *
                    440:  *     Assumes: Never called from interrupt context.
                    441:  */
                    442: kern_return_t
                    443: semaphore_timedwait(
                    444:        semaphore_t                     semaphore,
                    445:        mach_timespec_t         wait_time)
                    446: {
                    447:        return (semaphore_wait_common(semaphore, &wait_time));
                    448: }
                    449: 
                    450: /*
                    451:  *     Routine:        semaphore_reference
                    452:  *
                    453:  *     Take out a reference on a semaphore.  This keeps the data structure
                    454:  *     in existence (but the semaphore may be deactivated).
                    455:  */
                    456: void
                    457: semaphore_reference(
                    458:        semaphore_t             semaphore)
                    459: {
                    460:        spl_t                   spl_level;
                    461: 
                    462:        spl_level = splsched();
                    463:        wait_queue_lock(&semaphore->wait_queue);
                    464: 
                    465:        semaphore->ref_count++;
                    466: 
                    467:        wait_queue_unlock(&semaphore->wait_queue);
                    468:        splx(spl_level);
                    469: }
                    470: 
                    471: /*
                    472:  *     Routine:        semaphore_dereference
                    473:  *
                    474:  *     Release a reference on a semaphore.  If this is the last reference,
                    475:  *     the semaphore data structure is deallocated.
                    476:  */
                    477: void
                    478: semaphore_dereference(
                    479:        semaphore_t             semaphore)
                    480: {
                    481:        int                             ref_count;
                    482:        spl_t                   spl_level;
                    483: 
                    484:        if (semaphore != NULL) {
                    485:            spl_level = splsched();
                    486:            wait_queue_lock(&semaphore->wait_queue);
                    487: 
                    488:            ref_count = --(semaphore->ref_count);
                    489: 
                    490:            wait_queue_unlock(&semaphore->wait_queue);
                    491:            splx(spl_level);
                    492: 
                    493:            if (ref_count == 0) {
                    494:                        assert(wait_queue_empty(&semaphore->wait_queue));
                    495:                        kfree((vm_offset_t) semaphore, sizeof(struct semaphore));
                    496:            }
                    497:        }
                    498: }

unix.superglobalmegacorp.com

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