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