Browse Source

!612 实现 timer 相关函数
Merge pull request !612 from kang/timer

bernard 2 years ago
parent
commit
d248f1f712
5 changed files with 372 additions and 64 deletions
  1. 287 40
      components/libc/time/clock_time.c
  2. 15 0
      components/libc/time/clock_time.h
  3. 65 24
      components/lwp/lwp_syscall.c
  4. 1 0
      include/rtdef.h
  5. 4 0
      src/timer.c

+ 287 - 40
components/libc/time/clock_time.c

@@ -12,6 +12,7 @@
 #include <rtdevice.h>
 #include <rtdevice.h>
 #include <time.h>
 #include <time.h>
 #include "clock_time.h"
 #include "clock_time.h"
+#include "lwp.h"
 
 
 static struct timeval _timevalue;
 static struct timeval _timevalue;
 int clock_time_system_init()
 int clock_time_system_init()
@@ -82,7 +83,7 @@ int clock_getres(clockid_t clockid, struct timespec *res)
     if (res == RT_NULL)
     if (res == RT_NULL)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return -1;
+        return -RT_ERROR;
     }
     }
 
 
     switch (clockid)
     switch (clockid)
@@ -101,7 +102,7 @@ int clock_getres(clockid_t clockid, struct timespec *res)
 #endif
 #endif
 
 
     default:
     default:
-        ret = -1;
+        ret = -RT_ERROR;
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
         break;
         break;
     }
     }
@@ -117,7 +118,7 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
     if (tp == RT_NULL)
     if (tp == RT_NULL)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return -1;
+        return -RT_ERROR;
     }
     }
 
 
     switch (clockid)
     switch (clockid)
@@ -149,7 +150,7 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
 #endif
 #endif
     default:
     default:
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        ret = -1;
+        ret = -RT_ERROR;
     }
     }
 
 
     return ret;
     return ret;
@@ -166,7 +167,7 @@ int clock_settime(clockid_t clockid, const struct timespec *tp)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
 
 
-        return -1;
+        return -RT_ERROR;
     }
     }
 
 
     /* get second */
     /* get second */
@@ -186,7 +187,7 @@ int clock_settime(clockid_t clockid, const struct timespec *tp)
         rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second);
         rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second);
     }
     }
     else
     else
-        return -1;
+        return -RT_ERROR;
 
 
     return 0;
     return 0;
 }
 }
@@ -194,10 +195,10 @@ RTM_EXPORT(clock_settime);
 
 
 int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
 int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
 {
 {
-    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000)
+    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return -1;
+        return -RT_ERROR;
     }
     }
     switch (clockid)
     switch (clockid)
     {
     {
@@ -206,20 +207,27 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s
         rt_tick_t tick;
         rt_tick_t tick;
         if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
         if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
         {
         {
-            tick = (rqtp->tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec - _timevalue.tv_usec) * RT_TICK_PER_SECOND) / 1000000000;
+            tick = (rqtp->tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND + (rqtp->tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
             rt_tick_t rt_tick = rt_tick_get();
             rt_tick_t rt_tick = rt_tick_get();
             tick = tick < rt_tick ? 0 : tick - rt_tick;
             tick = tick < rt_tick ? 0 : tick - rt_tick;
         }
         }
         else
         else
         {
         {
-            tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec) * RT_TICK_PER_SECOND) / 1000000000;
+            tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec) * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
         }
         }
         rt_thread_delay(tick);
         rt_thread_delay(tick);
-        if (rmtp)
+
+        if (rt_get_errno() == -RT_EINTR)
         {
         {
-            tick = rt_tick_get() - tick;
-            rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
-            rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (1000000000 / RT_TICK_PER_SECOND);
+            if (rmtp)
+            {
+                tick = rt_tick_get() - tick;
+                /* get the passed time */
+                rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
+                rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+            }
+            rt_set_errno(EINTR);
+            return -RT_ERROR;
         }
         }
     }
     }
     break;
     break;
@@ -233,26 +241,31 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, s
         rt_tick_t tick;
         rt_tick_t tick;
         float unit = clock_cpu_getres();
         float unit = clock_cpu_getres();
 
 
-        cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / 1000000000) / unit;
+        cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec * (NANOSECOND_PER_SECOND / NANOSECOND_PER_SECOND)) / unit;
         if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
         if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
             cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old;
             cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old;
-        tick = cpu_tick / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+        tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
         rt_thread_delay(tick);
         rt_thread_delay(tick);
 
 
-        if (rmtp)
+        if (rt_get_errno() == -RT_EINTR)
         {
         {
-            uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
-            rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
-            rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+            if (rmtp)
+            {
+                uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+                rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
+                rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+            }
+            rt_set_errno(EINTR);
+            return -RT_ERROR;
         }
         }
-
-        while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
+        else
+            while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
     }
     }
     break;
     break;
 #endif
 #endif
     default:
     default:
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return -1;
+        return -RT_ERROR;
     }
     }
 
 
     return 0;
     return 0;
@@ -261,10 +274,10 @@ RTM_EXPORT(clock_nanosleep);
 
 
 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
 {
 {
-    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000)
+    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return -1;
+        return -RT_ERROR;
     }
     }
 #ifdef RT_USING_CPUTIME
 #ifdef RT_USING_CPUTIME
     uint64_t cpu_tick, cpu_tick_old;
     uint64_t cpu_tick, cpu_tick_old;
@@ -272,31 +285,265 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
     rt_tick_t tick;
     rt_tick_t tick;
     float unit = clock_cpu_getres();
     float unit = clock_cpu_getres();
 
 
-    cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / 1000000000)/unit;
-    tick = cpu_tick  / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+    cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / NANOSECOND_PER_SECOND)/unit;
+    tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
     rt_thread_delay(tick);
     rt_thread_delay(tick);
 
 
-    if (rmtp)
+    if (rt_get_errno() == -RT_EINTR)
     {
     {
-        uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
-        rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
-        rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+        if (rmtp)
+        {
+            uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+            rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
+            rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+        }
+        rt_set_errno(EINTR);
+        return -RT_ERROR;
     }
     }
-
-    while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
+    else
+        while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
 #else
 #else
     rt_tick_t tick;
     rt_tick_t tick;
-    tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / 1000000000;
+    tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
     rt_thread_delay(tick);
     rt_thread_delay(tick);
 
 
-    if (rmtp)
+    if (rt_get_errno() == -RT_EINTR)
     {
     {
-        tick = rt_tick_get() - tick;
-        /* get the passed time */
-        rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
-        rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (1000000000 / RT_TICK_PER_SECOND);
+        if (rmtp)
+        {
+            tick = rt_tick_get() - tick;
+            /* get the passed time */
+            rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
+            rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+        }
+        rt_set_errno(EINTR);
+        return -RT_ERROR;
     }
     }
 #endif
 #endif
     return 0;
     return 0;
 }
 }
-RTM_EXPORT(nanosleep);
+RTM_EXPORT(nanosleep);
+
+static void rtthread_timer_wrapper(void *timerobj)
+{
+    struct timer_obj *timer;
+
+    timer = (struct timer_obj *)timerobj;
+    sys_kill(timer->pid, timer->sigev_signo);
+
+    if (timer->reload == 0U)
+    {
+        timer->status = NOT_ACTIVE;
+    }
+
+    // if (timer->sigev_notify_function != RT_NULL)
+    // {
+    //     (timer->sigev_notify_function)(timer->val);
+    // }
+
+    timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
+    rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
+}
+
+int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
+{
+    static int num = 0;
+    struct timer_obj *timer;
+    char timername[RT_NAME_MAX] = {0};
+
+    if (clockid > CLOCK_TAI || evp->sigev_notify != SIGEV_NONE && evp->sigev_notify != SIGEV_SIGNAL)
+    {
+        rt_set_errno(EINVAL);
+        return -RT_ERROR;
+    }
+
+    timer = rt_malloc(sizeof(struct timer_obj));
+    if (timer == RT_NULL)
+    {
+        rt_set_errno(ENOMEM);
+        return -RT_ENOMEM;
+    }
+
+    rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
+    num %= 100;
+    timer->sigev_signo = evp->sigev_signo;
+    timer->pid = lwp_self()->pid;
+    timer->sigev_notify_function = evp->sigev_notify_function;
+    timer->val = evp->sigev_value;
+    timer->interval.tv_sec = 0;
+    timer->interval.tv_nsec = 0;
+    timer->reload = 0U;
+    timer->status = NOT_ACTIVE;
+
+    if (evp->sigev_notify == SIGEV_NONE)
+    {
+        rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
+    }
+    else
+    {
+        rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
+    }
+
+    *timerid = (timer_t)((uintptr_t)timer >> 1);
+
+    return RT_EOK;
+}
+RTM_EXPORT(timer_create);
+
+int timer_delete(timer_t timerid)
+{
+    struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
+
+    if (timer == RT_NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
+    {
+        rt_set_errno(EINVAL);
+        return -RT_ERROR;
+    }
+
+    if (timer->status == ACTIVE)
+    {
+        timer->status = NOT_ACTIVE;
+        rt_timer_stop(&timer->timer);
+    }
+    rt_timer_detach(&timer->timer);
+    rt_free(timer);
+    return RT_EOK;
+}
+RTM_EXPORT(timer_delete);
+
+int timer_getoverrun(timer_t timerid)
+{
+    struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
+    rt_set_errno(ENOSYS);
+    return -RT_ERROR;
+}
+
+int timer_gettime(timer_t timerid, struct itimerspec *its)
+{
+    struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
+    rt_tick_t remaining;
+    rt_uint32_t seconds, nanoseconds;
+
+    if (timer == NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
+    {
+        rt_set_errno(EINVAL);
+        return -RT_ERROR;
+    }
+
+    if (its == NULL)
+    {
+        rt_set_errno(EFAULT);
+        return -RT_ERROR;
+    }
+
+    if (timer->status == ACTIVE)
+    {
+        rt_tick_t remain_tick;
+
+        rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick);
+
+        /* 'remain_tick' is minimum-unit in the RT-Thread' timer,
+         * so the seconds, nanoseconds will be calculated by 'remain_tick'.
+         */
+        remaining = remain_tick - rt_tick_get();
+
+        /* calculate 'second' */
+        seconds = remaining / RT_TICK_PER_SECOND;
+
+        /* calculate 'nanosecond';  To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on.
+         *
+         *        remain_tick                  millisecond                                 remain_tick * MILLISECOND_PER_SECOND
+         *  ------------------------- = --------------------------  --->  millisecond = -------------------------------------------
+         *    RT_TICK_PER_SECOND          MILLISECOND_PER_SECOND                                RT_TICK_PER_SECOND
+         *
+         *                    remain_tick * MILLISECOND_PER_SECOND                          remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND
+         *   millisecond = ----------------------------------------  ---> nanosecond = -------------------------------------------------------------------
+         *                         RT_TICK_PER_SECOND                                                           RT_TICK_PER_SECOND
+         *
+         */
+        nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND;
+
+        its->it_value.tv_sec = (rt_int32_t)seconds;
+        its->it_value.tv_nsec = (rt_int32_t)nanoseconds;
+    }
+    else
+    {
+        /* Timer is disarmed */
+        its->it_value.tv_sec = 0;
+        its->it_value.tv_nsec = 0;
+    }
+
+    /* The interval last set by timer_settime() */
+    its->it_interval = timer->interval;
+    return RT_EOK;
+}
+RTM_EXPORT(timer_gettime);
+
+int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
+                  struct itimerspec *ovalue)
+{
+    struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
+    if (timer == NULL ||
+        rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer ||
+        value->it_interval.tv_nsec < 0 ||
+        value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND ||
+        value->it_interval.tv_sec < 0 ||
+        value->it_value.tv_nsec < 0 ||
+        value->it_value.tv_nsec >= NANOSECOND_PER_SECOND ||
+        value->it_value.tv_sec < 0)
+    {
+        rt_set_errno(EINVAL);
+        return -RT_ERROR;
+    }
+
+    /*  Save time to expire and old reload value. */
+    if (ovalue != NULL)
+    {
+        timer_gettime(timerid, ovalue);
+    }
+
+    /* Stop the timer if the value is 0 */
+    if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0))
+    {
+        if (timer->status == ACTIVE)
+        {
+            rt_timer_stop(&timer->timer);
+        }
+
+        timer->status = NOT_ACTIVE;
+        return RT_EOK;
+    }
+    
+    if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
+    {
+        rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND);
+        rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
+        rt_int64_t reload = ts + tns;
+        rt_tick_t rt_tick = rt_tick_get();
+        timer->reload = reload < rt_tick ? 0 : reload - rt_tick;
+    }
+    else
+        timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
+    timer->interval.tv_sec = value->it_interval.tv_sec;
+    timer->interval.tv_nsec = value->it_interval.tv_nsec;
+    timer->value.tv_sec = value->it_value.tv_sec;
+    timer->value.tv_nsec = value->it_value.tv_nsec;
+
+    if (timer->status == ACTIVE)
+    {
+        rt_timer_stop(&timer->timer);
+    }
+
+    timer->status = ACTIVE;
+
+    if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0))
+        rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL);
+    else
+        rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
+
+    rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
+    rt_timer_start(&timer->timer);
+
+    return RT_EOK;
+}
+RTM_EXPORT(timer_settime);

+ 15 - 0
components/libc/time/clock_time.h

@@ -41,6 +41,21 @@ extern "C" {
 #define CLOCK_MONOTONIC     4
 #define CLOCK_MONOTONIC     4
 #endif
 #endif
 
 
+#define ACTIVE 1
+#define NOT_ACTIVE 0
+struct timer_obj
+{
+    struct rt_timer timer;
+    void (*sigev_notify_function)(union sigval val);
+    union sigval val;
+    struct timespec interval;              /* Reload value */
+    struct timespec value;              /* Reload value */
+    rt_uint32_t reload;                    /* Reload value in ms */
+    rt_uint32_t status;
+    int sigev_signo;
+    pid_t pid;
+};
+
 int clock_getres  (clockid_t clockid, struct timespec *res);
 int clock_getres  (clockid_t clockid, struct timespec *res);
 int clock_gettime (clockid_t clockid, struct timespec *tp);
 int clock_gettime (clockid_t clockid, struct timespec *tp);
 int clock_settime (clockid_t clockid, const struct timespec *tp);
 int clock_settime (clockid_t clockid, const struct timespec *tp);

+ 65 - 24
components/lwp/lwp_syscall.c

@@ -920,7 +920,7 @@ int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
     
     
     lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
     lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
     ret = nanosleep(&rqtp_k, &rmtp_k);
     ret = nanosleep(&rqtp_k, &rmtp_k);
-    if (ret != -1 && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+    if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
         lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
         lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
 #else
 #else
     if (rmtp)
     if (rmtp)
@@ -1231,38 +1231,79 @@ static void timer_timeout_callback(void *parameter)
     rt_sem_release(sem);
     rt_sem_release(sem);
 }
 }
 
 
-rt_timer_t sys_timer_create(const char *name,
-        void *data,
-        rt_tick_t   time,
-        rt_uint8_t  flag)
+rt_err_t sys_timer_create(clockid_t clockid, struct sigevent *restrict sevp, timer_t *restrict timerid)
 {
 {
-    rt_timer_t timer = rt_timer_create(name, timer_timeout_callback, (void *)data, time, flag);
-    if (lwp_user_object_add(lwp_self(), (rt_object_t)timer) != 0)
+    int ret = 0;
+#ifdef RT_USING_USERSPACE
+    struct sigevent sevp_k;
+    timer_t timerid_k;
+    struct sigevent evp_default;
+    if (sevp == NULL)
     {
     {
-        rt_timer_delete(timer);
-        timer = NULL;
+        sevp_k.sigev_notify = SIGEV_SIGNAL;
+        sevp_k.sigev_signo = SIGALRM;
+        sevp = &sevp_k;
+    }
+    else
+        lwp_get_from_user(&sevp_k, (void *)sevp, sizeof sevp_k);
+    lwp_get_from_user(&timerid_k, (void *)timerid, sizeof timerid_k);
+    ret = timer_create(clockid, &sevp_k, &timerid_k);
+    if (ret != -RT_ERROR){
+        lwp_put_to_user(sevp, (void *)&sevp_k, sizeof sevp_k);
+        lwp_put_to_user(timerid, (void *)&timerid_k, sizeof timerid_k);
     }
     }
-    return timer;
+#else
+    ret = timer_create(clockid, sevp, timerid);
+#endif
+    return (ret < 0 ? GET_ERRNO() : ret);
 }
 }
 
 
-rt_err_t sys_timer_delete(rt_timer_t timer)
+rt_err_t sys_timer_delete(timer_t timerid)
 {
 {
-    return lwp_user_object_delete(lwp_self(), (rt_object_t)timer);
+    int ret = timer_delete(timerid);
+    return (ret < 0 ? GET_ERRNO() : ret);
 }
 }
 
 
-rt_err_t sys_timer_start(rt_timer_t timer)
+rt_err_t sys_timer_settime(timer_t timerid, int flags,
+                           const struct itimerspec *restrict new_value,
+                           struct itimerspec *restrict old_value)
 {
 {
-    return rt_timer_start(timer);
+    int ret = 0;
+#ifdef RT_USING_USERSPACE
+    struct itimerspec new_value_k;
+    struct itimerspec old_value_k;
+
+    lwp_get_from_user(&new_value_k, (void *)new_value, sizeof new_value_k);
+    lwp_get_from_user(&old_value_k, (void *)timerid, sizeof old_value_k);
+    ret = timer_settime(timerid, flags, &new_value_k, &old_value_k);
+    lwp_put_to_user(old_value, (void *)&old_value_k, sizeof old_value_k);
+
+#else
+    ret = timer_settime(timerid, flags, new_value, old_value);
+#endif
+    return (ret < 0 ? GET_ERRNO() : ret);
 }
 }
 
 
-rt_err_t sys_timer_stop(rt_timer_t timer)
+rt_err_t sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
 {
 {
-    return rt_timer_stop(timer);
+    int ret = 0;
+#ifdef RT_USING_USERSPACE
+
+    struct itimerspec curr_value_k;
+    lwp_get_from_user(&curr_value_k, (void *)curr_value, sizeof curr_value_k);
+    ret = timer_gettime(timerid, &curr_value_k);
+    lwp_put_to_user(curr_value, (void *)&curr_value_k, sizeof curr_value_k);
+#else
+    ret = timer_gettime(timerid, curr_value);
+#endif
+    return (ret < 0 ? GET_ERRNO() : ret);
 }
 }
 
 
-rt_err_t sys_timer_control(rt_timer_t timer, int cmd, void *arg)
+rt_err_t sys_timer_getoverrun(timer_t timerid)
 {
 {
-    return rt_timer_control(timer, cmd, arg);
+    int ret = 0;
+    ret = timer_getoverrun(timerid);
+    return (ret < 0 ? GET_ERRNO() : ret);
 }
 }
 
 
 rt_thread_t sys_thread_create(void *arg[])
 rt_thread_t sys_thread_create(void *arg[])
@@ -1579,7 +1620,7 @@ static int lwp_copy_files(struct rt_lwp *dst, struct rt_lwp *src)
         dfs_fd_unlock();
         dfs_fd_unlock();
         return 0;
         return 0;
     }
     }
-    return -1;
+    return -RT_ERROR;
 }
 }
 
 
 int _sys_fork(void)
 int _sys_fork(void)
@@ -1848,7 +1889,7 @@ static char *_load_script(const char *filename, struct lwp_args_info *args)
 {
 {
     void *page = NULL;
     void *page = NULL;
     char *new_page;
     char *new_page;
-    int fd = -1;
+    int fd = -RT_ERROR;
     int len;
     int len;
     char interp[INTERP_BUF_SIZE];
     char interp[INTERP_BUF_SIZE];
     char *cp;
     char *cp;
@@ -3791,7 +3832,7 @@ int sys_clock_nanosleep(clockid_t clk, int flags, const struct timespec *rqtp, s
 
 
     lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
     lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
     ret = clock_nanosleep(clk, flags, &rqtp_k, &rmtp_k);
     ret = clock_nanosleep(clk, flags, &rqtp_k, &rmtp_k);
-    if (ret != -1 && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+    if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
         lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
         lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
 #else
 #else
     if (rmtp)
     if (rmtp)
@@ -4255,9 +4296,9 @@ const static void* func_table[] =
 
 
     SYSCALL_SIGN(sys_timer_create),
     SYSCALL_SIGN(sys_timer_create),
     SYSCALL_SIGN(sys_timer_delete),
     SYSCALL_SIGN(sys_timer_delete),
-    SYSCALL_SIGN(sys_timer_start),
-    SYSCALL_SIGN(sys_timer_stop),
-    SYSCALL_SIGN(sys_timer_control),  /* 115 */
+    SYSCALL_SIGN(sys_timer_settime),
+    SYSCALL_SIGN(sys_timer_gettime),
+    SYSCALL_SIGN(sys_timer_getoverrun),  /* 115 */
     SYSCALL_SIGN(sys_getcwd),
     SYSCALL_SIGN(sys_getcwd),
     SYSCALL_SIGN(sys_chdir),
     SYSCALL_SIGN(sys_chdir),
     SYSCALL_SIGN(sys_unlink),
     SYSCALL_SIGN(sys_unlink),

+ 1 - 0
include/rtdef.h

@@ -462,6 +462,7 @@ struct rt_object_information
 #define RT_TIMER_CTRL_SET_FUNC          0x6             /**< set timer timeout func  */
 #define RT_TIMER_CTRL_SET_FUNC          0x6             /**< set timer timeout func  */
 #define RT_TIMER_CTRL_GET_PARM          0x7             /**< get timer parameter  */
 #define RT_TIMER_CTRL_GET_PARM          0x7             /**< get timer parameter  */
 #define RT_TIMER_CTRL_SET_PARM          0x8             /**< get timer parameter  */
 #define RT_TIMER_CTRL_SET_PARM          0x8             /**< get timer parameter  */
+#define RT_TIMER_CTRL_GET_REMAIN_TIME   0x9             /**< get timer remain time  */
 
 
 #ifndef RT_TIMER_SKIP_LIST_LEVEL
 #ifndef RT_TIMER_SKIP_LIST_LEVEL
 #define RT_TIMER_SKIP_LIST_LEVEL          1
 #define RT_TIMER_SKIP_LIST_LEVEL          1

+ 4 - 0
src/timer.c

@@ -529,6 +529,10 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
         timer->parameter = arg;
         timer->parameter = arg;
         break;
         break;
 
 
+    case RT_TIMER_CTRL_GET_REMAIN_TIME:
+        *(rt_tick_t *)arg = timer->timeout_tick;
+        break;
+
     default:
     default:
         break;
         break;
     }
     }