--- /dev/null
+/*
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * DEPRECATED INTERFACES - Should be removed
+ *
+ * Purpose: Routines for the creation and use of kernel
+ * alarm clock services. This file and the ipc
+ * routines in kern/ipc_clock.c constitute the
+ * machine-independent clock service layer.
+ */
+
+#include <mach/mach_types.h>
+
+#include <kern/lock.h>
+#include <kern/host.h>
+#include <kern/spl.h>
+#include <kern/sched_prim.h>
+#include <kern/thread.h>
+#include <kern/ipc_host.h>
+#include <kern/clock.h>
+#include <kern/zalloc.h>
+
+#include <ipc/ipc_types.h>
+#include <ipc/ipc_port.h>
+
+#include <mach/mach_traps.h>
+#include <mach/mach_time.h>
+
+#include <mach/clock_server.h>
+#include <mach/clock_reply.h>
+#include <mach/clock_priv_server.h>
+
+#include <mach/mach_host_server.h>
+#include <mach/host_priv_server.h>
+
+/*
+ * Actual clock alarm structure. Used for user clock_sleep() and
+ * clock_alarm() calls. Alarms are allocated from the alarm free
+ * list and entered in time priority order into the active alarm
+ * chain of the target clock.
+ */
+struct alarm {
+ struct alarm *al_next; /* next alarm in chain */
+ struct alarm *al_prev; /* previous alarm in chain */
+ int al_status; /* alarm status */
+ mach_timespec_t al_time; /* alarm time */
+ struct { /* message alarm data */
+ int type; /* alarm type */
+ ipc_port_t port; /* alarm port */
+ mach_msg_type_name_t
+ port_type; /* alarm port type */
+ struct clock *clock; /* alarm clock */
+ void *data; /* alarm data */
+ } al_alrm;
+#define al_type al_alrm.type
+#define al_port al_alrm.port
+#define al_port_type al_alrm.port_type
+#define al_clock al_alrm.clock
+#define al_data al_alrm.data
+ long al_seqno; /* alarm sequence number */
+};
+typedef struct alarm alarm_data_t;
+
+/* alarm status */
+#define ALARM_FREE 0 /* alarm is on free list */
+#define ALARM_SLEEP 1 /* active clock_sleep() */
+#define ALARM_CLOCK 2 /* active clock_alarm() */
+#define ALARM_DONE 4 /* alarm has expired */
+
+/* local data declarations */
+decl_simple_lock_data(static,alarm_lock) /* alarm synchronization */
+static struct zone *alarm_zone; /* zone for user alarms */
+static struct alarm *alrmfree; /* alarm free list pointer */
+static struct alarm *alrmdone; /* alarm done list pointer */
+static struct alarm *alrmlist;
+static long alrm_seqno; /* uniquely identifies alarms */
+static thread_call_data_t alarm_done_call;
+static timer_call_data_t alarm_expire_timer;
+
+extern struct clock clock_list[];
+extern int clock_count;
+
+static void post_alarm(
+ alarm_t alarm);
+
+static void set_alarm(
+ mach_timespec_t *alarm_time);
+
+static int check_time(
+ alarm_type_t alarm_type,
+ mach_timespec_t *alarm_time,
+ mach_timespec_t *clock_time);
+
+static void alarm_done(void);
+
+static void alarm_expire(void);
+
+static kern_return_t clock_sleep_internal(
+ clock_t clock,
+ sleep_type_t sleep_type,
+ mach_timespec_t *sleep_time);
+
+int rtclock_config(void);
+
+int rtclock_init(void);
+
+kern_return_t rtclock_gettime(
+ mach_timespec_t *cur_time);
+
+kern_return_t rtclock_getattr(
+ clock_flavor_t flavor,
+ clock_attr_t attr,
+ mach_msg_type_number_t *count);
+
+struct clock_ops sysclk_ops = {
+ rtclock_config, rtclock_init,
+ rtclock_gettime,
+ rtclock_getattr,
+};
+
+kern_return_t calend_gettime(
+ mach_timespec_t *cur_time);
+
+kern_return_t calend_getattr(
+ clock_flavor_t flavor,
+ clock_attr_t attr,
+ mach_msg_type_number_t *count);
+
+struct clock_ops calend_ops = {
+ 0, 0,
+ calend_gettime,
+ calend_getattr,
+};
+
+/*
+ * Macros to lock/unlock clock system.
+ */
+#define LOCK_ALARM(s) \
+ s = splclock(); \
+ simple_lock(&alarm_lock);
+
+#define UNLOCK_ALARM(s) \
+ simple_unlock(&alarm_lock); \
+ splx(s);
+
+void
+clock_oldconfig(void)
+{
+ clock_t clock;
+ register int i;
+
+ simple_lock_init(&alarm_lock, 0);
+ thread_call_setup(&alarm_done_call, (thread_call_func_t)alarm_done, NULL);
+ timer_call_setup(&alarm_expire_timer, (timer_call_func_t)alarm_expire, NULL);
+
+ /*
+ * Configure clock devices.
+ */
+ for (i = 0; i < clock_count; i++) {
+ clock = &clock_list[i];
+ if (clock->cl_ops && clock->cl_ops->c_config) {
+ if ((*clock->cl_ops->c_config)() == 0)
+ clock->cl_ops = 0;
+ }
+ }
+
+ /* start alarm sequence numbers at 0 */
+ alrm_seqno = 0;
+}
+
+void
+clock_oldinit(void)
+{
+ clock_t clock;
+ register int i;
+
+ /*
+ * Initialize basic clock structures.
+ */
+ for (i = 0; i < clock_count; i++) {
+ clock = &clock_list[i];
+ if (clock->cl_ops && clock->cl_ops->c_init)
+ (*clock->cl_ops->c_init)();
+ }
+}
+
+/*
+ * Initialize the clock ipc service facility.
+ */
+void
+clock_service_create(void)
+{
+ clock_t clock;
+ register int i;
+
+ /*
+ * Initialize ipc clock services.
+ */
+ for (i = 0; i < clock_count; i++) {
+ clock = &clock_list[i];
+ if (clock->cl_ops) {
+ ipc_clock_init(clock);
+ ipc_clock_enable(clock);
+ }
+ }
+
+ /*
+ * Perform miscellaneous late
+ * initialization.
+ */
+ i = sizeof(struct alarm);
+ alarm_zone = zinit(i, (4096/i)*i, 10*i, "alarms");
+}
+
+/*
+ * Get the service port on a clock.
+ */
+kern_return_t
+host_get_clock_service(
+ host_t host,
+ clock_id_t clock_id,
+ clock_t *clock) /* OUT */
+{
+ if (host == HOST_NULL || clock_id < 0 || clock_id >= clock_count) {
+ *clock = CLOCK_NULL;
+ return (KERN_INVALID_ARGUMENT);
+ }
+
+ *clock = &clock_list[clock_id];
+ if ((*clock)->cl_ops == 0)
+ return (KERN_FAILURE);
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Get the control port on a clock.
+ */
+kern_return_t
+host_get_clock_control(
+ host_priv_t host_priv,
+ clock_id_t clock_id,
+ clock_t *clock) /* OUT */
+{
+ if (host_priv == HOST_PRIV_NULL ||
+ clock_id < 0 || clock_id >= clock_count) {
+ *clock = CLOCK_NULL;
+ return (KERN_INVALID_ARGUMENT);
+ }
+
+ *clock = &clock_list[clock_id];
+ if ((*clock)->cl_ops == 0)
+ return (KERN_FAILURE);
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Get the current clock time.
+ */
+kern_return_t
+clock_get_time(
+ clock_t clock,
+ mach_timespec_t *cur_time) /* OUT */
+{
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+ return ((*clock->cl_ops->c_gettime)(cur_time));
+}
+
+kern_return_t
+rtclock_gettime(
+ mach_timespec_t *time) /* OUT */
+{
+ clock_get_system_nanotime(&time->tv_sec, (uint32_t *)&time->tv_nsec);
+
+ return (KERN_SUCCESS);
+}
+
+kern_return_t
+calend_gettime(
+ mach_timespec_t *time) /* OUT */
+{
+ clock_get_calendar_nanotime(&time->tv_sec, (uint32_t *)&time->tv_nsec);
+
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Get clock attributes.
+ */
+kern_return_t
+clock_get_attributes(
+ clock_t clock,
+ clock_flavor_t flavor,
+ clock_attr_t attr, /* OUT */
+ mach_msg_type_number_t *count) /* IN/OUT */
+{
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+ if (clock->cl_ops->c_getattr)
+ return (clock->cl_ops->c_getattr(flavor, attr, count));
+ return (KERN_FAILURE);
+}
+
+kern_return_t
+rtclock_getattr(
+ clock_flavor_t flavor,
+ clock_attr_t attr, /* OUT */
+ mach_msg_type_number_t *count) /* IN/OUT */
+{
+ if (*count != 1)
+ return (KERN_FAILURE);
+
+ switch (flavor) {
+
+ case CLOCK_GET_TIME_RES: /* >0 res */
+ case CLOCK_ALARM_CURRES: /* =0 no alarm */
+ case CLOCK_ALARM_MINRES:
+ case CLOCK_ALARM_MAXRES:
+ *(clock_res_t *) attr = NSEC_PER_SEC / 100;
+ break;
+
+ default:
+ return (KERN_INVALID_VALUE);
+ }
+
+ return (KERN_SUCCESS);
+}
+
+kern_return_t
+calend_getattr(
+ clock_flavor_t flavor,
+ clock_attr_t attr, /* OUT */
+ mach_msg_type_number_t *count) /* IN/OUT */
+{
+ if (*count != 1)
+ return (KERN_FAILURE);
+
+ switch (flavor) {
+
+ case CLOCK_GET_TIME_RES: /* >0 res */
+ *(clock_res_t *) attr = NSEC_PER_SEC / 100;
+ break;
+
+ case CLOCK_ALARM_CURRES: /* =0 no alarm */
+ case CLOCK_ALARM_MINRES:
+ case CLOCK_ALARM_MAXRES:
+ *(clock_res_t *) attr = 0;
+ break;
+
+ default:
+ return (KERN_INVALID_VALUE);
+ }
+
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Set the current clock time.
+ */
+kern_return_t
+clock_set_time(
+ clock_t clock,
+__unused mach_timespec_t new_time)
+{
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+ return (KERN_FAILURE);
+}
+
+/*
+ * Set the clock alarm resolution.
+ */
+kern_return_t
+clock_set_attributes(
+ clock_t clock,
+__unused clock_flavor_t flavor,
+__unused clock_attr_t attr,
+__unused mach_msg_type_number_t count)
+{
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+ return (KERN_FAILURE);
+}
+
+/*
+ * Setup a clock alarm.
+ */
+kern_return_t
+clock_alarm(
+ clock_t clock,
+ alarm_type_t alarm_type,
+ mach_timespec_t alarm_time,
+ ipc_port_t alarm_port,
+ mach_msg_type_name_t alarm_port_type)
+{
+ alarm_t alarm;
+ mach_timespec_t clock_time;
+ int chkstat;
+ kern_return_t reply_code;
+ spl_t s;
+
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+ if (clock != &clock_list[SYSTEM_CLOCK])
+ return (KERN_FAILURE);
+ if (IP_VALID(alarm_port) == 0)
+ return (KERN_INVALID_CAPABILITY);
+
+ /*
+ * Check alarm parameters. If parameters are invalid,
+ * send alarm message immediately.
+ */
+ (*clock->cl_ops->c_gettime)(&clock_time);
+ chkstat = check_time(alarm_type, &alarm_time, &clock_time);
+ if (chkstat <= 0) {
+ reply_code = (chkstat < 0 ? KERN_INVALID_VALUE : KERN_SUCCESS);
+ clock_alarm_reply(alarm_port, alarm_port_type,
+ reply_code, alarm_type, clock_time);
+ return (KERN_SUCCESS);
+ }
+
+ /*
+ * Get alarm and add to clock alarm list.
+ */
+
+ LOCK_ALARM(s);
+ if ((alarm = alrmfree) == 0) {
+ UNLOCK_ALARM(s);
+ alarm = (alarm_t) zalloc(alarm_zone);
+ if (alarm == 0)
+ return (KERN_RESOURCE_SHORTAGE);
+ LOCK_ALARM(s);
+ }
+ else
+ alrmfree = alarm->al_next;
+
+ alarm->al_status = ALARM_CLOCK;
+ alarm->al_time = alarm_time;
+ alarm->al_type = alarm_type;
+ alarm->al_port = alarm_port;
+ alarm->al_port_type = alarm_port_type;
+ alarm->al_clock = clock;
+ alarm->al_seqno = alrm_seqno++;
+ post_alarm(alarm);
+ UNLOCK_ALARM(s);
+
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Sleep on a clock. System trap. User-level libmach clock_sleep
+ * interface call takes a mach_timespec_t sleep_time argument which it
+ * converts to sleep_sec and sleep_nsec arguments which are then
+ * passed to clock_sleep_trap.
+ */
+kern_return_t
+clock_sleep_trap(
+ struct clock_sleep_trap_args *args)
+{
+ mach_port_name_t clock_name = args->clock_name;
+ sleep_type_t sleep_type = args->sleep_type;
+ int sleep_sec = args->sleep_sec;
+ int sleep_nsec = args->sleep_nsec;
+ mach_vm_address_t wakeup_time_addr = args->wakeup_time;
+ clock_t clock;
+ mach_timespec_t swtime;
+ kern_return_t rvalue;
+
+ /*
+ * Convert the trap parameters.
+ */
+ if (clock_name == MACH_PORT_NULL)
+ clock = &clock_list[SYSTEM_CLOCK];
+ else
+ clock = port_name_to_clock(clock_name);
+
+ swtime.tv_sec = sleep_sec;
+ swtime.tv_nsec = sleep_nsec;
+
+ /*
+ * Call the actual clock_sleep routine.
+ */
+ rvalue = clock_sleep_internal(clock, sleep_type, &swtime);
+
+ /*
+ * Return current time as wakeup time.
+ */
+ if (rvalue != KERN_INVALID_ARGUMENT && rvalue != KERN_FAILURE) {
+ copyout((char *)&swtime, wakeup_time_addr, sizeof(mach_timespec_t));
+ }
+ return (rvalue);
+}
+
+static kern_return_t
+clock_sleep_internal(
+ clock_t clock,
+ sleep_type_t sleep_type,
+ mach_timespec_t *sleep_time)
+{
+ alarm_t alarm;
+ mach_timespec_t clock_time;
+ kern_return_t rvalue;
+ int chkstat;
+ spl_t s;
+
+ if (clock == CLOCK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+
+ if (clock != &clock_list[SYSTEM_CLOCK])
+ return (KERN_FAILURE);
+
+ /*
+ * Check sleep parameters. If parameters are invalid
+ * return an error, otherwise post alarm request.
+ */
+ (*clock->cl_ops->c_gettime)(&clock_time);
+
+ chkstat = check_time(sleep_type, sleep_time, &clock_time);
+ if (chkstat < 0)
+ return (KERN_INVALID_VALUE);
+ rvalue = KERN_SUCCESS;
+ if (chkstat > 0) {
+ wait_result_t wait_result;
+
+ /*
+ * Get alarm and add to clock alarm list.
+ */
+
+ LOCK_ALARM(s);
+ if ((alarm = alrmfree) == 0) {
+ UNLOCK_ALARM(s);
+ alarm = (alarm_t) zalloc(alarm_zone);
+ if (alarm == 0)
+ return (KERN_RESOURCE_SHORTAGE);
+ LOCK_ALARM(s);
+ }
+ else
+ alrmfree = alarm->al_next;
+
+ /*
+ * Wait for alarm to occur.
+ */
+ wait_result = assert_wait((event_t)alarm, THREAD_ABORTSAFE);
+ if (wait_result == THREAD_WAITING) {
+ alarm->al_time = *sleep_time;
+ alarm->al_status = ALARM_SLEEP;
+ post_alarm(alarm);
+ UNLOCK_ALARM(s);
+
+ wait_result = thread_block(THREAD_CONTINUE_NULL);
+
+ /*
+ * Note if alarm expired normally or whether it
+ * was aborted. If aborted, delete alarm from
+ * clock alarm list. Return alarm to free list.
+ */
+ LOCK_ALARM(s);
+ if (alarm->al_status != ALARM_DONE) {
+ assert(wait_result != THREAD_AWAKENED);
+ if (((alarm->al_prev)->al_next = alarm->al_next) != NULL)
+ (alarm->al_next)->al_prev = alarm->al_prev;
+ rvalue = KERN_ABORTED;
+ }
+ *sleep_time = alarm->al_time;
+ alarm->al_status = ALARM_FREE;
+ } else {
+ assert(wait_result == THREAD_INTERRUPTED);
+ assert(alarm->al_status == ALARM_FREE);
+ rvalue = KERN_ABORTED;
+ }
+ alarm->al_next = alrmfree;
+ alrmfree = alarm;
+ UNLOCK_ALARM(s);
+ }
+ else
+ *sleep_time = clock_time;
+
+ return (rvalue);
+}
+
+/*
+ * Service clock alarm expirations.
+ */
+static void
+alarm_expire(void)
+{
+ clock_t clock;
+ register alarm_t alrm1;
+ register alarm_t alrm2;
+ mach_timespec_t clock_time;
+ mach_timespec_t *alarm_time;
+ spl_t s;
+
+ clock = &clock_list[SYSTEM_CLOCK];
+ (*clock->cl_ops->c_gettime)(&clock_time);
+
+ /*
+ * Update clock alarm list. Alarms that are due are moved
+ * to the alarmdone list to be serviced by a thread callout.
+ */
+ LOCK_ALARM(s);
+ alrm1 = (alarm_t)&alrmlist;
+ while ((alrm2 = alrm1->al_next) != NULL) {
+ alarm_time = &alrm2->al_time;
+ if (CMP_MACH_TIMESPEC(alarm_time, &clock_time) > 0)
+ break;
+
+ /*
+ * Alarm has expired, so remove it from the
+ * clock alarm list.
+ */
+ if ((alrm1->al_next = alrm2->al_next) != NULL)
+ (alrm1->al_next)->al_prev = alrm1;
+
+ /*
+ * If a clock_sleep() alarm, wakeup the thread
+ * which issued the clock_sleep() call.
+ */
+ if (alrm2->al_status == ALARM_SLEEP) {
+ alrm2->al_next = 0;
+ alrm2->al_status = ALARM_DONE;
+ alrm2->al_time = clock_time;
+ thread_wakeup((event_t)alrm2);
+ }
+
+ /*
+ * If a clock_alarm() alarm, place the alarm on
+ * the alarm done list and schedule the alarm
+ * delivery mechanism.
+ */
+ else {
+ assert(alrm2->al_status == ALARM_CLOCK);
+ if ((alrm2->al_next = alrmdone) != NULL)
+ alrmdone->al_prev = alrm2;
+ else
+ thread_call_enter(&alarm_done_call);
+ alrm2->al_prev = (alarm_t)&alrmdone;
+ alrmdone = alrm2;
+ alrm2->al_status = ALARM_DONE;
+ alrm2->al_time = clock_time;
+ }
+ }
+
+ /*
+ * Setup to expire for the next pending alarm.
+ */
+ if (alrm2)
+ set_alarm(alarm_time);
+ UNLOCK_ALARM(s);
+}
+
+static void
+alarm_done(void)
+{
+ register alarm_t alrm;
+ kern_return_t code;
+ spl_t s;
+
+ LOCK_ALARM(s);
+ while ((alrm = alrmdone) != NULL) {
+ if ((alrmdone = alrm->al_next) != NULL)
+ alrmdone->al_prev = (alarm_t)&alrmdone;
+ UNLOCK_ALARM(s);
+
+ code = (alrm->al_status == ALARM_DONE? KERN_SUCCESS: KERN_ABORTED);
+ if (alrm->al_port != IP_NULL) {
+ /* Deliver message to designated port */
+ if (IP_VALID(alrm->al_port)) {
+ clock_alarm_reply(alrm->al_port, alrm->al_port_type, code,
+ alrm->al_type, alrm->al_time);
+ }
+
+ LOCK_ALARM(s);
+ alrm->al_status = ALARM_FREE;
+ alrm->al_next = alrmfree;
+ alrmfree = alrm;
+ }
+ else
+ panic("clock_alarm_deliver");
+ }
+
+ UNLOCK_ALARM(s);
+}
+
+/*
+ * Post an alarm on the active alarm list.
+ *
+ * Always called from within a LOCK_ALARM() code section.
+ */
+static void
+post_alarm(
+ alarm_t alarm)
+{
+ register alarm_t alrm1, alrm2;
+ mach_timespec_t *alarm_time;
+ mach_timespec_t *queue_time;
+
+ /*
+ * Traverse alarm list until queue time is greater
+ * than alarm time, then insert alarm.
+ */
+ alarm_time = &alarm->al_time;
+ alrm1 = (alarm_t)&alrmlist;
+ while ((alrm2 = alrm1->al_next) != NULL) {
+ queue_time = &alrm2->al_time;
+ if (CMP_MACH_TIMESPEC(queue_time, alarm_time) > 0)
+ break;
+ alrm1 = alrm2;
+ }
+ alrm1->al_next = alarm;
+ alarm->al_next = alrm2;
+ alarm->al_prev = alrm1;
+ if (alrm2)
+ alrm2->al_prev = alarm;
+
+ /*
+ * If the inserted alarm is the 'earliest' alarm,
+ * reset the device layer alarm time accordingly.
+ */
+ if (alrmlist == alarm)
+ set_alarm(alarm_time);
+}
+
+static void
+set_alarm(
+ mach_timespec_t *alarm_time)
+{
+ uint64_t abstime;
+
+ nanotime_to_absolutetime(alarm_time->tv_sec, alarm_time->tv_nsec, &abstime);
+ timer_call_enter(&alarm_expire_timer, abstime);
+}
+
+/*
+ * Check the validity of 'alarm_time' and 'alarm_type'. If either
+ * argument is invalid, return a negative value. If the 'alarm_time'
+ * is now, return a 0 value. If the 'alarm_time' is in the future,
+ * return a positive value.
+ */
+static int
+check_time(
+ alarm_type_t alarm_type,
+ mach_timespec_t *alarm_time,
+ mach_timespec_t *clock_time)
+{
+ int result;
+
+ if (BAD_ALRMTYPE(alarm_type))
+ return (-1);
+ if (BAD_MACH_TIMESPEC(alarm_time))
+ return (-1);
+ if ((alarm_type & ALRMTYPE) == TIME_RELATIVE)
+ ADD_MACH_TIMESPEC(alarm_time, clock_time);
+
+ result = CMP_MACH_TIMESPEC(alarm_time, clock_time);
+
+ return ((result >= 0)? result: 0);
+}
+
+mach_timespec_t
+clock_get_system_value(void)
+{
+ clock_t clock = &clock_list[SYSTEM_CLOCK];
+ mach_timespec_t value;
+
+ (void) (*clock->cl_ops->c_gettime)(&value);
+
+ return value;
+}
+
+mach_timespec_t
+clock_get_calendar_value(void)
+{
+ clock_t clock = &clock_list[CALENDAR_CLOCK];
+ mach_timespec_t value = MACH_TIMESPEC_ZERO;
+
+ (void) (*clock->cl_ops->c_gettime)(&value);
+
+ return value;
+}