Annotation of XNU/osfmk/kern/clock.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_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.