xref: /kernel/liteos_m/kal/posix/src/time.c (revision 3d8536b4)
1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 *    conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 *    of conditions and the following disclaimer in the documentation and/or other materials
12 *    provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 *    to endorse or promote products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#define _GNU_SOURCE
32#include <time.h>
33#include <sys/time.h>
34#include <stdint.h>
35#include <errno.h>
36#include <signal.h>
37#include <unistd.h>
38#include "time_internal.h"
39#include "los_debug.h"
40#include "los_task.h"
41#include "los_swtmr.h"
42#include "los_tick.h"
43#include "los_context.h"
44#include "los_interrupt.h"
45#include "sys/times.h"
46#include "rtc_time_hook.h"
47
48#define DELAYTIMER_MAX 0x7FFFFFFFF
49
50/* accumulative time delta from discontinuous modify */
51STATIC struct timespec g_accDeltaFromSet;
52
53STATIC const UINT16 g_daysInMonth[2][13] = {
54    /* Normal years.  */
55    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
56    /* Leap years.  */
57    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
58};
59
60STATIC const UINT8 g_montbl[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
61
62#if (LOSCFG_LIBC_NEWLIB == 1)
63#define TIMEZONE _timezone
64#else
65#define TIMEZONE timezone
66/*
67 * Time zone information, stored in seconds,
68 * negative values indicate the east of UTC,
69 * positive values indicate the west of UTC.
70 */
71long TIMEZONE = -8 * 60 * 60; // set default to CST(UTC+8)
72#endif
73
74/*
75 * store register rtc func
76 */
77STATIC struct RtcTimeHook g_rtcTimeFunc;
78
79STATIC UINT64 g_rtcTimeBase = 0;
80STATIC UINT64 g_systickBase = 0;
81
82VOID LOS_RtcHookRegister(struct RtcTimeHook *cfg)
83{
84    if (cfg == NULL) {
85        return;
86    }
87    g_rtcTimeFunc.RtcGetTickHook = cfg->RtcGetTickHook;
88    g_rtcTimeFunc.RtcGetTimeHook = cfg->RtcGetTimeHook;
89    g_rtcTimeFunc.RtcSetTimeHook = cfg->RtcSetTimeHook;
90    g_rtcTimeFunc.RtcGetTimezoneHook = cfg->RtcGetTimezoneHook;
91    g_rtcTimeFunc.RtcSetTimezoneHook = cfg->RtcSetTimezoneHook;
92}
93
94int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
95{
96    UINT64 nseconds;
97    UINT64 tick;
98    UINT32 ret;
99    const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
100
101    if (!ValidTimeSpec(rqtp)) {
102        errno = EINVAL;
103        return -1;
104    }
105
106    nseconds = (UINT64)rqtp->tv_sec * OS_SYS_NS_PER_SECOND + rqtp->tv_nsec;
107
108    tick = (nseconds + nsPerTick - 1) / nsPerTick; // Round up for ticks
109
110    if (tick >= UINT32_MAX) {
111        errno = EINVAL;
112        return -1;
113    }
114
115    /* PS: skip the first tick because it is NOT a full tick. */
116    ret = LOS_TaskDelay(tick ? (UINT32)(tick + 1) : 0);
117    if (ret == LOS_OK || ret == LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK) {
118        if (rmtp) {
119            rmtp->tv_sec = rmtp->tv_nsec = 0;
120        }
121        return 0;
122    }
123
124    /* sleep in interrupt context or in task sched lock state */
125    errno = EINTR;
126    return -1;
127}
128
129int timer_create(clockid_t clockID, struct sigevent *restrict evp, timer_t *restrict timerID)
130{
131    UINT32 ret;
132    UINT32 swtmrID;
133
134    if (!timerID || (clockID != CLOCK_REALTIME) || !evp) {
135        errno = EINVAL;
136        return -1;
137    }
138
139    if ((evp->sigev_notify != SIGEV_THREAD) || evp->sigev_notify_attributes) {
140        errno = ENOTSUP;
141        return -1;
142    }
143
144    ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, (SWTMR_PROC_FUNC)evp->sigev_notify_function,
145                          &swtmrID, (UINT32)(UINTPTR)evp->sigev_value.sival_ptr
146#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
147                          , OS_SWTMR_ROUSES_IGNORE, OS_SWTMR_ALIGN_INSENSITIVE
148#endif
149    );
150    if (ret != LOS_OK) {
151        errno = (ret == LOS_ERRNO_SWTMR_MAXSIZE) ? EAGAIN : EINVAL;
152        return -1;
153    }
154
155    *timerID = (timer_t)(UINTPTR)swtmrID;
156    return 0;
157}
158
159int timer_delete(timer_t timerID)
160{
161    UINT32 swtmrID = (UINT32)(UINTPTR)timerID;
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    UINT32 swtmrID = (UINT32)(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 = ENOTSUP;
182        return -1;
183    }
184
185    if (value == NULL) {
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
198    /* if specified interval, it must be same with expiry due to the limitation of liteos-m */
199    if (interval && interval != expiry) {
200        errno = ENOTSUP;
201        return -1;
202    }
203
204    if (oldValue) {
205        (VOID)timer_gettime(timerID, oldValue);
206    }
207
208    ret = LOS_SwtmrStop(swtmrID);
209    if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
210        errno = EINVAL;
211        return -1;
212    }
213
214    intSave = LOS_IntLock();
215    swtmr = OS_SWT_FROM_SID(swtmrID);
216    swtmr->ucMode = (interval ? LOS_SWTMR_MODE_PERIOD : LOS_SWTMR_MODE_NO_SELFDELETE);
217    swtmr->uwInterval = (interval ? interval : expiry);
218
219    swtmr->ucOverrun = 0;
220    LOS_IntRestore(intSave);
221
222    if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
223        /*
224         * 1) when expiry is 0, means timer should be stopped.
225         * 2) If timer is ticking, stopping timer is already done before.
226         * 3) If timer is created but not ticking, return 0 as well.
227         */
228        return 0;
229    }
230
231    if (LOS_SwtmrStart(swtmr->usTimerID) != LOS_OK) {
232        errno = EINVAL;
233        return -1;
234    }
235
236    return 0;
237}
238
239int timer_gettime(timer_t timerID, struct itimerspec *value)
240{
241    UINT32 tick = 0;
242    SWTMR_CTRL_S *swtmr = NULL;
243    UINT32 swtmrID = (UINT32)(UINTPTR)timerID;
244    UINT32 ret;
245
246    if (value == NULL) {
247        errno = EINVAL;
248        return -1;
249    }
250
251    swtmr = OS_SWT_FROM_SID(swtmrID);
252
253    /* get expire time */
254    ret = LOS_SwtmrTimeGet(swtmr->usTimerID, &tick);
255    if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
256        errno = EINVAL;
257        return -1;
258    }
259    if (ret == LOS_ERRNO_SWTMR_NOT_STARTED) {
260        tick = 0;
261    }
262    OsTick2TimeSpec(&value->it_value, tick);
263    OsTick2TimeSpec(&value->it_interval, (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ? 0 : swtmr->uwInterval);
264    return 0;
265}
266
267int timer_getoverrun(timer_t timerID)
268{
269    SWTMR_CTRL_S *swtmr = NULL;
270    swtmr = OS_SWT_FROM_SID((UINT32)(UINTPTR)timerID);
271
272    if ((swtmr->ucOverrun) >= (UINT8)DELAYTIMER_MAX) {
273        return (INT32)DELAYTIMER_MAX;
274    }
275    return (int)swtmr->ucOverrun;
276}
277
278STATIC VOID OsGetHwTime(struct timespec *hwTime)
279{
280    UINT64 cycle = LOS_SysCycleGet();
281    UINT64 nowNsec = (cycle / g_sysClock) * OS_SYS_NS_PER_SECOND +
282                     (cycle % g_sysClock) * OS_SYS_NS_PER_SECOND / g_sysClock;
283
284    hwTime->tv_sec = nowNsec / OS_SYS_NS_PER_SECOND;
285    hwTime->tv_nsec = nowNsec % OS_SYS_NS_PER_SECOND;
286}
287
288STATIC VOID OsGetRealTime(struct timespec *realTime)
289{
290    UINT32 intSave;
291    struct timespec hwTime = {0};
292    OsGetHwTime(&hwTime);
293    intSave = LOS_IntLock();
294    realTime->tv_nsec = hwTime.tv_nsec + g_accDeltaFromSet.tv_nsec;
295    realTime->tv_sec = hwTime.tv_sec + g_accDeltaFromSet.tv_sec + (realTime->tv_nsec >= OS_SYS_NS_PER_SECOND);
296    realTime->tv_nsec %= OS_SYS_NS_PER_SECOND;
297    LOS_IntRestore(intSave);
298}
299
300STATIC VOID OsSetRealTime(const struct timespec *realTime)
301{
302    UINT32 intSave;
303    struct timespec hwTime = {0};
304    OsGetHwTime(&hwTime);
305    intSave = LOS_IntLock();
306    g_accDeltaFromSet.tv_nsec = realTime->tv_nsec - hwTime.tv_nsec;
307    g_accDeltaFromSet.tv_sec = realTime->tv_sec - hwTime.tv_sec - (g_accDeltaFromSet.tv_nsec < 0);
308    g_accDeltaFromSet.tv_nsec = (g_accDeltaFromSet.tv_nsec + OS_SYS_NS_PER_SECOND) % OS_SYS_NS_PER_SECOND;
309    LOS_IntRestore(intSave);
310}
311
312int clock_settime(clockid_t clockID, const struct timespec *tp)
313{
314    if (!ValidTimeSpec(tp)) {
315        errno = EINVAL;
316        return -1;
317    }
318
319    switch (clockID) {
320        case CLOCK_REALTIME:
321            /* we only support the realtime clock currently */
322            OsSetRealTime(tp);
323            return 0;
324        case CLOCK_MONOTONIC_COARSE:
325        case CLOCK_REALTIME_COARSE:
326        case CLOCK_MONOTONIC_RAW:
327        case CLOCK_PROCESS_CPUTIME_ID:
328        case CLOCK_BOOTTIME:
329#ifdef CLOCK_REALTIME_ALARM
330        case CLOCK_REALTIME_ALARM:
331#endif
332#ifdef CLOCK_BOOTTIME_ALARM
333        case CLOCK_BOOTTIME_ALARM:
334#endif
335#ifdef CLOCK_SGI_CYCLE
336        case CLOCK_SGI_CYCLE:
337#endif
338#ifdef CLOCK_TAI
339        case CLOCK_TAI:
340#endif
341        case CLOCK_THREAD_CPUTIME_ID:
342            errno = ENOTSUP;
343            return -1;
344        case CLOCK_MONOTONIC:
345        default:
346            errno = EINVAL;
347            return -1;
348    }
349}
350
351int clock_gettime(clockid_t clockID, struct timespec *tp)
352{
353    if (tp == NULL) {
354        errno = EINVAL;
355        return -1;
356    }
357
358    switch (clockID) {
359        case CLOCK_MONOTONIC_RAW:
360        case CLOCK_MONOTONIC:
361        case CLOCK_MONOTONIC_COARSE:
362            OsGetHwTime(tp);
363            return 0;
364        case CLOCK_REALTIME:
365        case CLOCK_REALTIME_COARSE:
366            OsGetRealTime(tp);
367            return 0;
368        case CLOCK_THREAD_CPUTIME_ID:
369        case CLOCK_PROCESS_CPUTIME_ID:
370        case CLOCK_BOOTTIME:
371#ifdef CLOCK_REALTIME_ALARM
372        case CLOCK_REALTIME_ALARM:
373#endif
374#ifdef CLOCK_BOOTTIME_ALARM
375        case CLOCK_BOOTTIME_ALARM:
376#endif
377#ifdef CLOCK_SGI_CYCLE
378        case CLOCK_SGI_CYCLE:
379#endif
380#ifdef CLOCK_TAI
381        case CLOCK_TAI:
382#endif
383            errno = ENOTSUP;
384            return -1;
385        default:
386            errno = EINVAL;
387            return -1;
388    }
389}
390
391int clock_getres(clockid_t clockID, struct timespec *tp)
392{
393    if (tp == NULL) {
394        errno = EINVAL;
395        return -1;
396    }
397
398    switch (clockID) {
399        case CLOCK_MONOTONIC_RAW:
400        case CLOCK_MONOTONIC:
401        case CLOCK_REALTIME:
402        case CLOCK_MONOTONIC_COARSE:
403        case CLOCK_REALTIME_COARSE:
404            tp->tv_nsec = OS_SYS_NS_PER_SECOND / g_sysClock;
405            tp->tv_sec = 0;
406            return 0;
407        case CLOCK_THREAD_CPUTIME_ID:
408        case CLOCK_PROCESS_CPUTIME_ID:
409        case CLOCK_BOOTTIME:
410#ifdef CLOCK_REALTIME_ALARM
411        case CLOCK_REALTIME_ALARM:
412#endif
413#ifdef CLOCK_BOOTTIME_ALARM
414        case CLOCK_BOOTTIME_ALARM:
415#endif
416#ifdef CLOCK_SGI_CYCLE
417        case CLOCK_SGI_CYCLE:
418#endif
419#ifdef CLOCK_TAI
420        case CLOCK_TAI:
421#endif
422            errno = ENOTSUP;
423            return -1;
424        default:
425            errno = EINVAL;
426            return -1;
427    }
428}
429
430int clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem)
431{
432    switch (clk) {
433        case CLOCK_REALTIME:
434            if (flags == 0) {
435                /* we only support the realtime clock currently */
436                return nanosleep(req, rem);
437            }
438            /* fallthrough */
439        case CLOCK_MONOTONIC_COARSE:
440        case CLOCK_REALTIME_COARSE:
441        case CLOCK_MONOTONIC_RAW:
442        case CLOCK_MONOTONIC:
443        case CLOCK_PROCESS_CPUTIME_ID:
444        case CLOCK_BOOTTIME:
445#ifdef CLOCK_REALTIME_ALARM
446        case CLOCK_REALTIME_ALARM:
447#endif
448#ifdef CLOCK_BOOTTIME_ALARM
449        case CLOCK_BOOTTIME_ALARM:
450#endif
451#ifdef CLOCK_SGI_CYCLE
452        case CLOCK_SGI_CYCLE:
453#endif
454#ifdef CLOCK_TAI
455        case CLOCK_TAI:
456#endif
457            if (flags == 0 || flags == TIMER_ABSTIME) {
458                return ENOTSUP;
459            }
460            /* fallthrough */
461        case CLOCK_THREAD_CPUTIME_ID:
462        default:
463            return EINVAL;
464    }
465}
466
467clock_t clock(void)
468{
469    if (g_rtcTimeFunc.RtcGetTickHook != NULL) {
470        return g_rtcTimeFunc.RtcGetTickHook();
471    }
472
473    clock_t clk;
474    struct timespec hwTime;
475    OsGetHwTime(&hwTime);
476
477    clk = hwTime.tv_sec * CLOCKS_PER_SEC;
478    clk += hwTime.tv_nsec  / (OS_SYS_NS_PER_SECOND / CLOCKS_PER_SEC);
479
480    return clk;
481}
482
483STATIC UINT64 GetCurrentTime(VOID)
484{
485    UINT64 tickDelta = 0;
486    UINT64 currentTick;
487
488    if (g_rtcTimeFunc.RtcGetTickHook != NULL) {
489        currentTick = g_rtcTimeFunc.RtcGetTickHook();
490        if ((g_systickBase != 0) && (currentTick > g_systickBase)) {
491            tickDelta = currentTick - g_systickBase;
492        }
493    }
494    return g_rtcTimeBase + LOS_Tick2MS((UINT32)tickDelta);
495}
496
497time_t time(time_t *timer)
498{
499    UINT64 usec = 0;
500    time_t sec;
501    INT32 rtcRet;
502
503    if (g_rtcTimeFunc.RtcGetTimeHook != NULL) {
504        rtcRet = g_rtcTimeFunc.RtcGetTimeHook(&usec);
505        if (rtcRet != 0) {
506            UINT64 currentTime;
507            currentTime = GetCurrentTime();
508            sec = currentTime / OS_SYS_MS_PER_SECOND;
509        } else {
510            sec = usec / OS_SYS_US_PER_SECOND;
511        }
512        if (timer != NULL) {
513            *timer = sec;
514        }
515        return sec;
516    } else {
517        struct timespec ts;
518        if (-1 == clock_gettime(CLOCK_REALTIME, &ts)) {
519            return (time_t)-1;
520        }
521
522        if (timer != NULL) {
523            *timer = ts.tv_sec;
524        }
525        return ts.tv_sec;
526    }
527}
528
529/*
530 * Compute the `struct tm' representation of T,
531 * offset OFFSET seconds east of UTC,
532 * and store year, yday, mon, mday, wday, hour, min, sec into *TP.
533 * Return nonzero if successful.
534 */
535static INT32 ConvertSecs2Utc(time_t t, INT32 offset, struct tm *tp)
536{
537    time_t days;
538    time_t rem;
539    time_t year;
540    time_t month;
541    time_t yearGuess;
542
543    days = t / SECS_PER_DAY;
544    rem = t % SECS_PER_DAY;
545    rem += offset;
546    while (rem < 0) {
547        rem += SECS_PER_DAY;
548        --days;
549    }
550    while (rem >= SECS_PER_DAY) {
551        rem -= SECS_PER_DAY;
552        ++days;
553    }
554    tp->tm_hour = rem / SECS_PER_HOUR;
555    rem %= SECS_PER_HOUR;
556    tp->tm_min = rem / SECS_PER_MIN;
557    tp->tm_sec = rem % SECS_PER_MIN;
558    /* January 1, 1970 was a Thursday.  */
559    tp->tm_wday = (BEGIN_WEEKDAY + days) % DAYS_PER_WEEK;
560    if (tp->tm_wday < 0) {
561        tp->tm_wday += DAYS_PER_WEEK;
562    }
563    year = EPOCH_YEAR;
564
565    while ((days < 0) ||
566           (days >= (IS_LEAP_YEAR (year) ? DAYS_PER_LEAP_YEAR : DAYS_PER_NORMAL_YEAR))) {
567        /* Guess a corrected year, assuming 365 days per year.  */
568        yearGuess = year + days / DAYS_PER_NORMAL_YEAR - (days % DAYS_PER_NORMAL_YEAR < 0);
569
570        /* Adjust days and year to match the guessed year.  */
571        days -= ((yearGuess - year) * DAYS_PER_NORMAL_YEAR +
572                 LEAPS_THRU_END_OF (yearGuess - 1) -
573                 LEAPS_THRU_END_OF (year - 1));
574        year = yearGuess;
575    }
576    tp->tm_year = year - TM_YEAR_BASE;
577    if (tp->tm_year != year - TM_YEAR_BASE) {
578        return 0;
579    }
580    tp->tm_yday = days;
581    const UINT16 *daysInMonth = g_daysInMonth[IS_LEAP_YEAR(year)];
582    /* valid month value is 0-11 */
583    for (month = 11; days < (long int) daysInMonth[month]; --month) {
584        continue;
585    }
586    days -= daysInMonth[month];
587    tp->tm_mon = month;
588    tp->tm_mday = days + 1;
589    tp->__tm_gmtoff = offset;
590    tp->__tm_zone = NULL;
591    tp->tm_isdst = 0;
592    return 1;
593}
594
595struct tm *gmtime_r(const time_t *timep, struct tm *result)
596{
597    if ((timep == NULL) || (result == NULL)) {
598        errno = EFAULT;
599        return NULL;
600    }
601    if (!ConvertSecs2Utc(*timep, 0, result)) {
602        errno = EINVAL;
603        return NULL;
604    }
605    return result;
606}
607
608struct tm *gmtime(const time_t *timer)
609{
610    static struct tm tm;
611    return gmtime_r(timer, &tm);
612}
613
614struct tm *localtime_r(const time_t *timep, struct tm *result)
615{
616    INT32 ret;
617
618    if ((timep == NULL) || (result == NULL)) {
619        errno = EFAULT;
620        return NULL;
621    }
622
623    if (g_rtcTimeFunc.RtcGetTimezoneHook != NULL) {
624        INT32 tempTimezone = 0;
625        g_rtcTimeFunc.RtcGetTimezoneHook(&tempTimezone);
626        ret = ConvertSecs2Utc(*timep, -tempTimezone, result);
627    } else {
628        ret = ConvertSecs2Utc(*timep, -TIMEZONE, result);
629    }
630
631    if (!ret) {
632        errno = EINVAL;
633        return NULL;
634    }
635    return result;
636}
637
638struct tm *localtime(const time_t *timer)
639{
640    static struct tm tm;
641    return localtime_r(timer, &tm);
642}
643
644static time_t ConvertUtc2Secs(struct tm *tm)
645{
646    time_t seconds = 0;
647    INT32 month = 0;
648    UINT8 leap = 0;
649
650    INT32 year = (EPOCH_YEAR - TM_YEAR_BASE);
651    while (year < tm->tm_year) {
652        seconds += SECS_PER_NORMAL_YEAR;
653        if (IS_LEAP_YEAR(year + TM_YEAR_BASE)) {
654            seconds += SECS_PER_DAY;
655        }
656        year++;
657    }
658
659    if (IS_LEAP_YEAR(tm->tm_year + TM_YEAR_BASE)) {
660        leap = 1;
661    }
662    while (month < tm->tm_mon) {
663        if ((month == 1) && leap) {
664            seconds += (g_montbl[month] + 1) * SECS_PER_DAY;
665        } else {
666            seconds += g_montbl[month] * SECS_PER_DAY;
667        }
668        month++;
669    }
670
671    seconds += (tm->tm_mday - 1) * SECS_PER_DAY;
672    seconds += tm->tm_hour * SECS_PER_HOUR + tm->tm_min * SECS_PER_MIN + tm->tm_sec;
673
674    if (g_rtcTimeFunc.RtcGetTimezoneHook != NULL) {
675        INT32 tempTimezone = 0;
676        g_rtcTimeFunc.RtcGetTimezoneHook(&tempTimezone);
677        seconds += tempTimezone;
678    } else {
679        seconds += TIMEZONE;
680    }
681
682    return seconds;
683}
684
685time_t mktime(struct tm *tmptr)
686{
687    time_t timeInSeconds;
688    if (tmptr == NULL) {
689        errno = EFAULT;
690        return (time_t)-1;
691    }
692
693    /* tm_isdst is not supported and is ignored */
694    if (tmptr->tm_year < (EPOCH_YEAR - TM_YEAR_BASE) ||
695            tmptr->__tm_gmtoff > (-TIME_ZONE_MIN * SECS_PER_MIN) ||
696            tmptr->__tm_gmtoff < (-TIME_ZONE_MAX * SECS_PER_MIN) ||
697            tmptr->tm_sec > 60 || tmptr->tm_sec < 0 ||      /* Seconds [0-60] */
698            tmptr->tm_min > 59 || tmptr->tm_min < 0 ||      /* Minutes [0-59] */
699            tmptr->tm_hour > 23 || tmptr->tm_hour < 0 ||    /* Hours [0-23] */
700            tmptr->tm_mday > 31 || tmptr->tm_mday < 1 ||    /* Day of the month [1-31] */
701            tmptr->tm_mon > 11 || tmptr->tm_mon < 0) {      /* Month [0-11] */
702        errno = EOVERFLOW;
703        return (time_t)-1;
704    }
705    timeInSeconds = ConvertUtc2Secs(tmptr);
706    /* normalize tm_wday and tm_yday */
707    if (g_rtcTimeFunc.RtcGetTimezoneHook != NULL) {
708        INT32 tempTimezone = 0;
709        g_rtcTimeFunc.RtcGetTimezoneHook(&tempTimezone);
710        ConvertSecs2Utc(timeInSeconds, -tempTimezone, tmptr);
711    } else {
712        ConvertSecs2Utc(timeInSeconds, -TIMEZONE, tmptr);
713    }
714
715    return timeInSeconds;
716}
717
718int gettimeofday(struct timeval *tv, void *ptz)
719{
720    struct timezone *tz = (struct timezone *)ptz;
721
722    if (tv != NULL) {
723        UINT64 usec = 0;
724
725        if ((g_rtcTimeFunc.RtcGetTimeHook != NULL) && (g_rtcTimeFunc.RtcGetTimeHook(&usec) == 0)) {
726            tv->tv_sec = usec / OS_SYS_US_PER_SECOND;
727            tv->tv_usec = usec % OS_SYS_US_PER_SECOND;
728        } else {
729            struct timespec ts;
730            if (-1 == clock_gettime(CLOCK_REALTIME, &ts)) {
731                return -1;
732            }
733            tv->tv_sec = ts.tv_sec;
734            tv->tv_usec = ts.tv_nsec / OS_SYS_NS_PER_US;
735        }
736    }
737
738    if (tz != NULL) {
739        if (g_rtcTimeFunc.RtcGetTimezoneHook != NULL) {
740            INT32 tempTimezone = 0;
741            g_rtcTimeFunc.RtcGetTimezoneHook(&tempTimezone);
742            tz->tz_minuteswest = tempTimezone / SECS_PER_MIN;
743        } else {
744            tz->tz_minuteswest = TIMEZONE / SECS_PER_MIN;
745        }
746
747        tz->tz_dsttime = 0;
748    }
749    return 0;
750}
751#if (LOSCFG_LIBC_NEWLIB == 1)
752FUNC_ALIAS(gettimeofday, _gettimeofday, (struct timeval *tv, void *ptz), int);
753#endif
754
755int settimeofday(const struct timeval *tv, const struct timezone *tz)
756{
757    struct timespec ts;
758
759    if ((tv == NULL) && (tz == NULL)) {
760        errno = EFAULT;
761        return -1;
762    }
763
764    if ((tv != NULL) && (tv->tv_usec >= OS_SYS_US_PER_SECOND)) {
765        errno = EINVAL;
766        return -1;
767    }
768
769    if (tz != NULL) {
770        if ((tz->tz_minuteswest >= TIME_ZONE_MIN) &&
771            (tz->tz_minuteswest <= TIME_ZONE_MAX)) {
772            TIMEZONE = tz->tz_minuteswest * SECS_PER_MIN;
773        } else {
774            errno = EINVAL;
775            return -1;
776        }
777
778        if (g_rtcTimeFunc.RtcSetTimezoneHook != NULL) {
779            g_rtcTimeFunc.RtcSetTimezoneHook(TIMEZONE);
780        }
781    }
782
783    if (tv != NULL) {
784        if (g_rtcTimeFunc.RtcSetTimeHook != NULL) {
785            UINT64 usec;
786            g_rtcTimeBase = tv->tv_sec * OS_SYS_MS_PER_SECOND + tv->tv_usec / OS_SYS_MS_PER_SECOND;
787            usec = tv->tv_sec * OS_SYS_US_PER_SECOND + tv->tv_usec;
788            if (g_rtcTimeFunc.RtcSetTimeHook(g_rtcTimeBase, &usec) < 0) {
789                return -1;
790            }
791        } else {
792            ts.tv_sec = tv->tv_sec;
793            ts.tv_nsec = tv->tv_usec * OS_SYS_NS_PER_US;
794            if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
795                return -1;
796            }
797        }
798    }
799
800    if (g_rtcTimeFunc.RtcGetTickHook != NULL) {
801        g_systickBase = g_rtcTimeFunc.RtcGetTickHook();
802    }
803
804    return 0;
805}
806
807int usleep(useconds_t useconds)
808{
809    struct timespec specTime = { 0 };
810    UINT64 nanoseconds = (UINT64)useconds * OS_SYS_NS_PER_US;
811
812    specTime.tv_sec = (time_t)(nanoseconds / OS_SYS_NS_PER_SECOND);
813    specTime.tv_nsec = (long)(nanoseconds % OS_SYS_NS_PER_SECOND);
814    return nanosleep(&specTime, NULL);
815}
816
817unsigned sleep(unsigned seconds)
818{
819    struct timespec specTime = { 0 };
820    UINT64 nanoseconds = (UINT64)seconds * OS_SYS_NS_PER_SECOND;
821
822    specTime.tv_sec = (time_t)(nanoseconds / OS_SYS_NS_PER_SECOND);
823    specTime.tv_nsec = (long)(nanoseconds % OS_SYS_NS_PER_SECOND);
824    return nanosleep(&specTime, NULL);
825}
826
827clock_t times(struct tms *tms)
828{
829    clock_t clockTick = (clock_t)LOS_TickCountGet();
830
831    if (tms != NULL) {
832        tms->tms_cstime = clockTick;
833        tms->tms_cutime = clockTick;
834        tms->tms_stime  = clockTick;
835        tms->tms_utime  = clockTick;
836    }
837    return clockTick;
838}
839