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; + for (waiter = fdlist->waiters; waiter != RT_NULL; waiter = waiter->next) + { + if (waiter->wqn.wqueue == wq) + { + waiter->wqn.key |= req->_key; + return; + } + } - rt_list_init(&(fdlist->wqn.list)); - - 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) + if (nbyte) { - return -EINVAL; - } + if (!lwp_user_accessable((void *)buf, 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; - - for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index) - { - size_t copy_length = kiov->iov_len; - - if (copy_length > remaining) - { - copy_length = remaining; - } - lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length); - remaining -= copy_length; - - ++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; - - 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); + return ret; } + ret = recvmsg(socket, &kmsg, flgs); + if (ret < 0) + { + error = GET_ERRNO(); + } + + if (ret < 0) + { + goto _free_res; + } + + kiov = kmsg.msg_iov; + remaining = (size_t)ret; + + for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index) + { + size_t copy_length = kiov->iov_len; + + if (copy_length > remaining) + { + copy_length = remaining; + } + lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length); + remaining -= copy_length; + + ++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; + + 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; - - for (index = 0; index < kmsg.msg_iovlen; ++index) - { - lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len); - - ++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; - - 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); + 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); + + ++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; + + 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); + 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)