summaryrefslogtreecommitdiff
path: root/components
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
parent25cbe4abae05e9be46edff3966850af8a7f58515 (diff)
[libc][posix] Fix epoll waiters and LWP syscall copies
修复 epoll waiter 生命周期,避免等待队列节点在回调后失效。 整理 LWP POSIX syscall 的用户空间拷贝和错误返回路径。
Diffstat (limited to 'components')
-rw-r--r--components/libc/posix/io/epoll/epoll.c102
-rw-r--r--components/lwp/lwp_syscall.c271
2 files changed, 258 insertions, 115 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);
}
-
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index ea096f2a90..a871f71b51 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -425,20 +425,18 @@ ssize_t sys_read(int fd, void *buf, size_t nbyte)
void *kmem = RT_NULL;
ssize_t ret = -1;
- if (!nbyte)
- {
- return -EINVAL;
- }
-
- if (!lwp_user_accessable((void *)buf, nbyte))
+ if (nbyte)
{
- return -EFAULT;
- }
+ if (!lwp_user_accessable((void *)buf, nbyte))
+ {
+ return -EFAULT;
+ }
- kmem = kmem_get(nbyte);
- if (!kmem)
- {
- return -ENOMEM;
+ kmem = kmem_get(nbyte);
+ if (!kmem)
+ {
+ return -ENOMEM;
+ }
}
ret = read(fd, kmem, nbyte);
@@ -794,6 +792,28 @@ sysret_t sys_close(int fd)
*/
sysret_t sys_ioctl(int fd, unsigned long cmd, void *data)
{
+#ifdef ARCH_MM_MMU
+ if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW)
+ {
+ struct flock lock;
+ int ret;
+
+ if (data == RT_NULL ||
+ !lwp_user_accessable(data, sizeof(lock)) ||
+ lwp_get_from_user(&lock, data, sizeof(lock)) != sizeof(lock))
+ {
+ return -EFAULT;
+ }
+
+ ret = ioctl(fd, cmd, &lock);
+ if (ret >= 0 && cmd == F_GETLK &&
+ lwp_put_to_user(data, &lock, sizeof(lock)) != sizeof(lock))
+ {
+ return -EFAULT;
+ }
+ return ret < 0 ? GET_ERRNO() : ret;
+ }
+#endif
int ret = ioctl(fd, cmd, data);
return (ret < 0 ? GET_ERRNO() : ret);
}
@@ -5680,7 +5700,9 @@ static void cmsg_level_lwip_2_muslc(struct msghdr *message)
static int copy_msghdr_from_user(struct msghdr *kmsg,
struct musl_msghdr *umsg,
struct iovec **out_iov, void **out_msg_control,
- void **out_msg_name, void **out_buffer)
+ void **out_msg_name, void **out_buffer,
+ socklen_t *out_user_name_length,
+ rt_bool_t receive)
{
int index;
size_t iovs_size;
@@ -5704,12 +5726,33 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
kmsg->msg_controllen = user_message.msg_controllen;
kmsg->msg_flags = user_message.msg_flags;
+ if (out_user_name_length != RT_NULL)
+ {
+ *out_user_name_length = kmsg->msg_namelen;
+ }
+
if (kmsg->msg_iovlen < 0 ||
(size_t)kmsg->msg_iovlen > SIZE_MAX / sizeof(*kmsg->msg_iov) ||
- kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer))
+ (!receive &&
+ kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer)))
{
return -EINVAL;
}
+ if (receive)
+ {
+ if (kmsg->msg_name == RT_NULL)
+ {
+ kmsg->msg_namelen = 0;
+ }
+ else if (kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer))
+ {
+ kmsg->msg_namelen = sizeof(union lwp_sockaddr_buffer);
+ }
+ if (kmsg->msg_control == RT_NULL)
+ {
+ kmsg->msg_controllen = 0;
+ }
+ }
if (kmsg->msg_name != RT_NULL &&
!lwp_user_accessable(kmsg->msg_name, kmsg->msg_namelen))
{
@@ -5862,6 +5905,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags)
{
int flgs, ret = -1;
+ int error = 0;
struct msghdr kmsg;
#ifdef ARCH_MM_MMU
int index;
@@ -5882,62 +5926,67 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags)
#ifdef ARCH_MM_MMU
ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control,
- &msg_name, &buffer);
+ &msg_name, &buffer, &user_name_length,
+ RT_TRUE);
- if (!ret)
+ if (ret < 0)
{
- user_name_length = kmsg.msg_namelen;
- ret = recvmsg(socket, &kmsg, flgs);
-
- if (ret < 0)
- {
- goto _free_res;
- }
-
- kiov = kmsg.msg_iov;
- remaining = (size_t)ret;
+ return ret;
+ }
+ ret = recvmsg(socket, &kmsg, flgs);
+ if (ret < 0)
+ {
+ error = GET_ERRNO();
+ }
- for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index)
- {
- size_t copy_length = kiov->iov_len;
+ if (ret < 0)
+ {
+ goto _free_res;
+ }
- if (copy_length > remaining)
- {
- copy_length = remaining;
- }
- lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length);
- remaining -= copy_length;
+ kiov = kmsg.msg_iov;
+ remaining = (size_t)ret;
- ++kiov;
- ++uiov;
- }
+ for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index)
+ {
+ size_t copy_length = kiov->iov_len;
- if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
+ if (copy_length > remaining)
{
- cmsg_level_lwip_2_muslc(&kmsg);
- lwp_put_to_user(msg_control, kmsg.msg_control,
- kmsg.msg_controllen);
+ copy_length = remaining;
}
- if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL)
- {
- socklen_t name_length;
+ lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length);
+ remaining -= copy_length;
- name_length = lwp_sockaddr_to_user(
- (struct musl_sockaddr *)msg_name, user_name_length,
- (const union lwp_sockaddr_buffer *)kmsg.msg_name,
- kmsg.msg_namelen);
- lwp_put_to_user(&msg->msg_namelen, &name_length,
- sizeof(name_length));
- }
- kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags);
- lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags));
- lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen,
- sizeof(kmsg.msg_controllen));
+ ++kiov;
+ ++uiov;
+ }
+
+ if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
+ {
+ cmsg_level_lwip_2_muslc(&kmsg);
+ lwp_put_to_user(msg_control, kmsg.msg_control,
+ kmsg.msg_controllen);
+ }
+ if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL)
+ {
+ socklen_t name_length;
- _free_res:
- kmem_put(buffer);
- kmem_put(kmsg.msg_iov);
+ name_length = lwp_sockaddr_to_user(
+ (struct musl_sockaddr *)msg_name, user_name_length,
+ (const union lwp_sockaddr_buffer *)kmsg.msg_name,
+ kmsg.msg_namelen);
+ lwp_put_to_user(&msg->msg_namelen, &name_length,
+ sizeof(name_length));
}
+ kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags);
+ lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags));
+ lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen,
+ sizeof(kmsg.msg_controllen));
+
+_free_res:
+ kmem_put(buffer);
+ kmem_put(kmsg.msg_iov);
#else
kmsg.msg_name = msg->msg_name;
kmsg.msg_namelen = msg->msg_namelen;
@@ -5948,6 +5997,10 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags)
kmsg.msg_flags = msg->msg_flags;
ret = recvmsg(socket, &kmsg, flgs);
+ if (ret < 0)
+ {
+ error = GET_ERRNO();
+ }
if (!ret)
{
@@ -5955,7 +6008,11 @@ sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags)
}
#endif /* ARCH_MM_MMU */
- return (ret < 0 ? GET_ERRNO() : ret);
+ if (ret >= 0)
+ {
+ return ret;
+ }
+ return error != 0 ? error : ret;
}
/**
@@ -6178,6 +6235,7 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags)
{
int flgs, ret = -1;
+ int error = 0;
struct msghdr kmsg;
#ifdef ARCH_MM_MMU
int index;
@@ -6195,47 +6253,53 @@ sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags)
#ifdef ARCH_MM_MMU
ret = copy_msghdr_from_user(&kmsg, (struct musl_msghdr *)msg, &uiov,
- &msg_control, &msg_name, &buffer);
+ &msg_control, &msg_name, &buffer, RT_NULL,
+ RT_FALSE);
- if (!ret)
+ if (ret < 0)
{
- kiov = kmsg.msg_iov;
+ return ret;
+ }
+ kiov = kmsg.msg_iov;
- for (index = 0; index < kmsg.msg_iovlen; ++index)
- {
- lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len);
+ for (index = 0; index < kmsg.msg_iovlen; ++index)
+ {
+ lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len);
- ++kiov;
- ++uiov;
- }
+ ++kiov;
+ ++uiov;
+ }
- if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
- {
- lwp_get_from_user(kmsg.msg_control, msg_control,
- kmsg.msg_controllen);
- cmsg_level_muslc_2_lwip(&kmsg);
- }
- if (msg_name != RT_NULL && kmsg.msg_namelen != 0)
- {
- union lwp_sockaddr_buffer kernel_address;
+ if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
+ {
+ lwp_get_from_user(kmsg.msg_control, msg_control,
+ kmsg.msg_controllen);
+ cmsg_level_muslc_2_lwip(&kmsg);
+ }
+ if (msg_name != RT_NULL && kmsg.msg_namelen != 0)
+ {
+ union lwp_sockaddr_buffer kernel_address;
- ret = lwp_sockaddr_from_user(&kernel_address,
- (struct musl_sockaddr *)msg_name,
- kmsg.msg_namelen);
- if (ret < 0)
- {
- kmem_put(buffer);
- kmem_put(kmsg.msg_iov);
- return ret;
- }
- rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen);
+ ret = lwp_sockaddr_from_user(&kernel_address,
+ (struct musl_sockaddr *)msg_name,
+ kmsg.msg_namelen);
+ if (ret < 0)
+ {
+ kmem_put(buffer);
+ kmem_put(kmsg.msg_iov);
+ return ret;
}
+ rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen);
+ }
- ret = sendmsg(socket, &kmsg, flgs);
-
- kmem_put(buffer);
- kmem_put(kmsg.msg_iov);
+ ret = sendmsg(socket, &kmsg, flgs);
+ if (ret < 0)
+ {
+ error = GET_ERRNO();
}
+
+ kmem_put(buffer);
+ kmem_put(kmsg.msg_iov);
#else
kmsg.msg_name = msg->msg_name;
kmsg.msg_namelen = msg->msg_namelen;
@@ -6246,10 +6310,18 @@ sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags)
kmsg.msg_flags = msg->msg_flags;
ret = sendmsg(socket, &kmsg, flgs);
+ if (ret < 0)
+ {
+ error = GET_ERRNO();
+ }
#endif /* ARCH_MM_MMU */
- return (ret < 0 ? GET_ERRNO() : ret);
+ if (ret >= 0)
+ {
+ return ret;
+ }
+ return error != 0 ? error : ret;
}
/**
@@ -6530,7 +6602,9 @@ sysret_t sys_socketpair(int domain, int type, int protocol, int fd[2])
*/
sysret_t sys_closesocket(int socket)
{
- return closesocket(socket);
+ sysret_t ret;
+ ret = closesocket(socket);
+ return ret;
}
#endif
@@ -10619,6 +10693,14 @@ sysret_t sys_chmod(const char *pathname, mode_t mode)
return (ret < 0 ? GET_ERRNO() : ret);
}
+sysret_t sys_fchmod(int fd, mode_t mode)
+{
+ int ret;
+
+ ret = fchmod(fd, mode);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
/**
* @brief Change the ownership of a file or directory.
*
@@ -11497,6 +11579,7 @@ const static struct rt_syscall_def func_table[] = {
SYSCALL_SIGN(sys_getppid),
SYSCALL_SIGN(sys_fchdir),
SYSCALL_SIGN(sys_chown),
+ SYSCALL_SIGN(sys_fchmod),
};
const void *lwp_get_sys_api(rt_uint32_t number)