]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/clock_oldops.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / osfmk / kern / clock_oldops.c
CommitLineData
0c530ab8 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
0c530ab8 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
0c530ab8
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0c530ab8
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * DEPRECATED INTERFACES - Should be removed
33 *
34 * Purpose: Routines for the creation and use of kernel
35 * alarm clock services. This file and the ipc
36 * routines in kern/ipc_clock.c constitute the
37 * machine-independent clock service layer.
38 */
39
40#include <mach/mach_types.h>
41
0c530ab8
A
42#include <kern/host.h>
43#include <kern/spl.h>
44#include <kern/sched_prim.h>
45#include <kern/thread.h>
46#include <kern/ipc_host.h>
47#include <kern/clock.h>
48#include <kern/zalloc.h>
49
50#include <ipc/ipc_types.h>
51#include <ipc/ipc_port.h>
52
53#include <mach/mach_traps.h>
54#include <mach/mach_time.h>
55
56#include <mach/clock_server.h>
57#include <mach/clock_reply.h>
58#include <mach/clock_priv_server.h>
59
60#include <mach/mach_host_server.h>
61#include <mach/host_priv_server.h>
5ba3f43e 62#include <libkern/section_keywords.h>
0c530ab8
A
63
64/*
65 * Actual clock alarm structure. Used for user clock_sleep() and
66 * clock_alarm() calls. Alarms are allocated from the alarm free
67 * list and entered in time priority order into the active alarm
68 * chain of the target clock.
69 */
0a7de745
A
70struct alarm {
71 struct alarm *al_next; /* next alarm in chain */
72 struct alarm *al_prev; /* previous alarm in chain */
73 int al_status; /* alarm status */
74 mach_timespec_t al_time; /* alarm time */
75 struct { /* message alarm data */
76 int type; /* alarm type */
77 ipc_port_t port; /* alarm port */
0c530ab8 78 mach_msg_type_name_t
0a7de745
A
79 port_type; /* alarm port type */
80 struct clock *clock; /* alarm clock */
81 void *data; /* alarm data */
0c530ab8 82 } al_alrm;
0a7de745
A
83#define al_type al_alrm.type
84#define al_port al_alrm.port
85#define al_port_type al_alrm.port_type
86#define al_clock al_alrm.clock
87#define al_data al_alrm.data
88 long al_seqno; /* alarm sequence number */
0c530ab8 89};
0a7de745 90typedef struct alarm alarm_data_t;
0c530ab8
A
91
92/* alarm status */
0a7de745
A
93#define ALARM_FREE 0 /* alarm is on free list */
94#define ALARM_SLEEP 1 /* active clock_sleep() */
95#define ALARM_CLOCK 2 /* active clock_alarm() */
96#define ALARM_DONE 4 /* alarm has expired */
0c530ab8
A
97
98/* local data declarations */
cb323159 99decl_simple_lock_data(static, alarm_lock); /* alarm synchronization */
0a7de745
A
100static struct zone *alarm_zone; /* zone for user alarms */
101static struct alarm *alrmfree; /* alarm free list pointer */
102static struct alarm *alrmdone; /* alarm done list pointer */
103static struct alarm *alrmlist;
104static long alrm_seqno; /* uniquely identifies alarms */
105static thread_call_data_t alarm_done_call;
106static timer_call_data_t alarm_expire_timer;
0c530ab8 107
0a7de745
A
108extern struct clock clock_list[];
109extern int clock_count;
0c530ab8 110
0a7de745
A
111static void post_alarm(
112 alarm_t alarm);
0c530ab8 113
0a7de745
A
114static void set_alarm(
115 mach_timespec_t *alarm_time);
0c530ab8 116
0a7de745
A
117static int check_time(
118 alarm_type_t alarm_type,
119 mach_timespec_t *alarm_time,
120 mach_timespec_t *clock_time);
0c530ab8 121
0a7de745 122static void alarm_done(void);
0c530ab8 123
0a7de745 124static void alarm_expire(void);
0c530ab8 125
0a7de745
A
126static kern_return_t clock_sleep_internal(
127 clock_t clock,
128 sleep_type_t sleep_type,
129 mach_timespec_t *sleep_time);
0c530ab8 130
0a7de745 131int rtclock_init(void);
0c530ab8 132
0a7de745
A
133kern_return_t rtclock_gettime(
134 mach_timespec_t *cur_time);
0c530ab8 135
0a7de745
A
136kern_return_t rtclock_getattr(
137 clock_flavor_t flavor,
138 clock_attr_t attr,
139 mach_msg_type_number_t *count);
0c530ab8 140
5ba3f43e 141SECURITY_READ_ONLY_EARLY(struct clock_ops) sysclk_ops = {
cb323159
A
142 .c_config = NULL,
143 .c_init = rtclock_init,
144 .c_gettime = rtclock_gettime,
145 .c_getattr = rtclock_getattr,
0c530ab8
A
146};
147
0a7de745
A
148kern_return_t calend_gettime(
149 mach_timespec_t *cur_time);
0c530ab8 150
0a7de745
A
151kern_return_t calend_getattr(
152 clock_flavor_t flavor,
153 clock_attr_t attr,
154 mach_msg_type_number_t *count);
0c530ab8 155
5ba3f43e 156SECURITY_READ_ONLY_EARLY(struct clock_ops) calend_ops = {
cb323159
A
157 .c_config = NULL,
158 .c_init = NULL,
159 .c_gettime = calend_gettime,
160 .c_getattr = calend_getattr,
0c530ab8
A
161};
162
d9a64523
A
163/*
164 * List of clock devices.
165 */
cb323159
A
166SECURITY_READ_ONLY_LATE(struct clock) clock_list[] = {
167 [SYSTEM_CLOCK] = {
168 .cl_ops = &sysclk_ops,
169 .cl_service = IPC_PORT_NULL,
170 .cl_control = IPC_PORT_NULL,
171 },
172 [CALENDAR_CLOCK] = {
173 .cl_ops = &calend_ops,
174 .cl_service = IPC_PORT_NULL,
175 .cl_control = IPC_PORT_NULL,
176 },
d9a64523 177};
0a7de745 178int clock_count = sizeof(clock_list) / sizeof(clock_list[0]);
d9a64523 179
0c530ab8
A
180/*
181 * Macros to lock/unlock clock system.
182 */
0a7de745
A
183#define LOCK_ALARM(s) \
184 s = splclock(); \
185 simple_lock(&alarm_lock, LCK_GRP_NULL);
0c530ab8 186
0a7de745
A
187#define UNLOCK_ALARM(s) \
188 simple_unlock(&alarm_lock); \
0c530ab8
A
189 splx(s);
190
191void
192clock_oldconfig(void)
193{
0a7de745
A
194 clock_t clock;
195 int i;
0c530ab8
A
196
197 simple_lock_init(&alarm_lock, 0);
198 thread_call_setup(&alarm_done_call, (thread_call_func_t)alarm_done, NULL);
199 timer_call_setup(&alarm_expire_timer, (timer_call_func_t)alarm_expire, NULL);
200
201 /*
202 * Configure clock devices.
203 */
204 for (i = 0; i < clock_count; i++) {
205 clock = &clock_list[i];
206 if (clock->cl_ops && clock->cl_ops->c_config) {
0a7de745 207 if ((*clock->cl_ops->c_config)() == 0) {
2d21ac55 208 clock->cl_ops = NULL;
0a7de745 209 }
0c530ab8
A
210 }
211 }
212
213 /* start alarm sequence numbers at 0 */
214 alrm_seqno = 0;
215}
216
217void
218clock_oldinit(void)
219{
0a7de745
A
220 clock_t clock;
221 int i;
0c530ab8
A
222
223 /*
224 * Initialize basic clock structures.
225 */
226 for (i = 0; i < clock_count; i++) {
227 clock = &clock_list[i];
0a7de745 228 if (clock->cl_ops && clock->cl_ops->c_init) {
0c530ab8 229 (*clock->cl_ops->c_init)();
0a7de745 230 }
0c530ab8
A
231 }
232}
233
234/*
235 * Initialize the clock ipc service facility.
236 */
237void
238clock_service_create(void)
239{
0a7de745
A
240 clock_t clock;
241 int i;
0c530ab8
A
242
243 /*
244 * Initialize ipc clock services.
245 */
246 for (i = 0; i < clock_count; i++) {
247 clock = &clock_list[i];
248 if (clock->cl_ops) {
249 ipc_clock_init(clock);
250 ipc_clock_enable(clock);
251 }
252 }
253
254 /*
255 * Perform miscellaneous late
256 * initialization.
257 */
258 i = sizeof(struct alarm);
0a7de745 259 alarm_zone = zinit(i, (4096 / i) * i, 10 * i, "alarms");
0c530ab8
A
260}
261
262/*
263 * Get the service port on a clock.
264 */
265kern_return_t
266host_get_clock_service(
0a7de745
A
267 host_t host,
268 clock_id_t clock_id,
269 clock_t *clock) /* OUT */
0c530ab8
A
270{
271 if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
272 *clock = CLOCK_NULL;
0a7de745 273 return KERN_INVALID_ARGUMENT;
0c530ab8
A
274 }
275
276 *clock = &clock_list[clock_id];
0a7de745
A
277 if ((*clock)->cl_ops == 0) {
278 return KERN_FAILURE;
279 }
280 return KERN_SUCCESS;
0c530ab8
A
281}
282
283/*
284 * Get the control port on a clock.
285 */
286kern_return_t
287host_get_clock_control(
0a7de745
A
288 host_priv_t host_priv,
289 clock_id_t clock_id,
290 clock_t *clock) /* OUT */
0c530ab8
A
291{
292 if (host_priv == HOST_PRIV_NULL ||
0a7de745 293 clock_id < 0 || clock_id >= clock_count) {
0c530ab8 294 *clock = CLOCK_NULL;
0a7de745 295 return KERN_INVALID_ARGUMENT;
0c530ab8
A
296 }
297
298 *clock = &clock_list[clock_id];
0a7de745
A
299 if ((*clock)->cl_ops == 0) {
300 return KERN_FAILURE;
301 }
302 return KERN_SUCCESS;
0c530ab8
A
303}
304
305/*
306 * Get the current clock time.
307 */
308kern_return_t
309clock_get_time(
0a7de745
A
310 clock_t clock,
311 mach_timespec_t *cur_time) /* OUT */
0c530ab8 312{
0a7de745
A
313 if (clock == CLOCK_NULL) {
314 return KERN_INVALID_ARGUMENT;
315 }
316 return (*clock->cl_ops->c_gettime)(cur_time);
0c530ab8
A
317}
318
319kern_return_t
320rtclock_gettime(
0a7de745 321 mach_timespec_t *time) /* OUT */
0c530ab8 322{
0a7de745
A
323 clock_sec_t secs;
324 clock_nsec_t nsecs;
b0d623f7
A
325
326 clock_get_system_nanotime(&secs, &nsecs);
327 time->tv_sec = (unsigned int)secs;
328 time->tv_nsec = nsecs;
0c530ab8 329
0a7de745 330 return KERN_SUCCESS;
0c530ab8
A
331}
332
333kern_return_t
334calend_gettime(
0a7de745 335 mach_timespec_t *time) /* OUT */
0c530ab8 336{
0a7de745
A
337 clock_sec_t secs;
338 clock_nsec_t nsecs;
b0d623f7
A
339
340 clock_get_calendar_nanotime(&secs, &nsecs);
341 time->tv_sec = (unsigned int)secs;
342 time->tv_nsec = nsecs;
0c530ab8 343
0a7de745 344 return KERN_SUCCESS;
0c530ab8
A
345}
346
347/*
348 * Get clock attributes.
349 */
350kern_return_t
351clock_get_attributes(
0a7de745
A
352 clock_t clock,
353 clock_flavor_t flavor,
354 clock_attr_t attr, /* OUT */
355 mach_msg_type_number_t *count) /* IN/OUT */
0c530ab8 356{
0a7de745
A
357 if (clock == CLOCK_NULL) {
358 return KERN_INVALID_ARGUMENT;
359 }
360 if (clock->cl_ops->c_getattr) {
361 return clock->cl_ops->c_getattr(flavor, attr, count);
362 }
363 return KERN_FAILURE;
0c530ab8
A
364}
365
366kern_return_t
367rtclock_getattr(
0a7de745
A
368 clock_flavor_t flavor,
369 clock_attr_t attr, /* OUT */
370 mach_msg_type_number_t *count) /* IN/OUT */
0c530ab8 371{
0a7de745
A
372 if (*count != 1) {
373 return KERN_FAILURE;
374 }
0c530ab8
A
375
376 switch (flavor) {
0a7de745
A
377 case CLOCK_GET_TIME_RES: /* >0 res */
378 case CLOCK_ALARM_CURRES: /* =0 no alarm */
0c530ab8
A
379 case CLOCK_ALARM_MINRES:
380 case CLOCK_ALARM_MAXRES:
381 *(clock_res_t *) attr = NSEC_PER_SEC / 100;
382 break;
383
384 default:
0a7de745 385 return KERN_INVALID_VALUE;
0c530ab8
A
386 }
387
0a7de745 388 return KERN_SUCCESS;
0c530ab8
A
389}
390
391kern_return_t
392calend_getattr(
0a7de745
A
393 clock_flavor_t flavor,
394 clock_attr_t attr, /* OUT */
395 mach_msg_type_number_t *count) /* IN/OUT */
0c530ab8 396{
0a7de745
A
397 if (*count != 1) {
398 return KERN_FAILURE;
399 }
0c530ab8
A
400
401 switch (flavor) {
0a7de745 402 case CLOCK_GET_TIME_RES: /* >0 res */
0c530ab8
A
403 *(clock_res_t *) attr = NSEC_PER_SEC / 100;
404 break;
405
0a7de745 406 case CLOCK_ALARM_CURRES: /* =0 no alarm */
0c530ab8
A
407 case CLOCK_ALARM_MINRES:
408 case CLOCK_ALARM_MAXRES:
409 *(clock_res_t *) attr = 0;
410 break;
411
412 default:
0a7de745 413 return KERN_INVALID_VALUE;
0c530ab8
A
414 }
415
0a7de745 416 return KERN_SUCCESS;
0c530ab8
A
417}
418
419/*
420 * Set the current clock time.
421 */
422kern_return_t
423clock_set_time(
0a7de745
A
424 clock_t clock,
425 __unused mach_timespec_t new_time)
0c530ab8 426{
0a7de745
A
427 if (clock == CLOCK_NULL) {
428 return KERN_INVALID_ARGUMENT;
429 }
430 return KERN_FAILURE;
0c530ab8
A
431}
432
433/*
434 * Set the clock alarm resolution.
435 */
436kern_return_t
437clock_set_attributes(
0a7de745
A
438 clock_t clock,
439 __unused clock_flavor_t flavor,
440 __unused clock_attr_t attr,
441 __unused mach_msg_type_number_t count)
0c530ab8 442{
0a7de745
A
443 if (clock == CLOCK_NULL) {
444 return KERN_INVALID_ARGUMENT;
445 }
446 return KERN_FAILURE;
0c530ab8
A
447}
448
449/*
450 * Setup a clock alarm.
451 */
452kern_return_t
453clock_alarm(
0a7de745
A
454 clock_t clock,
455 alarm_type_t alarm_type,
456 mach_timespec_t alarm_time,
457 ipc_port_t alarm_port,
458 mach_msg_type_name_t alarm_port_type)
0c530ab8 459{
0a7de745
A
460 alarm_t alarm;
461 mach_timespec_t clock_time;
462 int chkstat;
463 kern_return_t reply_code;
464 spl_t s;
465
466 if (clock == CLOCK_NULL) {
467 return KERN_INVALID_ARGUMENT;
468 }
469 if (clock != &clock_list[SYSTEM_CLOCK]) {
470 return KERN_FAILURE;
471 }
472 if (IP_VALID(alarm_port) == 0) {
473 return KERN_INVALID_CAPABILITY;
474 }
0c530ab8
A
475
476 /*
477 * Check alarm parameters. If parameters are invalid,
478 * send alarm message immediately.
479 */
480 (*clock->cl_ops->c_gettime)(&clock_time);
481 chkstat = check_time(alarm_type, &alarm_time, &clock_time);
482 if (chkstat <= 0) {
483 reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS);
484 clock_alarm_reply(alarm_port, alarm_port_type,
0a7de745
A
485 reply_code, alarm_type, clock_time);
486 return KERN_SUCCESS;
0c530ab8
A
487 }
488
489 /*
490 * Get alarm and add to clock alarm list.
491 */
492
493 LOCK_ALARM(s);
494 if ((alarm = alrmfree) == 0) {
495 UNLOCK_ALARM(s);
496 alarm = (alarm_t) zalloc(alarm_zone);
0a7de745
A
497 if (alarm == 0) {
498 return KERN_RESOURCE_SHORTAGE;
499 }
0c530ab8 500 LOCK_ALARM(s);
0a7de745 501 } else {
0c530ab8 502 alrmfree = alarm->al_next;
0a7de745 503 }
0c530ab8
A
504
505 alarm->al_status = ALARM_CLOCK;
506 alarm->al_time = alarm_time;
507 alarm->al_type = alarm_type;
508 alarm->al_port = alarm_port;
509 alarm->al_port_type = alarm_port_type;
510 alarm->al_clock = clock;
511 alarm->al_seqno = alrm_seqno++;
512 post_alarm(alarm);
513 UNLOCK_ALARM(s);
514
0a7de745 515 return KERN_SUCCESS;
0c530ab8
A
516}
517
518/*
519 * Sleep on a clock. System trap. User-level libmach clock_sleep
520 * interface call takes a mach_timespec_t sleep_time argument which it
521 * converts to sleep_sec and sleep_nsec arguments which are then
522 * passed to clock_sleep_trap.
523 */
524kern_return_t
525clock_sleep_trap(
526 struct clock_sleep_trap_args *args)
527{
0a7de745
A
528 mach_port_name_t clock_name = args->clock_name;
529 sleep_type_t sleep_type = args->sleep_type;
530 int sleep_sec = args->sleep_sec;
531 int sleep_nsec = args->sleep_nsec;
532 mach_vm_address_t wakeup_time_addr = args->wakeup_time;
533 clock_t clock;
534 mach_timespec_t swtime = {};
535 kern_return_t rvalue;
0c530ab8
A
536
537 /*
538 * Convert the trap parameters.
539 */
0a7de745 540 if (clock_name == MACH_PORT_NULL) {
0c530ab8 541 clock = &clock_list[SYSTEM_CLOCK];
0a7de745 542 } else {
0c530ab8 543 clock = port_name_to_clock(clock_name);
0a7de745 544 }
0c530ab8
A
545
546 swtime.tv_sec = sleep_sec;
547 swtime.tv_nsec = sleep_nsec;
548
549 /*
550 * Call the actual clock_sleep routine.
551 */
552 rvalue = clock_sleep_internal(clock, sleep_type, &swtime);
553
554 /*
555 * Return current time as wakeup time.
556 */
557 if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) {
558 copyout((char *)&swtime, wakeup_time_addr, sizeof(mach_timespec_t));
559 }
0a7de745
A
560 return rvalue;
561}
0c530ab8
A
562
563static kern_return_t
564clock_sleep_internal(
0a7de745
A
565 clock_t clock,
566 sleep_type_t sleep_type,
567 mach_timespec_t *sleep_time)
0c530ab8 568{
0a7de745
A
569 alarm_t alarm;
570 mach_timespec_t clock_time;
571 kern_return_t rvalue;
572 int chkstat;
573 spl_t s;
574
575 if (clock == CLOCK_NULL) {
576 return KERN_INVALID_ARGUMENT;
577 }
0c530ab8 578
0a7de745
A
579 if (clock != &clock_list[SYSTEM_CLOCK]) {
580 return KERN_FAILURE;
581 }
0c530ab8
A
582
583 /*
584 * Check sleep parameters. If parameters are invalid
585 * return an error, otherwise post alarm request.
586 */
587 (*clock->cl_ops->c_gettime)(&clock_time);
588
589 chkstat = check_time(sleep_type, sleep_time, &clock_time);
0a7de745
A
590 if (chkstat < 0) {
591 return KERN_INVALID_VALUE;
592 }
0c530ab8
A
593 rvalue = KERN_SUCCESS;
594 if (chkstat > 0) {
595 wait_result_t wait_result;
596
597 /*
598 * Get alarm and add to clock alarm list.
599 */
600
601 LOCK_ALARM(s);
602 if ((alarm = alrmfree) == 0) {
603 UNLOCK_ALARM(s);
604 alarm = (alarm_t) zalloc(alarm_zone);
0a7de745
A
605 if (alarm == 0) {
606 return KERN_RESOURCE_SHORTAGE;
607 }
0c530ab8 608 LOCK_ALARM(s);
0a7de745 609 } else {
0c530ab8 610 alrmfree = alarm->al_next;
0a7de745 611 }
0c530ab8
A
612
613 /*
614 * Wait for alarm to occur.
615 */
616 wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE);
617 if (wait_result == THREAD_WAITING) {
618 alarm->al_time = *sleep_time;
619 alarm->al_status = ALARM_SLEEP;
620 post_alarm(alarm);
621 UNLOCK_ALARM(s);
622
623 wait_result = thread_block(THREAD_CONTINUE_NULL);
624
625 /*
626 * Note if alarm expired normally or whether it
627 * was aborted. If aborted, delete alarm from
628 * clock alarm list. Return alarm to free list.
629 */
630 LOCK_ALARM(s);
631 if (alarm->al_status != ALARM_DONE) {
632 assert(wait_result != THREAD_AWAKENED);
0a7de745 633 if (((alarm->al_prev)->al_next = alarm->al_next) != NULL) {
0c530ab8 634 (alarm->al_next)->al_prev = alarm->al_prev;
0a7de745 635 }
0c530ab8
A
636 rvalue = KERN_ABORTED;
637 }
638 *sleep_time = alarm->al_time;
639 alarm->al_status = ALARM_FREE;
640 } else {
641 assert(wait_result == THREAD_INTERRUPTED);
642 assert(alarm->al_status == ALARM_FREE);
643 rvalue = KERN_ABORTED;
644 }
645 alarm->al_next = alrmfree;
646 alrmfree = alarm;
647 UNLOCK_ALARM(s);
0a7de745 648 } else {
0c530ab8 649 *sleep_time = clock_time;
0a7de745 650 }
0c530ab8 651
0a7de745 652 return rvalue;
0c530ab8
A
653}
654
655/*
656 * Service clock alarm expirations.
657 */
658static void
659alarm_expire(void)
660{
0a7de745
A
661 clock_t clock;
662 alarm_t alrm1;
663 alarm_t alrm2;
664 mach_timespec_t clock_time;
665 mach_timespec_t *alarm_time;
666 spl_t s;
0c530ab8
A
667
668 clock = &clock_list[SYSTEM_CLOCK];
669 (*clock->cl_ops->c_gettime)(&clock_time);
670
671 /*
672 * Update clock alarm list. Alarms that are due are moved
673 * to the alarmdone list to be serviced by a thread callout.
674 */
675 LOCK_ALARM(s);
676 alrm1 = (alarm_t)&alrmlist;
677 while ((alrm2 = alrm1->al_next) != NULL) {
678 alarm_time = &alrm2->al_time;
0a7de745 679 if (CMP_MACH_TIMESPEC(alarm_time, &clock_time) > 0) {
0c530ab8 680 break;
0a7de745 681 }
0c530ab8
A
682
683 /*
684 * Alarm has expired, so remove it from the
685 * clock alarm list.
0a7de745
A
686 */
687 if ((alrm1->al_next = alrm2->al_next) != NULL) {
0c530ab8 688 (alrm1->al_next)->al_prev = alrm1;
0a7de745 689 }
0c530ab8
A
690
691 /*
692 * If a clock_sleep() alarm, wakeup the thread
693 * which issued the clock_sleep() call.
694 */
695 if (alrm2->al_status == ALARM_SLEEP) {
2d21ac55 696 alrm2->al_next = NULL;
0c530ab8
A
697 alrm2->al_status = ALARM_DONE;
698 alrm2->al_time = clock_time;
699 thread_wakeup((event_t)alrm2);
700 }
0a7de745 701 /*
0c530ab8
A
702 * If a clock_alarm() alarm, place the alarm on
703 * the alarm done list and schedule the alarm
704 * delivery mechanism.
705 */
706 else {
707 assert(alrm2->al_status == ALARM_CLOCK);
0a7de745 708 if ((alrm2->al_next = alrmdone) != NULL) {
0c530ab8 709 alrmdone->al_prev = alrm2;
0a7de745 710 } else {
0c530ab8 711 thread_call_enter(&alarm_done_call);
0a7de745 712 }
0c530ab8
A
713 alrm2->al_prev = (alarm_t)&alrmdone;
714 alrmdone = alrm2;
715 alrm2->al_status = ALARM_DONE;
716 alrm2->al_time = clock_time;
717 }
718 }
719
720 /*
721 * Setup to expire for the next pending alarm.
722 */
0a7de745 723 if (alrm2) {
0c530ab8 724 set_alarm(alarm_time);
0a7de745 725 }
0c530ab8
A
726 UNLOCK_ALARM(s);
727}
728
729static void
730alarm_done(void)
731{
0a7de745
A
732 alarm_t alrm;
733 kern_return_t code;
734 spl_t s;
0c530ab8
A
735
736 LOCK_ALARM(s);
737 while ((alrm = alrmdone) != NULL) {
0a7de745 738 if ((alrmdone = alrm->al_next) != NULL) {
0c530ab8 739 alrmdone->al_prev = (alarm_t)&alrmdone;
0a7de745 740 }
0c530ab8
A
741 UNLOCK_ALARM(s);
742
743 code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED);
744 if (alrm->al_port != IP_NULL) {
745 /* Deliver message to designated port */
746 if (IP_VALID(alrm->al_port)) {
747 clock_alarm_reply(alrm->al_port, alrm->al_port_type, code,
0a7de745 748 alrm->al_type, alrm->al_time);
0c530ab8
A
749 }
750
751 LOCK_ALARM(s);
752 alrm->al_status = ALARM_FREE;
753 alrm->al_next = alrmfree;
754 alrmfree = alrm;
0a7de745 755 } else {
0c530ab8 756 panic("clock_alarm_deliver");
0a7de745 757 }
0c530ab8
A
758 }
759
760 UNLOCK_ALARM(s);
761}
762
763/*
764 * Post an alarm on the active alarm list.
765 *
766 * Always called from within a LOCK_ALARM() code section.
767 */
768static void
769post_alarm(
0a7de745 770 alarm_t alarm)
0c530ab8 771{
0a7de745
A
772 alarm_t alrm1, alrm2;
773 mach_timespec_t *alarm_time;
774 mach_timespec_t *queue_time;
0c530ab8
A
775
776 /*
777 * Traverse alarm list until queue time is greater
778 * than alarm time, then insert alarm.
779 */
780 alarm_time = &alarm->al_time;
781 alrm1 = (alarm_t)&alrmlist;
782 while ((alrm2 = alrm1->al_next) != NULL) {
783 queue_time = &alrm2->al_time;
0a7de745 784 if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0) {
0c530ab8 785 break;
0a7de745 786 }
0c530ab8
A
787 alrm1 = alrm2;
788 }
789 alrm1->al_next = alarm;
790 alarm->al_next = alrm2;
791 alarm->al_prev = alrm1;
0a7de745 792 if (alrm2) {
0c530ab8 793 alrm2->al_prev = alarm;
0a7de745 794 }
0c530ab8
A
795
796 /*
797 * If the inserted alarm is the 'earliest' alarm,
798 * reset the device layer alarm time accordingly.
799 */
0a7de745 800 if (alrmlist == alarm) {
0c530ab8 801 set_alarm(alarm_time);
0a7de745 802 }
0c530ab8
A
803}
804
805static void
806set_alarm(
0a7de745 807 mach_timespec_t *alarm_time)
0c530ab8 808{
0a7de745 809 uint64_t abstime;
0c530ab8
A
810
811 nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime);
39236c6e 812 timer_call_enter_with_leeway(&alarm_expire_timer, NULL, abstime, 0, TIMER_CALL_USER_NORMAL, FALSE);
0c530ab8
A
813}
814
815/*
816 * Check the validity of 'alarm_time' and 'alarm_type'. If either
817 * argument is invalid, return a negative value. If the 'alarm_time'
818 * is now, return a 0 value. If the 'alarm_time' is in the future,
819 * return a positive value.
820 */
821static int
822check_time(
0a7de745
A
823 alarm_type_t alarm_type,
824 mach_timespec_t *alarm_time,
825 mach_timespec_t *clock_time)
0c530ab8 826{
0a7de745 827 int result;
0c530ab8 828
0a7de745
A
829 if (BAD_ALRMTYPE(alarm_type)) {
830 return -1;
831 }
832 if (BAD_MACH_TIMESPEC(alarm_time)) {
833 return -1;
834 }
835 if ((alarm_type & ALRMTYPE) == TIME_RELATIVE) {
0c530ab8 836 ADD_MACH_TIMESPEC(alarm_time, clock_time);
0a7de745 837 }
0c530ab8
A
838
839 result = CMP_MACH_TIMESPEC(alarm_time, clock_time);
840
0a7de745 841 return (result >= 0)? result: 0;
0c530ab8
A
842}
843
0a7de745 844#ifndef __LP64__
b0d623f7 845
0c530ab8
A
846mach_timespec_t
847clock_get_system_value(void)
848{
0a7de745
A
849 clock_t clock = &clock_list[SYSTEM_CLOCK];
850 mach_timespec_t value;
0c530ab8
A
851
852 (void) (*clock->cl_ops->c_gettime)(&value);
853
854 return value;
855}
856
857mach_timespec_t
858clock_get_calendar_value(void)
859{
0a7de745
A
860 clock_t clock = &clock_list[CALENDAR_CLOCK];
861 mach_timespec_t value = MACH_TIMESPEC_ZERO;
0c530ab8
A
862
863 (void) (*clock->cl_ops->c_gettime)(&value);
864
865 return value;
866}
b0d623f7 867
0a7de745 868#endif /* __LP64__ */