/ duct-tape / xnu / osfmk / kern / clock_oldops.c
clock_oldops.c
  1  /*
  2   * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  3   *
  4   * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  5   *
  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.
 14   *
 15   * Please obtain a copy of the License at
 16   * http://www.opensource.apple.com/apsl/ and read it before using this file.
 17   *
 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
 20   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 21   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 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.
 25   *
 26   * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 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  
 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>
 62  #include <libkern/section_keywords.h>
 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   */
 70  struct  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 */
 78  		mach_msg_type_name_t
 79  		    port_type;                                  /* alarm port type */
 80  		struct  clock   *clock;         /* alarm clock */
 81  		void                    *data;          /* alarm data */
 82  	} al_alrm;
 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 */
 89  };
 90  typedef struct alarm    alarm_data_t;
 91  
 92  /* alarm status */
 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 */
 97  
 98  /* local data declarations */
 99  decl_simple_lock_data(static, alarm_lock);       /* alarm synchronization */
100  /* zone for user alarms */
101  static ZONE_DECLARE(alarm_zone, "alarms", sizeof(struct alarm), ZC_NONE);
102  static struct   alarm           *alrmfree;              /* alarm free list pointer */
103  static struct   alarm           *alrmdone;              /* alarm done list pointer */
104  static struct   alarm           *alrmlist;
105  static long                     alrm_seqno;             /* uniquely identifies alarms */
106  static thread_call_data_t       alarm_done_call;
107  static timer_call_data_t        alarm_expire_timer;
108  
109  extern  struct clock    clock_list[];
110  extern  int             clock_count;
111  
112  static void             post_alarm(
113  	alarm_t                 alarm);
114  
115  static void             set_alarm(
116  	mach_timespec_t *alarm_time);
117  
118  static int              check_time(
119  	alarm_type_t    alarm_type,
120  	mach_timespec_t *alarm_time,
121  	mach_timespec_t *clock_time);
122  
123  static void             alarm_done(void);
124  
125  static void             alarm_expire(void);
126  
127  static kern_return_t    clock_sleep_internal(
128  	clock_t                         clock,
129  	sleep_type_t            sleep_type,
130  	mach_timespec_t         *sleep_time);
131  
132  int             rtclock_init(void);
133  
134  kern_return_t   rtclock_gettime(
135  	mach_timespec_t                 *cur_time);
136  
137  kern_return_t   rtclock_getattr(
138  	clock_flavor_t                  flavor,
139  	clock_attr_t                    attr,
140  	mach_msg_type_number_t  *count);
141  
142  SECURITY_READ_ONLY_EARLY(struct clock_ops) sysclk_ops = {
143  	.c_config   = NULL,
144  	.c_init     = rtclock_init,
145  	.c_gettime  = rtclock_gettime,
146  	.c_getattr  = rtclock_getattr,
147  };
148  
149  kern_return_t   calend_gettime(
150  	mach_timespec_t                 *cur_time);
151  
152  kern_return_t   calend_getattr(
153  	clock_flavor_t                  flavor,
154  	clock_attr_t                    attr,
155  	mach_msg_type_number_t  *count);
156  
157  SECURITY_READ_ONLY_EARLY(struct clock_ops) calend_ops = {
158  	.c_config   = NULL,
159  	.c_init     = NULL,
160  	.c_gettime  = calend_gettime,
161  	.c_getattr  = calend_getattr,
162  };
163  
164  /*
165   * List of clock devices.
166   */
167  SECURITY_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  	},
178  };
179  int     clock_count = sizeof(clock_list) / sizeof(clock_list[0]);
180  
181  /*
182   *	Macros to lock/unlock clock system.
183   */
184  #define LOCK_ALARM(s)                   \
185  	s = splclock();                 \
186  	simple_lock(&alarm_lock, LCK_GRP_NULL);
187  
188  #define UNLOCK_ALARM(s)                 \
189  	simple_unlock(&alarm_lock);     \
190  	splx(s);
191  
192  void
193  clock_oldconfig(void)
194  {
195  	clock_t                 clock;
196  	int     i;
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) {
208  			if ((*clock->cl_ops->c_config)() == 0) {
209  				clock->cl_ops = NULL;
210  			}
211  		}
212  	}
213  
214  	/* start alarm sequence numbers at 0 */
215  	alrm_seqno = 0;
216  }
217  
218  void
219  clock_oldinit(void)
220  {
221  	clock_t                 clock;
222  	int     i;
223  
224  	/*
225  	 * Initialize basic clock structures.
226  	 */
227  	for (i = 0; i < clock_count; i++) {
228  		clock = &clock_list[i];
229  		if (clock->cl_ops && clock->cl_ops->c_init) {
230  			(*clock->cl_ops->c_init)();
231  		}
232  	}
233  }
234  
235  /*
236   * Initialize the clock ipc service facility.
237   */
238  void
239  clock_service_create(void)
240  {
241  	/*
242  	 * Initialize ipc clock services.
243  	 */
244  	for (int i = 0; i < clock_count; i++) {
245  		clock_t clock = &clock_list[i];
246  		if (clock->cl_ops) {
247  			ipc_clock_init(clock);
248  			ipc_clock_enable(clock);
249  		}
250  	}
251  }
252  
253  /*
254   * Get the service port on a clock.
255   */
256  kern_return_t
257  host_get_clock_service(
258  	host_t                  host,
259  	clock_id_t              clock_id,
260  	clock_t                 *clock)         /* OUT */
261  {
262  	if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
263  		*clock = CLOCK_NULL;
264  		return KERN_INVALID_ARGUMENT;
265  	}
266  
267  	*clock = &clock_list[clock_id];
268  	if ((*clock)->cl_ops == 0) {
269  		return KERN_FAILURE;
270  	}
271  	return KERN_SUCCESS;
272  }
273  
274  /*
275   * Get the control port on a clock.
276   */
277  kern_return_t
278  host_get_clock_control(
279  	host_priv_t             host_priv,
280  	clock_id_t              clock_id,
281  	clock_t                 *clock)         /* OUT */
282  {
283  	if (host_priv == HOST_PRIV_NULL ||
284  	    clock_id < 0 || clock_id >= clock_count) {
285  		*clock = CLOCK_NULL;
286  		return KERN_INVALID_ARGUMENT;
287  	}
288  
289  	*clock = &clock_list[clock_id];
290  	if ((*clock)->cl_ops == 0) {
291  		return KERN_FAILURE;
292  	}
293  	return KERN_SUCCESS;
294  }
295  
296  /*
297   * Get the current clock time.
298   */
299  kern_return_t
300  clock_get_time(
301  	clock_t                 clock,
302  	mach_timespec_t *cur_time)      /* OUT */
303  {
304  	if (clock == CLOCK_NULL) {
305  		return KERN_INVALID_ARGUMENT;
306  	}
307  	return (*clock->cl_ops->c_gettime)(cur_time);
308  }
309  
310  kern_return_t
311  rtclock_gettime(
312  	mach_timespec_t         *time)  /* OUT */
313  {
314  	clock_sec_t             secs;
315  	clock_nsec_t    nsecs;
316  
317  	clock_get_system_nanotime(&secs, &nsecs);
318  	time->tv_sec = (unsigned int)secs;
319  	time->tv_nsec = nsecs;
320  
321  	return KERN_SUCCESS;
322  }
323  
324  kern_return_t
325  calend_gettime(
326  	mach_timespec_t         *time)  /* OUT */
327  {
328  	clock_sec_t             secs;
329  	clock_nsec_t    nsecs;
330  
331  	clock_get_calendar_nanotime(&secs, &nsecs);
332  	time->tv_sec = (unsigned int)secs;
333  	time->tv_nsec = nsecs;
334  
335  	return KERN_SUCCESS;
336  }
337  
338  /*
339   * Get clock attributes.
340   */
341  kern_return_t
342  clock_get_attributes(
343  	clock_t                                 clock,
344  	clock_flavor_t                  flavor,
345  	clock_attr_t                    attr,           /* OUT */
346  	mach_msg_type_number_t  *count)         /* IN/OUT */
347  {
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;
355  }
356  
357  kern_return_t
358  rtclock_getattr(
359  	clock_flavor_t                  flavor,
360  	clock_attr_t                    attr,           /* OUT */
361  	mach_msg_type_number_t  *count)         /* IN/OUT */
362  {
363  	if (*count != 1) {
364  		return KERN_FAILURE;
365  	}
366  
367  	switch (flavor) {
368  	case CLOCK_GET_TIME_RES:        /* >0 res */
369  	case CLOCK_ALARM_CURRES:        /* =0 no alarm */
370  	case CLOCK_ALARM_MINRES:
371  	case CLOCK_ALARM_MAXRES:
372  		*(clock_res_t *) attr = NSEC_PER_SEC / 100;
373  		break;
374  
375  	default:
376  		return KERN_INVALID_VALUE;
377  	}
378  
379  	return KERN_SUCCESS;
380  }
381  
382  kern_return_t
383  calend_getattr(
384  	clock_flavor_t                  flavor,
385  	clock_attr_t                    attr,           /* OUT */
386  	mach_msg_type_number_t  *count)         /* IN/OUT */
387  {
388  	if (*count != 1) {
389  		return KERN_FAILURE;
390  	}
391  
392  	switch (flavor) {
393  	case CLOCK_GET_TIME_RES:        /* >0 res */
394  		*(clock_res_t *) attr = NSEC_PER_SEC / 100;
395  		break;
396  
397  	case CLOCK_ALARM_CURRES:        /* =0 no alarm */
398  	case CLOCK_ALARM_MINRES:
399  	case CLOCK_ALARM_MAXRES:
400  		*(clock_res_t *) attr = 0;
401  		break;
402  
403  	default:
404  		return KERN_INVALID_VALUE;
405  	}
406  
407  	return KERN_SUCCESS;
408  }
409  
410  /*
411   * Set the current clock time.
412   */
413  kern_return_t
414  clock_set_time(
415  	clock_t                                 clock,
416  	__unused mach_timespec_t        new_time)
417  {
418  	if (clock == CLOCK_NULL) {
419  		return KERN_INVALID_ARGUMENT;
420  	}
421  	return KERN_FAILURE;
422  }
423  
424  /*
425   * Set the clock alarm resolution.
426   */
427  kern_return_t
428  clock_set_attributes(
429  	clock_t                                         clock,
430  	__unused clock_flavor_t                 flavor,
431  	__unused clock_attr_t                   attr,
432  	__unused mach_msg_type_number_t count)
433  {
434  	if (clock == CLOCK_NULL) {
435  		return KERN_INVALID_ARGUMENT;
436  	}
437  	return KERN_FAILURE;
438  }
439  
440  /*
441   * Setup a clock alarm.
442   */
443  kern_return_t
444  clock_alarm(
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)
450  {
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  	}
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,
476  		    reply_code, alarm_type, clock_time);
477  		return KERN_SUCCESS;
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);
488  		if (alarm == 0) {
489  			return KERN_RESOURCE_SHORTAGE;
490  		}
491  		LOCK_ALARM(s);
492  	} else {
493  		alrmfree = alarm->al_next;
494  	}
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  
506  	return KERN_SUCCESS;
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   */
515  kern_return_t
516  clock_sleep_trap(
517  	struct clock_sleep_trap_args *args)
518  {
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;
527  
528  	/*
529  	 * Convert the trap parameters.
530  	 */
531  	if (clock_name == MACH_PORT_NULL) {
532  		clock = &clock_list[SYSTEM_CLOCK];
533  	} else {
534  		clock = port_name_to_clock(clock_name);
535  	}
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  	}
551  	return rvalue;
552  }
553  
554  static kern_return_t
555  clock_sleep_internal(
556  	clock_t                         clock,
557  	sleep_type_t            sleep_type,
558  	mach_timespec_t         *sleep_time)
559  {
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  	}
569  
570  	if (clock != &clock_list[SYSTEM_CLOCK]) {
571  		return KERN_FAILURE;
572  	}
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);
581  	if (chkstat < 0) {
582  		return KERN_INVALID_VALUE;
583  	}
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);
596  			if (alarm == 0) {
597  				return KERN_RESOURCE_SHORTAGE;
598  			}
599  			LOCK_ALARM(s);
600  		} else {
601  			alrmfree = alarm->al_next;
602  		}
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);
624  				if (((alarm->al_prev)->al_next = alarm->al_next) != NULL) {
625  					(alarm->al_next)->al_prev = alarm->al_prev;
626  				}
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);
639  	} else {
640  		*sleep_time = clock_time;
641  	}
642  
643  	return rvalue;
644  }
645  
646  /*
647   * Service clock alarm expirations.
648   */
649  static void
650  alarm_expire(void)
651  {
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;
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;
670  		if (CMP_MACH_TIMESPEC(alarm_time, &clock_time) > 0) {
671  			break;
672  		}
673  
674  		/*
675  		 * Alarm has expired, so remove it from the
676  		 * clock alarm list.
677  		 */
678  		if ((alrm1->al_next = alrm2->al_next) != NULL) {
679  			(alrm1->al_next)->al_prev = alrm1;
680  		}
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) {
687  			alrm2->al_next = NULL;
688  			alrm2->al_status = ALARM_DONE;
689  			alrm2->al_time = clock_time;
690  			thread_wakeup((event_t)alrm2);
691  		}
692  		/*
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);
699  			if ((alrm2->al_next = alrmdone) != NULL) {
700  				alrmdone->al_prev = alrm2;
701  			} else {
702  				thread_call_enter(&alarm_done_call);
703  			}
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  	 */
714  	if (alrm2) {
715  		set_alarm(alarm_time);
716  	}
717  	UNLOCK_ALARM(s);
718  }
719  
720  static void
721  alarm_done(void)
722  {
723  	alarm_t alrm;
724  	kern_return_t           code;
725  	spl_t                           s;
726  
727  	LOCK_ALARM(s);
728  	while ((alrm = alrmdone) != NULL) {
729  		if ((alrmdone = alrm->al_next) != NULL) {
730  			alrmdone->al_prev = (alarm_t)&alrmdone;
731  		}
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,
739  				    alrm->al_type, alrm->al_time);
740  			}
741  
742  			LOCK_ALARM(s);
743  			alrm->al_status = ALARM_FREE;
744  			alrm->al_next = alrmfree;
745  			alrmfree = alrm;
746  		} else {
747  			panic("clock_alarm_deliver");
748  		}
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   */
759  static void
760  post_alarm(
761  	alarm_t                         alarm)
762  {
763  	alarm_t alrm1, alrm2;
764  	mach_timespec_t         *alarm_time;
765  	mach_timespec_t         *queue_time;
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;
775  		if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0) {
776  			break;
777  		}
778  		alrm1 = alrm2;
779  	}
780  	alrm1->al_next = alarm;
781  	alarm->al_next = alrm2;
782  	alarm->al_prev = alrm1;
783  	if (alrm2) {
784  		alrm2->al_prev  = alarm;
785  	}
786  
787  	/*
788  	 * If the inserted alarm is the 'earliest' alarm,
789  	 * reset the device layer alarm time accordingly.
790  	 */
791  	if (alrmlist == alarm) {
792  		set_alarm(alarm_time);
793  	}
794  }
795  
796  static void
797  set_alarm(
798  	mach_timespec_t         *alarm_time)
799  {
800  	uint64_t        abstime;
801  
802  	nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime);
803  	timer_call_enter_with_leeway(&alarm_expire_timer, NULL, abstime, 0, TIMER_CALL_USER_NORMAL, FALSE);
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   */
812  static int
813  check_time(
814  	alarm_type_t            alarm_type,
815  	mach_timespec_t         *alarm_time,
816  	mach_timespec_t         *clock_time)
817  {
818  	int                                     result;
819  
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) {
827  		ADD_MACH_TIMESPEC(alarm_time, clock_time);
828  	}
829  
830  	result = CMP_MACH_TIMESPEC(alarm_time, clock_time);
831  
832  	return (result >= 0)? result: 0;
833  }
834  
835  #ifndef __LP64__
836  
837  mach_timespec_t
838  clock_get_system_value(void)
839  {
840  	clock_t                         clock = &clock_list[SYSTEM_CLOCK];
841  	mach_timespec_t         value;
842  
843  	(void) (*clock->cl_ops->c_gettime)(&value);
844  
845  	return value;
846  }
847  
848  mach_timespec_t
849  clock_get_calendar_value(void)
850  {
851  	clock_t                         clock = &clock_list[CALENDAR_CLOCK];
852  	mach_timespec_t         value = MACH_TIMESPEC_ZERO;
853  
854  	(void) (*clock->cl_ops->c_gettime)(&value);
855  
856  	return value;
857  }
858  
859  #endif  /* __LP64__ */