|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.