mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-11-16 12:34:33 +00:00
sync smart & dfs (#8672)
Signed-off-by: xqyjlj <xqyjlj@126.com> Signed-off-by: Shell <smokewood@qq.com> Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
@@ -7,6 +7,12 @@
|
||||
* Date Author Notes
|
||||
* 2016-12-28 Bernard first version
|
||||
* 2018-03-09 Bernard Add protection for pt->triggered.
|
||||
* 2023-12-04 Shell Fix return code and error verification
|
||||
* 2023-12-14 Shell When poll goes to sleep before the waitqueue has added a
|
||||
* record and finished enumerating all the fd's, it may be
|
||||
* incorrectly woken up. This is basically because the poll
|
||||
* mechanism wakeup algorithm does not correctly distinguish
|
||||
* the current wait state.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -16,11 +22,16 @@
|
||||
#include "poll.h"
|
||||
|
||||
struct rt_poll_node;
|
||||
enum rt_poll_status {
|
||||
RT_POLL_STAT_INIT,
|
||||
RT_POLL_STAT_TRIG,
|
||||
RT_POLL_STAT_WAITING,
|
||||
};
|
||||
|
||||
struct rt_poll_table
|
||||
{
|
||||
rt_pollreq_t req;
|
||||
rt_uint32_t triggered; /* the waited thread whether triggered */
|
||||
enum rt_poll_status status; /* the waited thread whether triggered */
|
||||
rt_thread_t polling_thread;
|
||||
struct rt_poll_node *nodes;
|
||||
};
|
||||
@@ -36,15 +47,25 @@ static RT_DEFINE_SPINLOCK(_spinlock);
|
||||
|
||||
static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
struct rt_poll_node *pn;
|
||||
int is_waiting;
|
||||
|
||||
if (key && !((rt_ubase_t)key & wait->key))
|
||||
return -1;
|
||||
|
||||
pn = rt_container_of(wait, struct rt_poll_node, wqn);
|
||||
pn->pt->triggered = 1;
|
||||
|
||||
return __wqueue_default_wake(wait, key);
|
||||
level = rt_spin_lock_irqsave(&_spinlock);
|
||||
is_waiting = (pn->pt->status == RT_POLL_STAT_WAITING);
|
||||
|
||||
pn->pt->status = RT_POLL_STAT_TRIG;
|
||||
rt_spin_unlock_irqrestore(&_spinlock, level);
|
||||
|
||||
if (is_waiting)
|
||||
return __wqueue_default_wake(wait, key);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
|
||||
@@ -71,7 +92,7 @@ static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
|
||||
static void poll_table_init(struct rt_poll_table *pt)
|
||||
{
|
||||
pt->req._proc = _poll_add;
|
||||
pt->triggered = 0;
|
||||
pt->status = RT_POLL_STAT_INIT;
|
||||
pt->nodes = RT_NULL;
|
||||
pt->polling_thread = rt_thread_self();
|
||||
}
|
||||
@@ -89,7 +110,7 @@ static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
|
||||
|
||||
level = rt_spin_lock_irqsave(&_spinlock);
|
||||
|
||||
if (timeout != 0 && !pt->triggered)
|
||||
if (timeout != 0 && pt->status != RT_POLL_STAT_TRIG)
|
||||
{
|
||||
if (rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE) == RT_EOK)
|
||||
{
|
||||
@@ -99,17 +120,31 @@ static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
rt_set_errno(RT_ETIMEOUT);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
rt_set_errno(0);
|
||||
}
|
||||
pt->status = RT_POLL_STAT_WAITING;
|
||||
rt_spin_unlock_irqrestore(&_spinlock, level);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
level = rt_spin_lock_irqsave(&_spinlock);
|
||||
if (pt->status == RT_POLL_STAT_WAITING)
|
||||
pt->status = RT_POLL_STAT_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
ret = !pt->triggered;
|
||||
ret = rt_get_errno();
|
||||
if (ret == RT_EINTR)
|
||||
ret = -RT_EINTR;
|
||||
else if (pt->status == RT_POLL_STAT_TRIG)
|
||||
ret = RT_EOK;
|
||||
else
|
||||
ret = -RT_ETIMEOUT;
|
||||
|
||||
rt_spin_unlock_irqrestore(&_spinlock, level);
|
||||
|
||||
return ret;
|
||||
@@ -170,7 +205,7 @@ static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, in
|
||||
{
|
||||
pf = fds;
|
||||
num = 0;
|
||||
pt->triggered = 0;
|
||||
pt->status = RT_POLL_STAT_INIT;
|
||||
|
||||
for (n = 0; n < nfds; n ++)
|
||||
{
|
||||
@@ -194,8 +229,13 @@ static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, in
|
||||
if (num || istimeout)
|
||||
break;
|
||||
|
||||
if (poll_wait_timeout(pt, msec))
|
||||
ret = poll_wait_timeout(pt, msec);
|
||||
if (ret == -RT_EINTR)
|
||||
return -EINTR;
|
||||
else if (ret == -RT_ETIMEOUT)
|
||||
istimeout = 1;
|
||||
else
|
||||
istimeout = 0;
|
||||
}
|
||||
|
||||
return num;
|
||||
|
||||
Reference in New Issue
Block a user