Browse Source

Fixed issues with timerfd (#8102)

zmq810150896 1 year ago
parent
commit
a289ae1b18
1 changed files with 99 additions and 54 deletions
  1. 99 54
      components/libc/posix/io/timerfd/timerfd.c

+ 99 - 54
components/libc/posix/io/timerfd/timerfd.c

@@ -35,8 +35,9 @@ struct rt_timerfd
     rt_timer_t timer;
     rt_timer_t timer;
     struct rt_mutex lock;
     struct rt_mutex lock;
     struct timespec pre_time;
     struct timespec pre_time;
-    rt_uint64_t timeout_num;
-    int ticks;
+    rt_atomic_t timeout_num;
+    struct rt_wqueue_node wqn;
+    rt_atomic_t ticks;
     int clockid;
     int clockid;
     int isperiodic;
     int isperiodic;
     int tick_out;
     int tick_out;
@@ -75,6 +76,8 @@ static int timerfd_close(struct dfs_file *file)
             tfd->timer = RT_NULL;
             tfd->timer = RT_NULL;
         }
         }
 
 
+        rt_wqueue_remove(&tfd->wqn);
+
         rt_mutex_detach(&tfd->lock);
         rt_mutex_detach(&tfd->lock);
         rt_free(tfd);
         rt_free(tfd);
     }
     }
@@ -93,11 +96,11 @@ static int timerfd_poll(struct dfs_file *file, struct rt_pollreq *req)
 
 
     rt_poll_add(&tfd->timerfd_queue, req);
     rt_poll_add(&tfd->timerfd_queue, req);
 
 
-    if (tfd->ticks)
-        events |= POLLIN;
-
     rt_mutex_release(&tfd->lock);
     rt_mutex_release(&tfd->lock);
 
 
+    if (rt_atomic_load(&(tfd->ticks)) > 0)
+        events |= POLLIN;
+
     return events;
     return events;
 }
 }
 
 
@@ -109,6 +112,7 @@ static ssize_t timerfd_read(struct dfs_file *file, void *buf, size_t count, off_
 {
 {
     struct rt_timerfd *tfd;
     struct rt_timerfd *tfd;
     rt_uint64_t *buffer;
     rt_uint64_t *buffer;
+    int ret = 0;
 
 
     buffer = (rt_uint64_t *)buf;
     buffer = (rt_uint64_t *)buf;
 
 
@@ -126,29 +130,45 @@ static ssize_t timerfd_read(struct dfs_file *file, void *buf, size_t count, off_
         return -1;
         return -1;
     }
     }
 
 
-    if ((tfd->ticks == 0) && (file->flags & O_NONBLOCK))
+    if ((rt_atomic_load(&(tfd->ticks)) == 0) && (file->flags & O_NONBLOCK))
     {
     {
         rt_set_errno(EAGAIN);
         rt_set_errno(EAGAIN);
         return -EAGAIN;
         return -EAGAIN;
     }
     }
     else
     else
     {
     {
-        if (tfd->ticks == 0)
+        if (rt_atomic_load(&(tfd->ticks)) == 0)
         {
         {
-            rt_wqueue_wait(&tfd->timerfd_queue, 0, RT_WAITING_FOREVER);
+            tfd->wqn.polling_thread = rt_thread_self();
+
+            rt_wqueue_remove(&tfd->wqn);
+            rt_wqueue_add(&tfd->timerfd_queue, &tfd->wqn);
+
+            ret = rt_thread_suspend_with_flag(tfd->wqn.polling_thread, RT_INTERRUPTIBLE);
+            if (ret == RT_EOK)
+            {
+                rt_schedule();
+            }
+            else
+            {
+                return ret;
+            }
         }
         }
 
 
-        rt_mutex_take(&tfd->lock, RT_WAITING_FOREVER);
-        (*buffer) = tfd->timeout_num;
-        rt_mutex_release(&tfd->lock);
-    }
+        (*buffer) = rt_atomic_load(&(tfd->timeout_num));
 
 
-    tfd->ticks = 0;
+        rt_atomic_store(&(tfd->ticks), 0);
+    }
 
 
     return sizeof(buffer);
     return sizeof(buffer);
 }
 }
 
 
-static int timerfd_create_do(int clockid, int flags)
+static int timerfd_wqueue_callback(struct rt_wqueue_node *wait, void *key)
+{
+    return 0;
+}
+
+static int timerfd_do_create(int clockid, int flags)
 {
 {
     struct rt_timerfd *tfd = RT_NULL;
     struct rt_timerfd *tfd = RT_NULL;
     struct dfs_file *df;
     struct dfs_file *df;
@@ -189,29 +209,32 @@ static int timerfd_create_do(int clockid, int flags)
 
 
         tfd = (struct rt_timerfd *)rt_malloc(sizeof(struct rt_timerfd));
         tfd = (struct rt_timerfd *)rt_malloc(sizeof(struct rt_timerfd));
 
 
-        rt_mutex_init(&tfd->lock, TIMERFD_MUTEX_NAME, RT_IPC_FLAG_FIFO);
-        rt_wqueue_init(&tfd->timerfd_queue);
-
-        tfd->isperiodic = INIT_PERIODIC;
-        tfd->ticks = 0;
-        tfd->timeout_num = 0;
-        tfd->tick_out = 0;
-        tfd->clockid = clockid;
-        tfd->timer = RT_NULL;
-        tfd->pre_time.tv_sec = 0;
-        tfd->pre_time.tv_nsec = 0;
-
         if (tfd)
         if (tfd)
         {
         {
+            rt_mutex_init(&tfd->lock, TIMERFD_MUTEX_NAME, RT_IPC_FLAG_FIFO);
+            rt_wqueue_init(&tfd->timerfd_queue);
+
+            tfd->isperiodic = INIT_PERIODIC;
+            tfd->ticks = 0;
+            tfd->timeout_num = 0;
+            tfd->tick_out = 0;
+            tfd->clockid = clockid;
+            tfd->timer = RT_NULL;
+            tfd->pre_time.tv_sec = 0;
+            tfd->pre_time.tv_nsec = 0;
+            tfd->wqn.polling_thread = rt_thread_self();
+            rt_list_init(&(tfd->wqn.list));
+            tfd->wqn.wakeup = timerfd_wqueue_callback;
+
             df->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode));
             df->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode));
             if (df->vnode)
             if (df->vnode)
             {
             {
                 dfs_vnode_init(df->vnode, FT_REGULAR, &timerfd_fops);
                 dfs_vnode_init(df->vnode, FT_REGULAR, &timerfd_fops);
                 df->vnode->data = tfd;
                 df->vnode->data = tfd;
 
 
-                #ifdef RT_USING_DFS_V2
+#ifdef RT_USING_DFS_V2
                 df->fops = &timerfd_fops;
                 df->fops = &timerfd_fops;
-                #endif
+#endif
             }
             }
             else
             else
             {
             {
@@ -276,17 +299,20 @@ static void timerfd_timeout(void *parameter)
 
 
     rt_wqueue_wakeup(&tfd->timerfd_queue, (void *)POLLIN);
     rt_wqueue_wakeup(&tfd->timerfd_queue, (void *)POLLIN);
 
 
-    rt_mutex_take(&tfd->lock, RT_WAITING_FOREVER);
+    rt_atomic_store(&(tfd->ticks), 1);
+    rt_atomic_add(&(tfd->timeout_num), 1);
 
 
-    tfd->ticks = 1;
-    tfd->timeout_num ++;
+    rt_mutex_take(&tfd->lock, RT_WAITING_FOREVER);
 
 
     get_current_time(tfd, RT_NULL);
     get_current_time(tfd, RT_NULL);
     if (tfd->isperiodic == OPEN_PERIODIC)
     if (tfd->isperiodic == OPEN_PERIODIC)
     {
     {
-        rt_timer_stop(tfd->timer);
-        rt_timer_delete(tfd->timer);
-        tfd->timer = RT_NULL;
+        if (tfd->timer)
+        {
+            rt_timer_stop(tfd->timer);
+            rt_timer_delete(tfd->timer);
+            tfd->timer = RT_NULL;
+        }
         tfd->isperiodic = ENTER_PERIODIC;
         tfd->isperiodic = ENTER_PERIODIC;
         tfd->timer = rt_timer_create(TIMERFD_MUTEX_NAME, timerfd_timeout,
         tfd->timer = rt_timer_create(TIMERFD_MUTEX_NAME, timerfd_timeout,
                         tfd, tfd->tick_out,
                         tfd, tfd->tick_out,
@@ -307,9 +333,15 @@ static void timerfd_time_operation(time_t *sec, long *nsec)
             *nsec = 1 * SEC_TO_NSEC + *nsec;
             *nsec = 1 * SEC_TO_NSEC + *nsec;
         }
         }
     }
     }
+
+    if (*sec < 0 || *nsec < 0)
+    {
+        *sec = 0;
+        *nsec = 0;
+    }
 }
 }
 
 
-static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, struct itimerspec *old)
+static int timerfd_do_settime(int fd, int flags, const struct itimerspec *new, struct itimerspec *old)
 {
 {
     int ret = 0;
     int ret = 0;
     struct rt_timerfd *tfd;
     struct rt_timerfd *tfd;
@@ -331,7 +363,9 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s
         return -EINVAL;
         return -EINVAL;
 
 
     tfd = df->vnode->data;
     tfd = df->vnode->data;
-    tfd->timeout_num = 0;
+
+    rt_atomic_store(&(tfd->ticks), 0);
+    rt_atomic_store(&(tfd->timeout_num), 0);
 
 
     rt_mutex_take(&tfd->lock, RT_WAITING_FOREVER);
     rt_mutex_take(&tfd->lock, RT_WAITING_FOREVER);
     tfd->isperiodic = INIT_PERIODIC;
     tfd->isperiodic = INIT_PERIODIC;
@@ -346,6 +380,18 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s
 
 
     if (new)
     if (new)
     {
     {
+        if (tfd->timer != RT_NULL)
+        {
+            rt_timer_stop(tfd->timer);
+            rt_timer_delete(tfd->timer);
+            tfd->timer = RT_NULL;
+        }
+
+        if (new->it_value.tv_nsec == 0 && new->it_value.tv_sec == 0)
+        {
+            return 0;
+        }
+
         value_msec = (new->it_value.tv_nsec / MSEC_TO_NSEC) + (new->it_value.tv_sec * SEC_TO_MSEC);
         value_msec = (new->it_value.tv_nsec / MSEC_TO_NSEC) + (new->it_value.tv_sec * SEC_TO_MSEC);
         interval_msec = (new->it_interval.tv_nsec / MSEC_TO_NSEC) + (new->it_interval.tv_sec * SEC_TO_MSEC);
         interval_msec = (new->it_interval.tv_nsec / MSEC_TO_NSEC) + (new->it_interval.tv_sec * SEC_TO_MSEC);
 
 
@@ -369,13 +415,16 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s
         tfd->ittimer.it_value.tv_nsec = new->it_value.tv_nsec - current_time.tv_nsec;
         tfd->ittimer.it_value.tv_nsec = new->it_value.tv_nsec - current_time.tv_nsec;
         timerfd_time_operation(&tfd->ittimer.it_value.tv_sec, &tfd->ittimer.it_value.tv_nsec);
         timerfd_time_operation(&tfd->ittimer.it_value.tv_sec, &tfd->ittimer.it_value.tv_nsec);
 
 
-        if (tfd->timer != RT_NULL)
+        if ((interval_msec > 0) && (interval_msec <= TIME_INT32_MAX))
         {
         {
-            rt_timer_stop(tfd->timer);
-            rt_timer_delete(tfd->timer);
-            tfd->timer = RT_NULL;
+            tfd->tick_out = rt_tick_from_millisecond(interval_msec);
+            if (tfd->tick_out < 0)
+                return -EINVAL;
+            tfd->isperiodic = OPEN_PERIODIC;
         }
         }
 
 
+        get_current_time(tfd, RT_NULL);
+
         if (value_msec > 0)
         if (value_msec > 0)
         {
         {
             if (value_msec > TIME_INT32_MAX)
             if (value_msec > TIME_INT32_MAX)
@@ -385,20 +434,15 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s
             if (tick_out < 0)
             if (tick_out < 0)
                 return -EINVAL;
                 return -EINVAL;
 
 
-            if ((interval_msec > 0) && (interval_msec <= TIME_INT32_MAX))
-            {
-                tfd->tick_out = rt_tick_from_millisecond(interval_msec);
-                if (tfd->tick_out < 0)
-                    return -EINVAL;
-                tfd->isperiodic = OPEN_PERIODIC;
-            }
-
-            get_current_time(tfd, RT_NULL);
             tfd->timer = rt_timer_create(TIMERFD_MUTEX_NAME, timerfd_timeout,
             tfd->timer = rt_timer_create(TIMERFD_MUTEX_NAME, timerfd_timeout,
                             tfd, tick_out,
                             tfd, tick_out,
                             RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
                             RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
              rt_timer_start(tfd->timer);
              rt_timer_start(tfd->timer);
         }
         }
+        else
+        {
+            timerfd_timeout(tfd);
+        }
     }
     }
     else
     else
     {
     {
@@ -411,7 +455,7 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s
     return ret;
     return ret;
 }
 }
 
 
-static int timerfd_gettime_do(int fd, struct itimerspec *cur)
+static int timerfd_do_gettime(int fd, struct itimerspec *cur)
 {
 {
     struct rt_timerfd *tfd;
     struct rt_timerfd *tfd;
     struct dfs_file *df = RT_NULL;
     struct dfs_file *df = RT_NULL;
@@ -443,10 +487,11 @@ static int timerfd_gettime_do(int fd, struct itimerspec *cur)
     {
     {
         cur->it_value.tv_nsec = tfd->ittimer.it_interval.tv_nsec - tv_nsec;
         cur->it_value.tv_nsec = tfd->ittimer.it_interval.tv_nsec - tv_nsec;
         cur->it_value.tv_sec = tfd->ittimer.it_interval.tv_sec - tv_sec;
         cur->it_value.tv_sec = tfd->ittimer.it_interval.tv_sec - tv_sec;
+        timerfd_time_operation(&cur->it_value.tv_sec, &cur->it_value.tv_nsec);
     }
     }
     else
     else
     {
     {
-        if (tfd->timeout_num == 1)
+        if (rt_atomic_load(&(tfd->timeout_num)) == 1)
         {
         {
             cur->it_value.tv_nsec = 0;
             cur->it_value.tv_nsec = 0;
             cur->it_value.tv_sec = 0;
             cur->it_value.tv_sec = 0;
@@ -466,15 +511,15 @@ static int timerfd_gettime_do(int fd, struct itimerspec *cur)
 
 
 int timerfd_create(int clockid, int flags)
 int timerfd_create(int clockid, int flags)
 {
 {
-    return timerfd_create_do(clockid, flags);
+    return timerfd_do_create(clockid, flags);
 }
 }
 
 
 int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itimerspec *old)
 int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itimerspec *old)
 {
 {
-    return timerfd_settime_do(fd, flags, new, old);
+    return timerfd_do_settime(fd, flags, new, old);
 }
 }
 
 
 int timerfd_gettime(int fd, struct itimerspec *cur)
 int timerfd_gettime(int fd, struct itimerspec *cur)
 {
 {
-    return timerfd_gettime_do(fd, cur);
+    return timerfd_do_gettime(fd, cur);
 }
 }