Annotation of XNU/osfmk/kern/clock.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:  *     File:           kern/clock.c
                     27:  *     Purpose:        Routines for the creation and use of kernel
                     28:  *                     alarm clock services. This file and the ipc
                     29:  *                     routines in kern/ipc_clock.c constitute the
                     30:  *                     machine-independent clock service layer.
                     31:  */
                     32: 
                     33: #include <cpus.h>
                     34: #include <mach_host.h>
                     35: 
                     36: #include <mach/boolean.h>
                     37: #include <mach/policy.h>
                     38: #include <mach/processor_info.h>
                     39: #include <mach/vm_param.h>
                     40: #include <machine/mach_param.h>
                     41: #include <kern/cpu_number.h>
                     42: #include <kern/misc_protos.h>
                     43: #include <kern/lock.h>
                     44: #include <kern/host.h>
                     45: #include <kern/processor.h>
                     46: #include <kern/sched.h>
                     47: #include <kern/spl.h>
                     48: #include <kern/thread.h>
                     49: #include <kern/thread_swap.h>
                     50: #include <kern/ipc_host.h>
                     51: #include <kern/clock.h>
                     52: #include <kern/zalloc.h>
                     53: #include <kern/sf.h>
                     54: #include <ipc/ipc_port.h>
                     55: #include <mach/mach_syscalls.h>
                     56: 
                     57: #include <mach/clock_reply.h>
                     58: 
                     59: /*
                     60:  * Exported interface
                     61:  */
                     62: 
                     63: #include <mach/clock_server.h>
                     64: #include <mach/mach_host_server.h>
                     65: 
                     66: /* local data declarations */
                     67: decl_simple_lock_data(static,ClockLock)                /* clock system synchronization */
                     68: static struct  zone            *alarm_zone;    /* zone for user alarms */
                     69: static struct  alarm           *alrmfree;              /* alarm free list pointer */
                     70: static struct  alarm           *alrmdone;              /* alarm done list pointer */
                     71: static long                                    alrm_seqno;             /* uniquely identifies alarms */
                     72: static thread_call_data_t      alarm_deliver;
                     73: 
                     74: /* backwards compatibility */
                     75: int             hz = HZ;                /* GET RID OF THIS !!! */
                     76: int             tick = (1000000 / HZ);  /* GET RID OF THIS !!! */
                     77: 
                     78: /* external declarations */
                     79: extern struct clock    clock_list[];
                     80: extern int             clock_count;
                     81: 
                     82: /* local clock subroutines */
                     83: static
                     84: void   flush_alarms(
                     85:                        clock_t                 clock);
                     86: 
                     87: static
                     88: void   post_alarm(
                     89:                        clock_t                 clock,
                     90:                        alarm_t                 alarm);
                     91: 
                     92: static
                     93: int            check_time(
                     94:                        alarm_type_t    alarm_type,
                     95:                        mach_timespec_t *alarm_time,
                     96:                        mach_timespec_t *clock_time);
                     97: 
                     98: static void            clock_alarm_deliver(void);
                     99: 
                    100: /*
                    101:  *     Macros to lock/unlock clock system.
                    102:  */
                    103: #define LOCK_CLOCK(s)                  \
                    104:        s = splclock();                 \
                    105:        simple_lock(&ClockLock);
                    106: 
                    107: #define UNLOCK_CLOCK(s)                        \
                    108:        simple_unlock(&ClockLock);      \
                    109:        splx(s);
                    110: 
                    111: /*
                    112:  * Configure the clock system. (Not sure if we need this,
                    113:  * as separate from clock_init()).
                    114:  */
                    115: void
                    116: clock_config(void)
                    117: {
                    118:        clock_t                 clock;
                    119:        register int    i;
                    120: 
                    121:        if (cpu_number() != master_cpu)
                    122:                panic("clock_config");
                    123: 
                    124:        /*
                    125:         * Configure clock devices.
                    126:         */
                    127:        simple_lock_init(&ClockLock, ETAP_MISC_CLOCK);
                    128:        for (i = 0; i < clock_count; i++) {
                    129:                clock = &clock_list[i];
                    130:                if (clock->cl_ops) {
                    131:                        if ((*clock->cl_ops->c_config)() == 0)
                    132:                                clock->cl_ops = 0;
                    133:                }
                    134:        }
                    135: 
                    136:        /* start alarm sequence numbers at 0 */
                    137:        alrm_seqno = 0;
                    138: }
                    139: 
                    140: /*
                    141:  * Initialize the clock system.
                    142:  */
                    143: void
                    144: clock_init(void)
                    145: {
                    146:        clock_t                 clock;
                    147:        register int    i;
                    148: 
                    149:        /*
                    150:         * Initialize basic clock structures.
                    151:         */
                    152:        for (i = 0; i < clock_count; i++) {
                    153:                clock = &clock_list[i];
                    154:                if (clock->cl_ops)
                    155:                        (*clock->cl_ops->c_init)();
                    156:        }
                    157: }
                    158: 
                    159: /*
                    160:  * Initialize the clock ipc service facility.
                    161:  */
                    162: void
                    163: clock_service_create(void)
                    164: {
                    165:        clock_t                 clock;
                    166:        register int    i;
                    167: 
                    168:        /*
                    169:         * Initialize ipc clock services.
                    170:         */
                    171:        for (i = 0; i < clock_count; i++) {
                    172:                clock = &clock_list[i];
                    173:                if (clock->cl_ops) {
                    174:                        ipc_clock_init(clock);
                    175:                        ipc_clock_enable(clock);
                    176:                }
                    177:        }
                    178: 
                    179:        /*
                    180:         * Initialize clock service alarms.
                    181:         */
                    182:        i = sizeof(struct alarm);
                    183:        alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms");
                    184: 
                    185:        /*
                    186:         * Initialize the clock alarm delivery mechanism.
                    187:         */
                    188:        thread_call_setup(&alarm_deliver, clock_alarm_deliver, NULL);
                    189: }
                    190: 
                    191: /*
                    192:  * Get the service port on a clock.
                    193:  */
                    194: kern_return_t
                    195: host_get_clock_service(
                    196:        host_t                  host,
                    197:        clock_id_t              clock_id,
                    198:        clock_t                 *clock)         /* OUT */
                    199: {
                    200:        if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
                    201:                *clock = CLOCK_NULL;
                    202:                return (KERN_INVALID_ARGUMENT);
                    203:        }
                    204: 
                    205:        *clock = &clock_list[clock_id];
                    206:        if ((*clock)->cl_ops == 0)
                    207:                return (KERN_FAILURE);
                    208:        return (KERN_SUCCESS);
                    209: }
                    210: 
                    211: /*
                    212:  * Get the control port on a clock.
                    213:  */
                    214: kern_return_t
                    215: host_get_clock_control(
                    216:        host_t                  host,
                    217:        clock_id_t              clock_id,
                    218:        clock_t                 *clock)         /* OUT */
                    219: {
                    220:        if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
                    221:                *clock = CLOCK_NULL;
                    222:                return (KERN_INVALID_ARGUMENT);
                    223:        }
                    224: 
                    225:        *clock = &clock_list[clock_id];
                    226:        if ((*clock)->cl_ops == 0)
                    227:                return (KERN_FAILURE);
                    228:        return (KERN_SUCCESS);
                    229: }
                    230: 
                    231: /*
                    232:  * Get the current clock time.
                    233:  */
                    234: kern_return_t
                    235: clock_get_time(
                    236:        clock_t                 clock,
                    237:        mach_timespec_t *cur_time)      /* OUT */
                    238: {
                    239:        if (clock == CLOCK_NULL)
                    240:                return (KERN_INVALID_ARGUMENT);
                    241:        return ((*clock->cl_ops->c_gettime)(cur_time));
                    242: }
                    243: 
                    244: /*
                    245:  * Get clock attributes.
                    246:  */
                    247: kern_return_t
                    248: clock_get_attributes(
                    249:        clock_t                                 clock,
                    250:        clock_flavor_t                  flavor,
                    251:        clock_attr_t                    attr,           /* OUT */
                    252:        mach_msg_type_number_t  *count)         /* IN/OUT */
                    253: {
                    254:        kern_return_t   (*getattr)(
                    255:                                                clock_flavor_t                  flavor,
                    256:                                                clock_attr_t                    attr,
                    257:                                                mach_msg_type_number_t  *count);
                    258: 
                    259:        if (clock == CLOCK_NULL)
                    260:                return (KERN_INVALID_ARGUMENT);
                    261:        if (getattr = clock->cl_ops->c_getattr)
                    262:                return((*getattr)(flavor, attr, count));
                    263:        else
                    264:                return (KERN_FAILURE);
                    265: }
                    266: 
                    267: /*
                    268:  * Set the current clock time.
                    269:  */
                    270: kern_return_t
                    271: clock_set_time(
                    272:        clock_t                 clock,
                    273:        mach_timespec_t new_time)
                    274: {
                    275:        mach_timespec_t *clock_time;
                    276:        kern_return_t   (*settime)(
                    277:                                                mach_timespec_t         *clock_time);
                    278: 
                    279:        if (clock == CLOCK_NULL)
                    280:                return (KERN_INVALID_ARGUMENT);
                    281:        if ((settime = clock->cl_ops->c_settime) == 0)
                    282:                return (KERN_FAILURE);
                    283:        clock_time = &new_time;
                    284:        if (BAD_MACH_TIMESPEC(clock_time))
                    285:                return (KERN_INVALID_VALUE);
                    286: 
                    287:        /*
                    288:         * Flush all outstanding alarms.
                    289:         */
                    290:        flush_alarms(clock);
                    291: 
                    292:        /*
                    293:         * Set the new time.
                    294:         */
                    295:        return ((*settime)(clock_time));
                    296: }
                    297: 
                    298: /*
                    299:  * Set the clock alarm resolution.
                    300:  */
                    301: kern_return_t
                    302: clock_set_attributes(
                    303:        clock_t                                 clock,
                    304:        clock_flavor_t                  flavor,
                    305:        clock_attr_t                    attr,
                    306:        mach_msg_type_number_t  count)
                    307: {
                    308:        kern_return_t   (*setattr)(
                    309:                                                clock_flavor_t                  flavor,
                    310:                                                clock_attr_t                    attr,
                    311:                                                mach_msg_type_number_t  count);
                    312: 
                    313:        if (clock == CLOCK_NULL)
                    314:                return (KERN_INVALID_ARGUMENT);
                    315:        if (setattr = clock->cl_ops->c_setattr)
                    316:                return ((*setattr)(flavor, attr, count));
                    317:        else
                    318:                return (KERN_FAILURE);
                    319: }
                    320: 
                    321: /*
                    322:  * Setup a clock alarm.
                    323:  */
                    324: kern_return_t
                    325: clock_alarm(
                    326:        clock_t                                 clock,
                    327:        alarm_type_t                    alarm_type,
                    328:        mach_timespec_t                 alarm_time,
                    329:        ipc_port_t                              alarm_port,
                    330:        mach_msg_type_name_t    alarm_port_type)
                    331: {
                    332:        alarm_t                                 alarm;
                    333:        mach_timespec_t                 clock_time;
                    334:        int                                             chkstat;
                    335:        kern_return_t                   reply_code;
                    336:        spl_t                                   s;
                    337: 
                    338:        if (clock == CLOCK_NULL)
                    339:                return (KERN_INVALID_ARGUMENT);
                    340:        if (clock->cl_ops->c_setalrm == 0)
                    341:                return (KERN_FAILURE);
                    342:        if (IP_VALID(alarm_port) == 0)
                    343:                return (KERN_INVALID_CAPABILITY);
                    344: 
                    345:        /*
                    346:         * Check alarm parameters. If parameters are invalid,
                    347:         * send alarm message immediately.
                    348:         */
                    349:        (*clock->cl_ops->c_gettime)(&clock_time);
                    350:        chkstat = check_time(alarm_type, &alarm_time, &clock_time);
                    351:        if (chkstat <= 0) {
                    352:                reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS);
                    353:                clock_alarm_reply(alarm_port, alarm_port_type,
                    354:                                  reply_code, alarm_type, clock_time);
                    355:                return (KERN_SUCCESS);
                    356:        }
                    357: 
                    358:        /*
                    359:         * Get alarm and add to clock alarm list.
                    360:         */
                    361: 
                    362:        LOCK_CLOCK(s);
                    363:        if ((alarm = alrmfree) == 0) {
                    364:                UNLOCK_CLOCK(s);
                    365:                alarm = (alarm_t) zalloc(alarm_zone);
                    366:                if (alarm == 0)
                    367:                        return (KERN_RESOURCE_SHORTAGE);
                    368:                LOCK_CLOCK(s);
                    369:        }
                    370:        else
                    371:                alrmfree = alarm->al_next;
                    372: 
                    373:        alarm->al_status = ALARM_CLOCK;
                    374:        alarm->al_time = alarm_time;
                    375:        alarm->al_type = alarm_type;
                    376:        alarm->al_port = alarm_port;
                    377:        alarm->al_port_type = alarm_port_type;
                    378:        alarm->al_clock = clock;
                    379:        alarm->al_policy = POLICY_NULL;
                    380:        alarm->al_seqno = alrm_seqno++;
                    381:        post_alarm(clock, alarm);
                    382:        UNLOCK_CLOCK(s);
                    383: 
                    384:        return (KERN_SUCCESS);
                    385: }
                    386: 
                    387: /*
                    388:  * Set a clock alarm for a scheduling policy.
                    389:  */
                    390: kern_return_t
                    391: clock_alarm_sp(
                    392:        alarm_type_t            alarm_type,
                    393:        mach_timespec_t         alarm_time,
                    394:        long                            *alarm_id,
                    395:        int                                     policy,
                    396:        void                            *alarm_data,
                    397:        alarm_t                         alarm)
                    398: {
                    399:        clock_t                         clock;
                    400:        mach_timespec_t         clock_time;
                    401:        int                                     chkstat;
                    402:        spl_t                           s;
                    403: 
                    404:        /* Always use system clock. */
                    405:        clock = &clock_list[SYSTEM_CLOCK];
                    406: 
                    407:        if (clock->cl_ops->c_setalrm == 0)
                    408:                return (KERN_FAILURE);
                    409: 
                    410:        assert(alarm != 0);
                    411: 
                    412:        /*
                    413:         * Check alarm parameters. If parameters are invalid,
                    414:         * send alarm message immediately.
                    415:         */
                    416:        (*clock->cl_ops->c_gettime)(&clock_time);
                    417:        chkstat = check_time(alarm_type, &alarm_time, &clock_time);
                    418:        if (chkstat <= 0) {
                    419:                return(chkstat < 0 ? KERN_INVALID_VALUE : KERN_RETURN_MAX);
                    420:                /*** ??? define a better value for `KERN_RETURN_MAX' ***/
                    421:        }
                    422: 
                    423:        /*
                    424:         * Get alarm and add to clock alarm list.
                    425:         */
                    426: 
                    427:        LOCK_CLOCK(s);
                    428:        alarm->al_status = ALARM_CLOCK;
                    429:        alarm->al_time = alarm_time;
                    430:        alarm->al_type = alarm_type;
                    431:        alarm->al_port = IP_NULL;
                    432:        alarm->al_port_type = 0;
                    433:        alarm->al_clock = clock;
                    434:        alarm->al_data = alarm_data;
                    435:        alarm->al_policy = policy;
                    436:        alarm->al_seqno = alrm_seqno++;
                    437:        *alarm_id = alarm->al_seqno;
                    438:        post_alarm(clock, alarm);
                    439:        UNLOCK_CLOCK(s);
                    440: 
                    441:        return (KERN_SUCCESS);
                    442: }
                    443: 
                    444: /*
                    445:  * Cancel a clock alarm on behalf of a scheduling policy.
                    446:  */
                    447: kern_return_t
                    448: clock_alarm_cancel_sp(
                    449:        long                            alarm_id)
                    450: {
                    451:        clock_t                         clock;
                    452:        alarm_t                         alrm1, alrm2;
                    453:        kern_return_t           kr = KERN_FAILURE;
                    454:        spl_t                           s;
                    455: 
                    456:        /*
                    457:         * Cancel alarm with ID `alarm_id.'
                    458:         */
                    459: 
                    460:        /* Always use system clock. */
                    461:        clock = &clock_list[SYSTEM_CLOCK];
                    462: 
                    463:        /* Assume you can't cancel alarms if you can't set them */
                    464:        if (clock->cl_ops->c_setalrm == 0)
                    465:                return (KERN_FAILURE);
                    466: 
                    467:        LOCK_CLOCK(s);
                    468:        alrm1 = (alarm_t) &clock->cl_alarm;
                    469:        while (alrm2 = alrm1->al_next) {
                    470:                /*
                    471:                 * See if alarm is still in alarm list.
                    472:                 */
                    473:                if (alrm2->al_seqno == alarm_id) {
                    474:                        /* Found it.  Now remove it. */
                    475:                        if (alrm1->al_next = alrm2->al_next) {
                    476:                                (alrm1->al_next)->al_prev = alrm1;
                    477:                        }
                    478: 
                    479:                        /* Indicate success */
                    480:                        kr = KERN_SUCCESS;
                    481: 
                    482:                        /*
                    483:                         * If the canceled alarm is the 'earliest' alarm,
                    484:                         * reset the device layer alarm time accordingly.
                    485:                         */
                    486:                        if (clock->cl_alarm.al_next == alrm2)
                    487:                                (*clock->cl_ops->c_setalrm)
                    488:                                  (&((clock->cl_alarm.al_next)->al_time));
                    489: 
                    490:                        /* Quit looking */
                    491:                        break;
                    492:                }
                    493:        }
                    494:        UNLOCK_CLOCK(s);
                    495: 
                    496:        return(kr);
                    497: }
                    498: 
                    499: /*
                    500:  * Sleep on a clock. System trap. User-level libmach clock_sleep
                    501:  * interface call takes a mach_timespec_t sleep_time argument which it
                    502:  * converts to sleep_sec and sleep_nsec arguments which are then
                    503:  * passed to clock_sleep_trap.
                    504:  */
                    505: kern_return_t
                    506: clock_sleep_trap(
                    507:        mach_port_name_t        clock_name,
                    508:        sleep_type_t            sleep_type,
                    509:        int                                     sleep_sec,
                    510:        int                                     sleep_nsec,
                    511:        mach_timespec_t         *wakeup_time)
                    512: {
                    513:        clock_t                         clock;
                    514:        mach_timespec_t         swtime;
                    515:        kern_return_t           rvalue;
                    516: 
                    517:        /*
                    518:         * Convert the trap parameters.
                    519:         */
                    520:        clock = port_name_to_clock(clock_name);
                    521:        swtime.tv_sec  = sleep_sec;
                    522:        swtime.tv_nsec = sleep_nsec;
                    523: 
                    524:        /*
                    525:         * Call the actual clock_sleep routine.
                    526:         */
                    527:        rvalue = clock_sleep_internal(clock, sleep_type, &swtime);
                    528: 
                    529:        /*
                    530:         * Return current time as wakeup time.
                    531:         */
                    532:        if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) {
                    533:                copyout((char *)&swtime, (char *)wakeup_time,
                    534:                        sizeof(mach_timespec_t));
                    535:        }
                    536:        return (rvalue);
                    537: }      
                    538: 
                    539: /*
                    540:  * Kernel internally callable clock sleep routine. The calling
                    541:  * thread is suspended until the requested sleep time is reached.
                    542:  */
                    543: kern_return_t
                    544: clock_sleep_internal(
                    545:        clock_t                         clock,
                    546:        sleep_type_t            sleep_type,
                    547:        mach_timespec_t         *sleep_time)
                    548: {
                    549:        alarm_t                         alarm;
                    550:        mach_timespec_t         clock_time;
                    551:        kern_return_t           rvalue;
                    552:        int                                     chkstat;
                    553:        spl_t                           s;
                    554: 
                    555:        if (clock == CLOCK_NULL)
                    556:                return (KERN_INVALID_ARGUMENT);
                    557:        if (clock->cl_ops->c_setalrm == 0)
                    558:                return (KERN_FAILURE);
                    559: 
                    560:        /*
                    561:         * Check sleep parameters. If parameters are invalid
                    562:         * return an error, otherwise post alarm request.
                    563:         */
                    564:        (*clock->cl_ops->c_gettime)(&clock_time);
                    565: 
                    566:        chkstat = check_time(sleep_type, sleep_time, &clock_time);
                    567:        if (chkstat < 0)
                    568:                return (KERN_INVALID_VALUE);
                    569:        rvalue = KERN_SUCCESS;
                    570:        if (chkstat > 0) {
                    571:                /*
                    572:                 * Get alarm and add to clock alarm list.
                    573:                 */
                    574: 
                    575:                LOCK_CLOCK(s);
                    576:                if ((alarm = alrmfree) == 0) {
                    577:                        UNLOCK_CLOCK(s);
                    578:                        alarm = (alarm_t) zalloc(alarm_zone);
                    579:                        if (alarm == 0)
                    580:                                return (KERN_RESOURCE_SHORTAGE);
                    581:                        LOCK_CLOCK(s);
                    582:                }
                    583:                else
                    584:                        alrmfree = alarm->al_next;
                    585: 
                    586:                alarm->al_time = *sleep_time;
                    587:                alarm->al_status = ALARM_SLEEP;
                    588:                post_alarm(clock, alarm);
                    589: 
                    590:                /*
                    591:                 * Wait for alarm to occur.
                    592:                 */
                    593:                assert_wait((event_t)alarm, THREAD_ABORTSAFE);
                    594:                UNLOCK_CLOCK(s);
                    595:                /* should we force spl(0) at this point? */
                    596:                thread_block((void (*)(void)) 0);
                    597:                /* we should return here at ipl0 */
                    598: 
                    599:                /*
                    600:                 * Note if alarm expired normally or whether it
                    601:                 * was aborted. If aborted, delete alarm from
                    602:                 * clock alarm list. Return alarm to free list.
                    603:                 */
                    604:                LOCK_CLOCK(s);
                    605:                if (alarm->al_status != ALARM_DONE) {
                    606:                        /* This means we were interrupted and that
                    607:                           thread->wait_result != THREAD_AWAKENED. */
                    608:                        if ((alarm->al_prev)->al_next = alarm->al_next)
                    609:                                (alarm->al_next)->al_prev = alarm->al_prev;
                    610:                        rvalue = KERN_ABORTED;
                    611:                }
                    612:                *sleep_time = alarm->al_time;
                    613:                alarm->al_status = ALARM_FREE;
                    614:                alarm->al_next = alrmfree;
                    615:                alrmfree = alarm;
                    616:                UNLOCK_CLOCK(s);
                    617:        }
                    618:        else
                    619:                *sleep_time = clock_time;
                    620: 
                    621:        return (rvalue);
                    622: }
                    623: 
                    624: /*
                    625:  * CLOCK INTERRUPT SERVICE ROUTINES.
                    626:  */
                    627: 
                    628: /*
                    629:  * Service clock alarm interrupts. Called from machine dependent
                    630:  * layer at splclock(). The clock_id argument specifies the clock,
                    631:  * and the clock_time argument gives that clock's current time.
                    632:  */
                    633: void
                    634: clock_alarm_intr(
                    635:        clock_id_t                      clock_id,
                    636:        mach_timespec_t         *clock_time)
                    637: {
                    638:        clock_t                         clock;
                    639:        register alarm_t        alrm1;
                    640:        register alarm_t        alrm2;
                    641:        mach_timespec_t         *alarm_time;
                    642:        spl_t                           s;
                    643: 
                    644:        clock = &clock_list[clock_id];
                    645: 
                    646:        /*
                    647:         * Update clock alarm list. All alarms that are due are moved
                    648:         * to the alarmdone list to be serviced by the alarm_thread.
                    649:         */
                    650: 
                    651:        LOCK_CLOCK(s);
                    652:        alrm1 = (alarm_t) &clock->cl_alarm;
                    653:        while (alrm2 = alrm1->al_next) {
                    654:                alarm_time = &alrm2->al_time;
                    655:                if (CMP_MACH_TIMESPEC(alarm_time, clock_time) > 0)
                    656:                        break;
                    657: 
                    658:                /*
                    659:                 * Alarm has expired, so remove it from the
                    660:                 * clock alarm list.
                    661:                 */  
                    662:                if (alrm1->al_next = alrm2->al_next)
                    663:                        (alrm1->al_next)->al_prev = alrm1;
                    664: 
                    665:                /*
                    666:                 * If a clock_sleep() alarm, wakeup the thread
                    667:                 * which issued the clock_sleep() call.
                    668:                 */
                    669:                if (alrm2->al_status == ALARM_SLEEP) {
                    670:                        alrm2->al_next = 0;
                    671:                        alrm2->al_status = ALARM_DONE;
                    672:                        alrm2->al_time = *clock_time;
                    673:                        thread_wakeup((event_t)alrm2);
                    674:                }
                    675: 
                    676:                /*
                    677:                 * If a clock_alarm() alarm, place the alarm on
                    678:                 * the alarm done list and schedule the alarm
                    679:                 * delivery mechanism.
                    680:                 */
                    681:                else {
                    682:                        assert(alrm2->al_status == ALARM_CLOCK);
                    683:                        if (alrm2->al_next = alrmdone)
                    684:                                alrmdone->al_prev = alrm2;
                    685:                        else
                    686:                                thread_call_enter(&alarm_deliver);
                    687:                        alrm2->al_prev = (alarm_t) &alrmdone;
                    688:                        alrmdone = alrm2;
                    689:                        alrm2->al_status = ALARM_DONE;
                    690:                        alrm2->al_time = *clock_time;
                    691:                }
                    692:        }
                    693: 
                    694:        /*
                    695:         * Setup the clock dependent layer to deliver another
                    696:         * interrupt for the next pending alarm.
                    697:         */
                    698:        if (alrm2)
                    699:                (*clock->cl_ops->c_setalrm)(alarm_time);
                    700:        UNLOCK_CLOCK(s);
                    701: }
                    702: 
                    703: /*
                    704:  * ALARM DELIVERY ROUTINES.
                    705:  */
                    706: 
                    707: static
                    708: void
                    709: clock_alarm_deliver(void)
                    710: {
                    711:        register alarm_t        alrm;
                    712:        kern_return_t           code;
                    713:        sched_policy_t          *policy;
                    714:        spl_t                           s;
                    715: 
                    716:        LOCK_CLOCK(s);
                    717:        while (alrm = alrmdone) {
                    718:                if (alrmdone = alrm->al_next)
                    719:                        alrmdone->al_prev = (alarm_t) &alrmdone;
                    720:                UNLOCK_CLOCK(s);
                    721: 
                    722:                code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED);
                    723:                if (alrm->al_port != IP_NULL) {
                    724:                        /* Deliver message to designated port */
                    725:                        if (IP_VALID(alrm->al_port)) {
                    726:                                clock_alarm_reply(alrm->al_port, alrm->al_port_type, code,
                    727:                                                                                                alrm->al_type, alrm->al_time);
                    728:                        }
                    729: 
                    730:                        LOCK_CLOCK(s);
                    731:                        alrm->al_status = ALARM_FREE;
                    732:                        alrm->al_next = alrmfree;
                    733:                        alrmfree = alrm;
                    734:                }
                    735:                else {
                    736:                        /* Call designated scheduling policy's alarm routine */
                    737:                        assert(alrm->al_policy != POLICY_NULL);
                    738:                        policy = &sched_policy[alrm->al_policy];
                    739:                        policy->sp_ops.sp_alarm_expired(policy, alrm->al_seqno, code,
                    740:                                                                alrm->al_type, alrm->al_time, alrm->al_data);
                    741: 
                    742:                        LOCK_CLOCK(s);
                    743:                }
                    744:        }
                    745: 
                    746:        UNLOCK_CLOCK(s);
                    747: }
                    748: 
                    749: /*
                    750:  * CLOCK PRIVATE SERVICING SUBROUTINES.
                    751:  */
                    752: 
                    753: /*
                    754:  * Flush all pending alarms on a clock. All alarms
                    755:  * are activated and timestamped correctly, so any
                    756:  * programs waiting on alarms/threads will proceed
                    757:  * with accurate information.
                    758:  */
                    759: static
                    760: void
                    761: flush_alarms(
                    762:        clock_t                         clock)
                    763: {
                    764:        register alarm_t        alrm1, alrm2;
                    765:        spl_t                           s;
                    766: 
                    767:        /*
                    768:         * Flush all outstanding alarms.
                    769:         */
                    770:        LOCK_CLOCK(s);
                    771:        alrm1 = (alarm_t) &clock->cl_alarm;
                    772:        while (alrm2 = alrm1->al_next) {
                    773:                /*
                    774:                 * Remove alarm from the clock alarm list.
                    775:                 */  
                    776:                if (alrm1->al_next = alrm2->al_next)
                    777:                        (alrm1->al_next)->al_prev = alrm1;
                    778: 
                    779:                /*
                    780:                 * If a clock_sleep() alarm, wakeup the thread
                    781:                 * which issued the clock_sleep() call.
                    782:                 */
                    783:                if (alrm2->al_status == ALARM_SLEEP) {
                    784:                        alrm2->al_next = 0;
                    785:                        thread_wakeup((event_t)alrm2);
                    786:                }
                    787:                else {
                    788:                        /*
                    789:                         * If a clock_alarm() alarm, place the alarm on
                    790:                         * the alarm done list and wakeup the dedicated
                    791:                         * kernel alarm_thread to service the alarm.
                    792:                         */
                    793:                        assert(alrm2->al_status == ALARM_CLOCK);
                    794:                        if (alrm2->al_next = alrmdone)
                    795:                                alrmdone->al_prev = alrm2;
                    796:                        else
                    797:                                thread_wakeup((event_t)&alrmdone);
                    798:                        alrm2->al_prev = (alarm_t) &alrmdone;
                    799:                        alrmdone = alrm2;
                    800:                }
                    801:        }
                    802:        UNLOCK_CLOCK(s);
                    803: }
                    804: 
                    805: /*
                    806:  * Post an alarm on a clock's active alarm list. The alarm is
                    807:  * inserted in time-order into the clock's active alarm list.
                    808:  * Always called from within a LOCK_CLOCK() code section.
                    809:  */
                    810: static
                    811: void
                    812: post_alarm(
                    813:        clock_t                         clock,
                    814:        alarm_t                         alarm)
                    815: {
                    816:        register alarm_t        alrm1, alrm2;
                    817:        mach_timespec_t         *alarm_time;
                    818:        mach_timespec_t         *queue_time;
                    819: 
                    820:        /*
                    821:         * Traverse alarm list until queue time is greater
                    822:         * than alarm time, then insert alarm.
                    823:         */
                    824:        alarm_time = &alarm->al_time;
                    825:        alrm1 = (alarm_t) &clock->cl_alarm;
                    826:        while (alrm2 = alrm1->al_next) {
                    827:                queue_time = &alrm2->al_time;
                    828:                if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0)
                    829:                        break;
                    830:                alrm1 = alrm2;
                    831:        }
                    832:        alrm1->al_next = alarm;
                    833:        alarm->al_next = alrm2;
                    834:        alarm->al_prev = alrm1;
                    835:        if (alrm2)
                    836:                alrm2->al_prev  = alarm;
                    837: 
                    838:        /*
                    839:         * If the inserted alarm is the 'earliest' alarm,
                    840:         * reset the device layer alarm time accordingly.
                    841:         */
                    842:        if (clock->cl_alarm.al_next == alarm)
                    843:                (*clock->cl_ops->c_setalrm)(alarm_time);
                    844: }
                    845: 
                    846: /*
                    847:  * Check the validity of 'alarm_time' and 'alarm_type'. If either
                    848:  * argument is invalid, return a negative value. If the 'alarm_time'
                    849:  * is now, return a 0 value. If the 'alarm_time' is in the future,
                    850:  * return a positive value.
                    851:  */
                    852: static
                    853: int
                    854: check_time(
                    855:        alarm_type_t            alarm_type,
                    856:        mach_timespec_t         *alarm_time,
                    857:        mach_timespec_t         *clock_time)
                    858: {
                    859:        int                                     result;
                    860: 
                    861:        if (BAD_ALRMTYPE(alarm_type))
                    862:                return (-1);
                    863:        if (BAD_MACH_TIMESPEC(alarm_time))
                    864:                return (-1);
                    865:        if ((alarm_type & ALRMTYPE) == TIME_RELATIVE)
                    866:                ADD_MACH_TIMESPEC(alarm_time, clock_time);
                    867: 
                    868:        result = CMP_MACH_TIMESPEC(alarm_time, clock_time);
                    869: 
                    870:        return ((result >= 0)? result: 0);
                    871: }
                    872: 
                    873: mach_timespec_t
                    874: clock_get_system_value(void)
                    875: {
                    876:        clock_t                         clock = &clock_list[SYSTEM_CLOCK];
                    877:        mach_timespec_t         value;
                    878: 
                    879:        (void) (*clock->cl_ops->c_gettime)(&value);
                    880: 
                    881:        return value;
                    882: }
                    883: 
                    884: mach_timespec_t
                    885: clock_get_calendar_value(void)
                    886: {
                    887:        clock_t                         clock = &clock_list[CALENDAR_CLOCK];
                    888:        mach_timespec_t         value = MACH_TIMESPEC_ZERO;
                    889: 
                    890:        (void) (*clock->cl_ops->c_gettime)(&value);
                    891: 
                    892:        return value;
                    893: }
                    894: 
                    895: void
                    896: clock_set_calendar_value(
                    897:        mach_timespec_t         value)
                    898: {
                    899:        clock_t                         clock = &clock_list[CALENDAR_CLOCK];
                    900: 
                    901:        (void) (*clock->cl_ops->c_settime)(&value);
                    902: }
                    903: 
                    904: void
                    905: clock_deadline_for_periodic_event(
                    906:        AbsoluteTime            interval,
                    907:        AbsoluteTime            abstime,
                    908:        AbsoluteTime            *deadline)
                    909: {
                    910:        assert(AbsoluteTime_to_scalar(&interval) != 0);
                    911: 
                    912:        ADD_ABSOLUTETIME(deadline, &interval);
                    913: 
                    914:        if (    AbsoluteTime_to_scalar(deadline)        <=
                    915:                        AbsoluteTime_to_scalar(&abstime)                ) {
                    916:                *deadline = abstime;
                    917:                clock_get_uptime(&abstime);
                    918:                ADD_ABSOLUTETIME(deadline, &interval);
                    919: 
                    920:                if (    AbsoluteTime_to_scalar(deadline)        <=
                    921:                                AbsoluteTime_to_scalar(&abstime)                ) {
                    922:                        *deadline = abstime;
                    923:                        ADD_ABSOLUTETIME(deadline, &interval);
                    924:                }
                    925:        }
                    926: }

unix.superglobalmegacorp.com

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