1/* 2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <stdint.h> 33#include <errno.h> 34#include <time.h> 35#include <signal.h> 36#include <unistd.h> 37#include <los_hwi.h> 38#include <los_swtmr.h> 39#include <los_swtmr_pri.h> 40 41#ifndef STATIC 42#define STATIC static 43#endif 44 45#define OS_SYS_NS_PER_US 1000 46#define OS_SYS_NS_PER_SECOND 1000000000 47#define OS_SYS_US_PER_SECOND 1000000 48#define OS_SYS_MS_PER_SECOND 1000 49 50STATIC INLINE BOOL ValidTimerID(UINT16 swtmrID) 51{ 52 /* check timer id */ 53 return (swtmrID < LOSCFG_BASE_CORE_SWTMR_LIMIT); 54} 55 56/* internal functions */ 57STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp) 58{ 59 /* Fail a NULL pointer */ 60 if (tp == NULL) { 61 return FALSE; 62 } 63 64 /* Fail illegal nanosecond values */ 65 if ((tp->tv_nsec < 0) || (tp->tv_nsec >= OS_SYS_NS_PER_SECOND) || (tp->tv_sec < 0)) { 66 return FALSE; 67 } 68 69 return TRUE; 70} 71 72STATIC INLINE UINT32 OsTimeSpec2Tick(const struct timespec *tp) 73{ 74 UINT64 tick, ns; 75 76 ns = (UINT64)tp->tv_sec * OS_SYS_NS_PER_SECOND + tp->tv_nsec; 77 /* Round up for ticks */ 78 tick = (ns * LOSCFG_BASE_CORE_TICK_PER_SECOND + (OS_SYS_NS_PER_SECOND - 1)) / OS_SYS_NS_PER_SECOND; 79 if (tick > LOS_WAIT_FOREVER) { 80 tick = LOS_WAIT_FOREVER; 81 } 82 return (UINT32)tick; 83} 84 85STATIC INLINE VOID OsTick2TimeSpec(struct timespec *tp, UINT32 tick) 86{ 87 UINT64 ns = ((UINT64)tick * OS_SYS_NS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND; 88 tp->tv_sec = (time_t)(ns / OS_SYS_NS_PER_SECOND); 89 tp->tv_nsec = (long)(ns % OS_SYS_NS_PER_SECOND); 90} 91 92int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) 93{ 94 UINT64 nseconds; 95 UINT64 tick; 96 UINT32 ret; 97 const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND; 98 99 if (!ValidTimeSpec(rqtp)) { 100 errno = EINVAL; 101 return -1; 102 } 103 104 nseconds = (UINT64)rqtp->tv_sec * OS_SYS_NS_PER_SECOND + rqtp->tv_nsec; 105 106 tick = (nseconds + nsPerTick - 1) / nsPerTick; // Round up for ticks 107 108 if (tick >= UINT32_MAX) { 109 errno = EINVAL; 110 return -1; 111 } 112 113 /* PS: skip the first tick because it is NOT a full tick. */ 114 ret = LOS_TaskDelay(tick ? (UINT32)(tick + 1) : 0); 115 if (ret == LOS_OK || ret == LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK) { 116 if (rmtp) { 117 rmtp->tv_sec = rmtp->tv_nsec = 0; 118 } 119 return 0; 120 } 121 122 /* sleep in interrupt context or in task sched lock state */ 123 errno = EPERM; 124 return -1; 125} 126 127int timer_create(clockid_t clockID, struct sigevent *restrict evp, timer_t *restrict timerID) 128{ 129 UINT32 ret; 130 UINT16 swtmrID; 131 132 if (!timerID || (clockID != CLOCK_REALTIME)) { 133 errno = EINVAL; 134 return -1; 135 } 136 137 if (!evp || evp->sigev_notify != SIGEV_THREAD || evp->sigev_notify_attributes) { 138 errno = ENOTSUP; 139 return -1; 140 } 141 142 ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, (SWTMR_PROC_FUNC)evp->sigev_notify_function, 143 &swtmrID, (UINT32)(UINTPTR)evp->sigev_value.sival_ptr); 144 if (ret != LOS_OK) { 145 errno = (ret == LOS_ERRNO_SWTMR_MAXSIZE) ? EAGAIN : EINVAL; 146 return -1; 147 } 148 149 *timerID = (timer_t)(UINTPTR)swtmrID; 150 return 0; 151} 152 153int timer_delete(timer_t timerID) 154{ 155 UINT16 swtmrID = (UINT16)(UINTPTR)timerID; 156 157 if (!ValidTimerID(swtmrID)) { 158 errno = EINVAL; 159 return -1; 160 } 161 162 if (LOS_SwtmrDelete(swtmrID) != LOS_OK) { 163 errno = EINVAL; 164 return -1; 165 } 166 167 return 0; 168} 169 170int timer_settime(timer_t timerID, int flags, 171 const struct itimerspec *restrict value, 172 struct itimerspec *restrict oldValue) 173{ 174 UINT32 intSave; 175 UINT16 swtmrID = (UINT16)(UINTPTR)timerID; 176 SWTMR_CTRL_S *swtmr = NULL; 177 UINT32 interval, expiry, ret; 178 179 if (flags != 0) { 180 /* flags not supported currently */ 181 errno = ENOSYS; 182 return -1; 183 } 184 185 if (value == NULL || !ValidTimerID(swtmrID)) { 186 errno = EINVAL; 187 return -1; 188 } 189 190 if (!ValidTimeSpec(&value->it_value) || !ValidTimeSpec(&value->it_interval)) { 191 errno = EINVAL; 192 return -1; 193 } 194 195 expiry = OsTimeSpec2Tick(&value->it_value); 196 interval = OsTimeSpec2Tick(&value->it_interval); 197 /* if specified interval, it must be same with expiry due to the limitation of liteos-m */ 198 if (interval && interval != expiry) { 199 errno = ENOTSUP; 200 return -1; 201 } 202 203 if (oldValue) { 204 (VOID)timer_gettime(timerID, oldValue); 205 } 206 207 ret = LOS_SwtmrStop(swtmrID); 208 if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) { 209 errno = EINVAL; 210 return -1; 211 } 212 213 intSave = LOS_IntLock(); 214 swtmr = OS_SWT_FROM_SID(swtmrID); 215 swtmr->ucMode = (interval ? LOS_SWTMR_MODE_PERIOD : LOS_SWTMR_MODE_NO_SELFDELETE); 216 swtmr->uwInterval = (interval ? interval : expiry); 217 218 LOS_IntRestore(intSave); 219 220 if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) { 221 /* 222 * 1) when expiry is 0, means timer should be stopped. 223 * 2) If timer is ticking, stopping timer is already done before. 224 * 3) If timer is created but not ticking, return 0 as well. 225 */ 226 return 0; 227 } 228 229 if (LOS_SwtmrStart(swtmr->usTimerID) != LOS_OK) { 230 errno = EINVAL; 231 return -1; 232 } 233 234 return 0; 235} 236 237int timer_gettime(timer_t timerID, struct itimerspec *value) 238{ 239 UINT32 tick = 0; 240 SWTMR_CTRL_S *swtmr = NULL; 241 UINT16 swtmrID = (UINT16)(UINTPTR)timerID; 242 UINT32 ret; 243 244 if ((value == NULL) || !ValidTimerID(swtmrID)) { 245 errno = EINVAL; 246 return -1; 247 } 248 249 swtmr = OS_SWT_FROM_SID(swtmrID); 250 251 /* get expire time */ 252 ret = LOS_SwtmrTimeGet(swtmr->usTimerID, &tick); 253 if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) { 254 errno = EINVAL; 255 return -1; 256 } 257 258 OsTick2TimeSpec(&value->it_value, tick); 259 OsTick2TimeSpec(&value->it_interval, (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ? 0 : swtmr->uwInterval); 260 return 0; 261} 262 263int timer_getoverrun(timer_t timerID) 264{ 265 UINT16 swtmrID = (UINT16)(UINTPTR)timerID; 266 267 if (!ValidTimerID(swtmrID)) { 268 errno = EINVAL; 269 return -1; 270 } 271 272 errno = ENOSYS; 273 return -1; 274} 275