From a289ae1b186b8a0d64f77b0a2387c1693ab473e8 Mon Sep 17 00:00:00 2001 From: zmq810150896 <50894086+zmq810150896@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:20:50 +0800 Subject: [PATCH] Fixed issues with timerfd (#8102) --- components/libc/posix/io/timerfd/timerfd.c | 153 +++++++++++++-------- 1 file changed, 99 insertions(+), 54 deletions(-) diff --git a/components/libc/posix/io/timerfd/timerfd.c b/components/libc/posix/io/timerfd/timerfd.c index 06ded7b595..980c8f81e3 100644 --- a/components/libc/posix/io/timerfd/timerfd.c +++ b/components/libc/posix/io/timerfd/timerfd.c @@ -35,8 +35,9 @@ struct rt_timerfd rt_timer_t timer; struct rt_mutex lock; 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 isperiodic; int tick_out; @@ -75,6 +76,8 @@ static int timerfd_close(struct dfs_file *file) tfd->timer = RT_NULL; } + rt_wqueue_remove(&tfd->wqn); + rt_mutex_detach(&tfd->lock); 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); - if (tfd->ticks) - events |= POLLIN; - rt_mutex_release(&tfd->lock); + if (rt_atomic_load(&(tfd->ticks)) > 0) + events |= POLLIN; + 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; rt_uint64_t *buffer; + int ret = 0; 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; } - if ((tfd->ticks == 0) && (file->flags & O_NONBLOCK)) + if ((rt_atomic_load(&(tfd->ticks)) == 0) && (file->flags & O_NONBLOCK)) { rt_set_errno(EAGAIN); return -EAGAIN; } 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); } -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 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)); - 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) { + 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)); if (df->vnode) { dfs_vnode_init(df->vnode, FT_REGULAR, &timerfd_fops); df->vnode->data = tfd; - #ifdef RT_USING_DFS_V2 +#ifdef RT_USING_DFS_V2 df->fops = &timerfd_fops; - #endif +#endif } else { @@ -276,17 +299,20 @@ static void timerfd_timeout(void *parameter) 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); 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->timer = rt_timer_create(TIMERFD_MUTEX_NAME, timerfd_timeout, tfd, tfd->tick_out, @@ -307,9 +333,15 @@ static void timerfd_time_operation(time_t *sec, long *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; struct rt_timerfd *tfd; @@ -331,7 +363,9 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s return -EINVAL; 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); 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 (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); 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; 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 > 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) 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, tick_out, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); rt_timer_start(tfd->timer); } + else + { + timerfd_timeout(tfd); + } } else { @@ -411,7 +455,7 @@ static int timerfd_settime_do(int fd, int flags, const struct itimerspec *new, s 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 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_sec = tfd->ittimer.it_interval.tv_sec - tv_sec; + timerfd_time_operation(&cur->it_value.tv_sec, &cur->it_value.tv_nsec); } else { - if (tfd->timeout_num == 1) + if (rt_atomic_load(&(tfd->timeout_num)) == 1) { cur->it_value.tv_nsec = 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) { - 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) { - return timerfd_settime_do(fd, flags, new, old); + return timerfd_do_settime(fd, flags, new, old); } int timerfd_gettime(int fd, struct itimerspec *cur) { - return timerfd_gettime_do(fd, cur); + return timerfd_do_gettime(fd, cur); }