summaryrefslogtreecommitdiff
path: root/components/libc
diff options
context:
space:
mode:
authorbernard <[email protected]>2026-08-23 07:44:06 +0800
committerRbb666 <[email protected]>2026-08-30 20:49:24 +0800
commit3152ab617b29cfc579badfce358490b7fa8810b1 (patch)
tree1b0ffe57767f40ae1868c608150644eb6b33933f /components/libc
parent25cbe4abae05e9be46edff3966850af8a7f58515 (diff)
[libc][posix] Fix epoll waiters and LWP syscall copies
修复 epoll waiter 生命周期,避免等待队列节点在回调后失效。 整理 LWP POSIX syscall 的用户空间拷贝和错误返回路径。
Diffstat (limited to 'components/libc')
-rw-r--r--components/libc/posix/io/epoll/epoll.c102
1 files changed, 81 insertions, 21 deletions
diff --git a/components/libc/posix/io/epoll/epoll.c b/components/libc/posix/io/epoll/epoll.c
index a4c9dcfc06..9aa11e2d87 100644
--- a/components/libc/posix/io/epoll/epoll.c
+++ b/components/libc/posix/io/epoll/epoll.c
@@ -31,6 +31,15 @@
EPOLLET | EPOLLEXCLUSIVE)
struct rt_eventpoll;
+struct rt_fd_list;
+
+struct rt_epoll_waiter
+{
+ struct rt_wqueue_node wqn;
+ struct rt_fd_list *fdlist;
+ struct rt_epoll_waiter *next;
+ rt_bool_t queued;
+};
enum rt_epoll_status {
RT_EPOLL_STAT_INIT,
@@ -45,7 +54,7 @@ struct rt_fd_list
struct epoll_event epev; /**< Epoll event structure */
rt_pollreq_t req; /**< Poll request structure */
struct rt_eventpoll *ep; /**< Pointer to the associated event poll */
- struct rt_wqueue_node wqn; /**< Wait queue node */
+ struct rt_epoll_waiter *waiters; /**< Wait nodes registered by poll */
int exclusive; /**< Indicates if the event is exclusive */
rt_bool_t is_rdl_node; /**< Indicates if the node is in the ready list */
int fd; /**< File descriptor */
@@ -71,6 +80,42 @@ static int epoll_poll(struct dfs_file *file, struct rt_pollreq *req);
static int epoll_get_event(struct rt_fd_list *fl, rt_pollreq_t *req);
static int epoll_do_ctl(int epfd, int op, int fd, struct epoll_event *event);
+static void epoll_remove_waiters(struct rt_fd_list *fdlist)
+{
+ struct rt_epoll_waiter *waiter;
+
+ while (fdlist->waiters != RT_NULL)
+ {
+ waiter = fdlist->waiters;
+ fdlist->waiters = waiter->next;
+ if (waiter->queued)
+ {
+ rt_wqueue_remove(&waiter->wqn);
+ waiter->queued = RT_FALSE;
+ }
+ rt_free(waiter);
+ }
+}
+
+static void epoll_set_polling_thread(struct rt_eventpoll *ep,
+ rt_thread_t thread)
+{
+ struct rt_epoll_waiter *waiter;
+ struct rt_fd_list *fdlist;
+
+ rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
+ ep->polling_thread = thread;
+ for (fdlist = ep->fdlist; fdlist != RT_NULL; fdlist = fdlist->next)
+ {
+ for (waiter = fdlist->waiters; waiter != RT_NULL;
+ waiter = waiter->next)
+ {
+ waiter->wqn.polling_thread = thread;
+ }
+ }
+ rt_mutex_release(&ep->lock);
+}
+
static const struct dfs_file_ops epoll_fops =
{
.close = epoll_close,
@@ -96,7 +141,7 @@ static int epoll_close_fdlist(struct rt_fd_list *fdlist)
while (list->next != RT_NULL)
{
fre_node = list->next;
- rt_wqueue_remove(&fre_node->wqn);
+ epoll_remove_waiters(fre_node);
list->next = fre_node->next;
rt_free(fre_node);
@@ -196,6 +241,7 @@ static int epoll_poll(struct dfs_file *file, struct rt_pollreq *req)
static int epoll_wqueue_callback(struct rt_wqueue_node *wait, void *key)
{
struct rt_fd_list *fdlist;
+ struct rt_epoll_waiter *waiter;
struct rt_eventpoll *ep;
rt_base_t level;
int is_waiting = 0;
@@ -203,7 +249,8 @@ static int epoll_wqueue_callback(struct rt_wqueue_node *wait, void *key)
if (key && !((rt_ubase_t)key & wait->key))
return -1;
- fdlist = rt_container_of(wait, struct rt_fd_list, wqn);
+ waiter = rt_container_of(wait, struct rt_epoll_waiter, wqn);
+ fdlist = waiter->fdlist;
ep = fdlist->ep;
if (ep)
@@ -242,17 +289,34 @@ static void epoll_wqueue_add_callback(rt_wqueue_t *wq, rt_pollreq_t *req)
{
struct rt_fd_list *fdlist;
struct rt_eventpoll *ep;
+ struct rt_epoll_waiter *waiter;
fdlist = rt_container_of(req, struct rt_fd_list, req);
ep = fdlist->ep;
- fdlist->wqn.key = req->_key;
-
- rt_list_init(&(fdlist->wqn.list));
+ for (waiter = fdlist->waiters; waiter != RT_NULL; waiter = waiter->next)
+ {
+ if (waiter->wqn.wqueue == wq)
+ {
+ waiter->wqn.key |= req->_key;
+ return;
+ }
+ }
- fdlist->wqn.polling_thread = ep->polling_thread;
- fdlist->wqn.wakeup = epoll_wqueue_callback;
- rt_wqueue_add(wq, &fdlist->wqn);
+ waiter = (struct rt_epoll_waiter *)rt_calloc(1, sizeof(*waiter));
+ if (waiter == RT_NULL)
+ {
+ return;
+ }
+ waiter->fdlist = fdlist;
+ waiter->wqn.key = req->_key;
+ waiter->wqn.polling_thread = ep->polling_thread;
+ waiter->wqn.wakeup = epoll_wqueue_callback;
+ rt_list_init(&waiter->wqn.list);
+ waiter->next = fdlist->waiters;
+ fdlist->waiters = waiter;
+ rt_wqueue_add(wq, &waiter->wqn);
+ waiter->queued = RT_TRUE;
}
/**
@@ -346,6 +410,7 @@ static int epoll_epf_init(int fd)
ep->fdlist->next = RT_NULL;
ep->fdlist->fd = fd;
ep->fdlist->ep = ep;
+ ep->fdlist->waiters = RT_NULL;
ep->fdlist->exclusive = 0;
ep->fdlist->is_rdl_node = RT_FALSE;
dfs_vnode_init(df->vnode, FT_REGULAR, &epoll_fops);
@@ -457,6 +522,7 @@ static int epoll_ctl_add(struct dfs_file *df, int fd, struct epoll_event *event)
memcpy(&fdlist->epev.data, &event->data, sizeof(event->data));
fdlist->epev.events = 0;
fdlist->ep = ep;
+ fdlist->waiters = RT_NULL;
fdlist->exclusive = 0;
fdlist->is_rdl_node = RT_FALSE;
fdlist->req._proc = epoll_wqueue_add_callback;
@@ -520,8 +586,7 @@ static int epoll_ctl_del(struct dfs_file *df, int fd)
fre_fd = fdlist->next;
fdlist->next = fdlist->next->next;
- if (fre_fd->wqn.wqueue)
- rt_wqueue_remove(&fre_fd->wqn);
+ epoll_remove_waiters(fre_fd);
rt_free(fre_fd);
break;
@@ -570,8 +635,7 @@ static int epoll_ctl_mod(struct dfs_file *df, int fd, struct epoll_event *event)
rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
memcpy(&fdlist->next->epev.data, &event->data, sizeof(event->data));
fdlist->next->revents = event->events;
- if (fdlist->next->wqn.wqueue)
- rt_wqueue_remove(&fdlist->next->wqn);
+ epoll_remove_waiters(fdlist->next);
rt_mutex_release(&ep->lock);
epoll_ctl_install(fdlist->next, ep);
@@ -804,10 +868,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max
isn_add = 0;
if (event_num < maxevents)
{
- if (rdlist->wqn.wqueue)
- {
- rt_wqueue_remove(&rdlist->wqn);
- }
+ epoll_remove_waiters(rdlist);
mask = epoll_get_event(rdlist, &rdlist->req);
@@ -825,8 +886,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max
{
rdlist->revents = 0;
isfree = 1;
- if (rdlist->wqn.wqueue)
- rt_wqueue_remove(&rdlist->wqn);
+ epoll_remove_waiters(rdlist);
}
else
{
@@ -864,7 +924,7 @@ static int epoll_do(struct rt_eventpoll *ep, struct epoll_event *events, int max
else
{
level = rt_spin_lock_irqsave(&ep->spinlock);
- if (!rdlist->wqn.wqueue)
+ if (rdlist->waiters == RT_NULL)
{
epoll_get_event(rdlist, &rdlist->req);
}
@@ -937,6 +997,7 @@ static int epoll_do_wait(int epfd, struct epoll_event *events, int maxevents, in
ep = (struct rt_eventpoll *)df->vnode->data;
if (ep)
{
+ epoll_set_polling_thread(ep, rt_thread_self());
ret = epoll_do(ep, events, maxevents, timeout);
}
}
@@ -1039,4 +1100,3 @@ int epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, int timeou
{
return epoll_do_wait(epfd, events, maxevents, timeout, ss);
}
-