/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <assert.h> #include <errno.h> #include <trusty/time.h> #include <trusty_syscalls.h> #define NS_PER_SEC 1000000000 int trusty_nanosleep(clockid_t clock_id, uint32_t flags, uint64_t sleep_time) { /* TODO validate clock_ids. */ /* No flags, yet. */ assert(flags == 0); return _trusty_nanosleep(clock_id, flags, sleep_time); } int trusty_nanodelay(clockid_t clock_id, uint32_t flags, uint64_t sleep_time) { int64_t target, time; int rc; /* TODO validate clock_ids. */ /* No flags, yet. */ assert(flags == 0); rc = trusty_gettime(clock_id, &time); if (rc) return rc; target = time + sleep_time; while (time < target) { rc = trusty_gettime(clock_id, &time); if (rc) return rc; } return 0; } int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* req, struct timespec* rem) { /* Validate inputs. */ if (!req) { errno = EFAULT; return -1; } if (req->tv_sec < 0) { errno = EINVAL; return -1; } if (req->tv_nsec >= NS_PER_SEC || req->tv_nsec < 0) { errno = EINVAL; return -1; } /* Convert timespec to nanoseconds. */ uint64_t sleep_time; /* * Note: casting NS_PER_SEC to work around a Clang codegen bug. * See: b/145830721 */ if (__builtin_mul_overflow(req->tv_sec, (uint64_t)NS_PER_SEC, &sleep_time)) { errno = EINVAL; return -1; } if (__builtin_add_overflow(sleep_time, req->tv_nsec, &sleep_time)) { errno = EINVAL; return -1; } /* Actually sleep. */ int ret = trusty_nanosleep(clock_id, flags, sleep_time); /* Handle the result. */ if (rem) { /* Trusty should not wake up early, except for clock rounding. */ rem->tv_sec = 0; rem->tv_nsec = 0; } if (ret) { /* clock_id was invalid? */ errno = EINVAL; return -1; } return 0; } int nanosleep(const struct timespec* req, struct timespec* rem) { return clock_nanosleep(CLOCK_BOOTTIME, 0, req, rem); } int trusty_gettime(clockid_t clock_id, int64_t* time) { return _trusty_gettime(clock_id, 0, time); } int __clock_gettime(clockid_t clock_id, struct timespec* ts) { if (ts == NULL) { errno = EFAULT; return -1; } int64_t time; int rc = trusty_gettime(clock_id, &time); if (rc) { /* &time is valid, so clock_id must have been invalid. */ errno = EINVAL; return -1; } ts->tv_sec = (time_t)(time / NS_PER_SEC); ts->tv_nsec = (long)(time % NS_PER_SEC); return 0; } /* * Internally, Musl references __clock_gettime, and then provides an alias for * external users. Since we're providing the function, we need to provide the * internal name for Musl and the external name for the user. */ weak_alias(__clock_gettime, clock_gettime);