1285307Sed/*-
2285307Sed * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3285307Sed *
4285307Sed * Redistribution and use in source and binary forms, with or without
5285307Sed * modification, are permitted provided that the following conditions
6285307Sed * are met:
7285307Sed * 1. Redistributions of source code must retain the above copyright
8285307Sed *    notice, this list of conditions and the following disclaimer.
9285307Sed * 2. Redistributions in binary form must reproduce the above copyright
10285307Sed *    notice, this list of conditions and the following disclaimer in the
11285307Sed *    documentation and/or other materials provided with the distribution.
12285307Sed *
13285307Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14285307Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15285307Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16285307Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17285307Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18285307Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19285307Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20285307Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21285307Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22285307Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23285307Sed * SUCH DAMAGE.
24285307Sed */
25285307Sed
26285307Sed#include <sys/cdefs.h>
27285307Sed__FBSDID("$FreeBSD: releng/11.0/sys/compat/cloudabi/cloudabi_clock.c 297247 2016-03-24 21:47:15Z ed $");
28285307Sed
29285754Sed#include <sys/param.h>
30285754Sed#include <sys/proc.h>
31285754Sed#include <sys/stdint.h>
32285754Sed#include <sys/syscallsubr.h>
33285754Sed
34297247Sed#include <contrib/cloudabi/cloudabi_types_common.h>
35297247Sed
36285307Sed#include <compat/cloudabi/cloudabi_proto.h>
37285754Sed#include <compat/cloudabi/cloudabi_util.h>
38285307Sed
39285754Sed/* Converts a CloudABI clock ID to a FreeBSD clock ID. */
40285754Sedstatic int
41285754Sedcloudabi_convert_clockid(cloudabi_clockid_t in, clockid_t *out)
42285754Sed{
43285754Sed	switch (in) {
44285754Sed	case CLOUDABI_CLOCK_MONOTONIC:
45285754Sed		*out = CLOCK_MONOTONIC;
46285754Sed		return (0);
47285754Sed	case CLOUDABI_CLOCK_PROCESS_CPUTIME_ID:
48285754Sed		*out = CLOCK_PROCESS_CPUTIME_ID;
49285754Sed		return (0);
50285754Sed	case CLOUDABI_CLOCK_REALTIME:
51285754Sed		*out = CLOCK_REALTIME;
52285754Sed		return (0);
53285754Sed	case CLOUDABI_CLOCK_THREAD_CPUTIME_ID:
54285754Sed		*out = CLOCK_THREAD_CPUTIME_ID;
55285754Sed		return (0);
56285754Sed	default:
57285754Sed		return (EINVAL);
58285754Sed	}
59285754Sed}
60285754Sed
61285754Sed/* Converts a struct timespec to a CloudABI timestamp. */
62285307Sedint
63285754Sedcloudabi_convert_timespec(const struct timespec *in, cloudabi_timestamp_t *out)
64285754Sed{
65285754Sed	cloudabi_timestamp_t s, ns;
66285754Sed
67285754Sed	if (in->tv_sec < 0) {
68285754Sed		/* Timestamps from before the Epoch cannot be expressed. */
69285754Sed		*out = 0;
70285754Sed		return (EOVERFLOW);
71285754Sed	}
72285754Sed	s = in->tv_sec;
73285754Sed	ns = in->tv_nsec;
74285754Sed	if (s > UINT64_MAX / 1000000000 ||
75285754Sed	    (s == UINT64_MAX / 1000000000 && ns > UINT64_MAX % 1000000000)) {
76285754Sed		/* Addition of seconds and nanoseconds would overflow. */
77285754Sed		*out = UINT64_MAX;
78285754Sed		return (EOVERFLOW);
79285754Sed	}
80285754Sed	*out = s * 1000000000 + ns;
81285754Sed	return (0);
82285754Sed}
83285754Sed
84285908Sed/* Fetches the time value of a clock. */
85285754Sedint
86285908Sedcloudabi_clock_time_get(struct thread *td, cloudabi_clockid_t clock_id,
87285908Sed    cloudabi_timestamp_t *ret)
88285307Sed{
89285754Sed	struct timespec ts;
90285754Sed	int error;
91285754Sed	clockid_t clockid;
92285307Sed
93285908Sed	error = cloudabi_convert_clockid(clock_id, &clockid);
94285754Sed	if (error != 0)
95285754Sed		return (error);
96285908Sed	error = kern_clock_gettime(td, clockid, &ts);
97285754Sed	if (error != 0)
98285754Sed		return (error);
99285908Sed	return (cloudabi_convert_timespec(&ts, ret));
100285307Sed}
101285307Sed
102285307Sedint
103285908Sedcloudabi_sys_clock_res_get(struct thread *td,
104285908Sed    struct cloudabi_sys_clock_res_get_args *uap)
105285307Sed{
106285754Sed	struct timespec ts;
107285754Sed	cloudabi_timestamp_t cts;
108285754Sed	int error;
109285754Sed	clockid_t clockid;
110285307Sed
111285754Sed	error = cloudabi_convert_clockid(uap->clock_id, &clockid);
112285754Sed	if (error != 0)
113285754Sed		return (error);
114285908Sed	error = kern_clock_getres(td, clockid, &ts);
115285754Sed	if (error != 0)
116285754Sed		return (error);
117285754Sed	error = cloudabi_convert_timespec(&ts, &cts);
118285754Sed	if (error != 0)
119285754Sed		return (error);
120285754Sed	td->td_retval[0] = cts;
121285754Sed	return (0);
122285307Sed}
123285908Sed
124285908Sedint
125285908Sedcloudabi_sys_clock_time_get(struct thread *td,
126285908Sed    struct cloudabi_sys_clock_time_get_args *uap)
127285908Sed{
128285908Sed	cloudabi_timestamp_t ts;
129285908Sed	int error;
130285908Sed
131285908Sed	error = cloudabi_clock_time_get(td, uap->clock_id, &ts);
132285908Sed	td->td_retval[0] = ts;
133285908Sed	return (error);
134285908Sed}
135