diff --git a/components/libc/posix/io/signalfd/SConscript b/components/libc/posix/io/signalfd/SConscript new file mode 100644 index 0000000000..611d0f3a8e --- /dev/null +++ b/components/libc/posix/io/signalfd/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd] + +if GetDepend('RT_USING_DFS'): + if GetDepend('RT_USING_MUSLLIBC'): + src += ['signalfd.c'] + +group = DefineGroup('POSIX', src, depend = ['RT_USING_SMART'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/io/signalfd/signalfd.c b/components/libc/posix/io/signalfd/signalfd.c new file mode 100644 index 0000000000..b7cb20dc44 --- /dev/null +++ b/components/libc/posix/io/signalfd/signalfd.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-29 zmq810150896 first version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIGNALFD_MUTEX_NAME "signalfd" +#define SIGNALFD_SHART_MAX 10 + +static int is_head_init = 0; + +struct rt_signalfd_ctx +{ + sigset_t sigmask; + struct rt_mutex lock; + siginfo_t info; + int tick; + rt_wqueue_t signalfd_queue; + struct rt_lwp *lwp[SIGNALFD_SHART_MAX]; +}; + +static int signalfd_close(struct dfs_file *file); +static int signalfd_poll(struct dfs_file *file, struct rt_pollreq *req); +#ifndef RT_USING_DFS_V2 +static ssize_t signalfd_read(struct dfs_file *file, void *buf, size_t count); +#else +static ssize_t signalfd_read(struct dfs_file *file, void *buf, size_t count, off_t *pos); +#endif +static int signalfd_add_notify(struct rt_signalfd_ctx *sfd); + +static const struct dfs_file_ops signalfd_fops = +{ + .close = signalfd_close, + .poll = signalfd_poll, + .read = signalfd_read, +}; + +static int signalfd_close(struct dfs_file *file) +{ + struct rt_signalfd_ctx *sfd; + + if (file->vnode->ref_count != 1) + return 0; + + sfd = file->vnode->data; + + if (sfd) + { + rt_mutex_detach(&sfd->lock); + rt_free(sfd); + } + + return 0; +} + +static int signalfd_poll(struct dfs_file *file, struct rt_pollreq *req) +{ + struct rt_signalfd_ctx *sfd; + int events = 0; + + if (file->vnode) + { + sfd = file->vnode->data; + + rt_poll_add(&sfd->signalfd_queue, req); + signalfd_add_notify(sfd); + + rt_mutex_take(&sfd->lock, RT_WAITING_FOREVER); + + if (sfd->tick) + events |= POLLIN; + + sfd->tick = 0; + rt_mutex_release(&sfd->lock); + } + + return events; +} + +#ifndef RT_USING_DFS_V2 +static ssize_t signalfd_read(struct dfs_file *file, void *buf, size_t count) +#else +static ssize_t signalfd_read(struct dfs_file *file, void *buf, size_t count, off_t *pos) +#endif +{ + struct rt_signalfd_ctx *sfd; + struct signalfd_siginfo *buffer; + rt_err_t ret = -1; + + if (sizeof(struct signalfd_siginfo) > count) + return -1; + + buffer = (struct signalfd_siginfo *)buf; + + if (file->vnode) + { + sfd = file->vnode->data; + + signalfd_add_notify(sfd); + + rt_wqueue_wait(&sfd->signalfd_queue, 0, RT_WAITING_FOREVER); + rt_mutex_take(&sfd->lock, RT_WAITING_FOREVER); + sfd->tick = 1; + rt_mutex_release(&sfd->lock); + + buffer->ssi_signo = sfd->info.si_signo; + buffer->ssi_code = sfd->info.si_code; + + ret = sizeof(struct signalfd_siginfo); + } + + return ret; +} + +static void signalfd_callback(rt_wqueue_t *signalfd_queue, int signum) +{ + struct rt_signalfd_ctx *sfd; + + sfd = rt_container_of(signalfd_queue, struct rt_signalfd_ctx, signalfd_queue); + + if (sfd) + { + for (int sig = 1; sig < NSIG; sig++) + { + if (sigismember(&sfd->sigmask, signum)) + { + rt_mutex_take(&sfd->lock, RT_WAITING_FOREVER); + sfd->tick = 1; + sfd->info.si_signo = signum; + rt_mutex_release(&sfd->lock); + rt_wqueue_wakeup(signalfd_queue, (void*)POLLIN); + } + } + } +} + +static int signalfd_add_notify(struct rt_signalfd_ctx *sfd) +{ + struct rt_lwp_notify *lwp_notify; + rt_err_t ret = -1; + rt_slist_t *node; + int is_lwp = 0; + + rt_mutex_take(&sfd->lock, RT_WAITING_FOREVER); + + for (int i = 0; i < is_head_init; i++) + { + if (sfd->lwp[i]) + { + if (sfd->lwp[i] == lwp_self()) + { + is_lwp = 1; + } + } + } + + if (is_lwp == 0) + { + sfd->lwp[is_head_init] = lwp_self(); + + if (is_head_init == 0) + { + rt_slist_init(&sfd->lwp[is_head_init]->signalfd_notify_head); + } + + lwp_notify = (struct rt_lwp_notify *)rt_malloc(sizeof(struct rt_lwp_notify)); + if (lwp_notify) + { + lwp_notify->notify = signalfd_callback; + lwp_notify->signalfd_queue = &sfd->signalfd_queue; + rt_slist_append(&sfd->lwp[is_head_init]->signalfd_notify_head, &(lwp_notify->list_node)); + + is_head_init ++; + ret = 0; + } + else + { + rt_slist_for_each(node, &sfd->lwp[is_head_init]->signalfd_notify_head) + { + struct rt_lwp_notify *n = rt_slist_entry(node, struct rt_lwp_notify, list_node); + rt_slist_remove(&sfd->lwp[is_head_init]->signalfd_notify_head, &n->list_node); + rt_free(n); + } + rt_set_errno(ENOMEM); + } + } + + rt_mutex_release(&sfd->lock); + + return ret; +} + +static int signalfd_do(int fd, const sigset_t *mask, int flags) +{ + struct dfs_file *df; + struct rt_signalfd_ctx *sfd; + rt_err_t ret = 0; + + if (fd == -1) + { + fd = fd_new(); + if (fd < 0) + return -1; + + ret = fd; + df = fd_get(fd); + + if (df) + { + sfd = (struct rt_signalfd_ctx *)rt_malloc(sizeof(struct rt_signalfd_ctx)); + if (sfd) + { + df->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode)); + if (df->vnode) + { + dfs_vnode_init(df->vnode, FT_REGULAR, &signalfd_fops); + df->vnode->data = sfd; + + for (int i = 0; i < is_head_init; i++) + { + sfd->lwp[i] = RT_NULL; + } + + sigemptyset(&sfd->sigmask); + memcpy(&sfd->sigmask, mask, sizeof(sigset_t)); + + rt_mutex_init(&sfd->lock, SIGNALFD_MUTEX_NAME, RT_IPC_FLAG_FIFO); + rt_wqueue_init(&sfd->signalfd_queue); + + if (signalfd_add_notify(sfd) < 0) + { + is_head_init = 0; + fd_release(fd); + rt_free(sfd); + ret = -1; + } + + sfd->tick = 0; + + df->flags |= flags; + + #ifdef RT_USING_DFS_V2 + df->fops = &signalfd_fops; + #endif + } + else + { + fd_release(fd); + rt_free(sfd); + ret = -1; + } + } + else + { + fd_release(fd); + ret = -1; + } + } + else + { + fd_release(fd); + } + } + else + { + df = fd_get(fd); + if (df) + { + sfd = df->vnode->data; + df->flags = flags; + sigemptyset(&sfd->sigmask); + memcpy(&sfd->sigmask, mask, sizeof(sigset_t)); + ret = fd; + } + else + { + rt_set_errno(EBADF); + ret = -1; + } + } + + return ret; +} + +int signalfd(int fd, const sigset_t *mask, int flags) +{ + return signalfd_do(fd, mask, flags); +} diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 147f0c6051..eb6a20e6ba 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -68,6 +68,13 @@ struct rt_lwp_objs struct rt_mem_obj mem_obj; }; +struct rt_lwp_notify +{ + void (*notify)(rt_wqueue_t *signalfd_queue, int signo); + rt_wqueue_t *signalfd_queue; + rt_slist_t list_node; +}; + struct rt_lwp { #ifdef ARCH_MM_MMU @@ -131,6 +138,8 @@ struct rt_lwp int debug; uint32_t bak_first_ins; + rt_slist_t signalfd_notify_head; + #ifdef LWP_ENABLE_ASID uint64_t generation; unsigned int asid; diff --git a/components/lwp/lwp_signal.c b/components/lwp/lwp_signal.c index 69270638e1..ffba9e27b0 100644 --- a/components/lwp/lwp_signal.c +++ b/components/lwp/lwp_signal.c @@ -392,6 +392,20 @@ void lwp_sigqueue_clear(lwp_sigqueue_t sigq) } } +static void lwp_signal_notify(rt_slist_t *list_head, lwp_siginfo_t siginfo) +{ + rt_slist_t *node; + + rt_slist_for_each(node, list_head) + { + struct rt_lwp_notify *n = rt_slist_entry(node, struct rt_lwp_notify, list_node); + if (n->notify) + { + n->notify(n->signalfd_queue, siginfo->ksiginfo.signo); + } + } +} + rt_err_t lwp_signal_init(struct lwp_signal *sig) { rt_err_t rc; @@ -704,6 +718,7 @@ rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, long value) { need_schedule = _siginfo_deliver_to_lwp(lwp, siginfo); ret = 0; + lwp_signal_notify(&lwp->signalfd_notify_head, siginfo); } else { @@ -856,6 +871,7 @@ rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long { need_schedule = _siginfo_deliver_to_thread(thread, siginfo); ret = 0; + lwp_signal_notify(&lwp->signalfd_notify_head, siginfo); } else { diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index ad84dd2d9b..2d9e0c0bed 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -53,6 +53,10 @@ #include /* rename() */ #include #include /* statfs() */ +#include +#ifdef RT_USING_MUSLLIBC +#include +#endif #endif #include "mqueue.h" @@ -5416,6 +5420,15 @@ sysret_t sys_epoll_pwait(int fd, return (ret < 0 ? GET_ERRNO() : ret); } +sysret_t sys_ftruncate(int fd, off_t length) +{ + int ret; + + ret = ftruncate(fd, length); + + return (ret < 0 ? GET_ERRNO() : ret); +} + sysret_t sys_chmod(const char *fileName, mode_t mode) { char *copy_fileName; @@ -5563,6 +5576,54 @@ ssize_t sys_pwrite64(int fd, void *buf, int size, off_t offset) } #endif +sysret_t sys_timerfd_create(int clockid, int flags) +{ + return 0; +} + +sysret_t sys_timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itimerspec *old) +{ + return 0; +} + +sysret_t sys_timerfd_gettime(int fd, struct itimerspec *cur) +{ + return 0; +} + +sysret_t sys_signalfd(int fd, const sigset_t *mask, int flags) +{ + int ret = 0; + sigset_t *kmask = RT_NULL; + +#ifdef RT_USING_MUSLLIBC + if (mask == RT_NULL) + return -EINVAL; + + if (!lwp_user_accessable((void *)mask, sizeof(struct itimerspec))) + { + return -EFAULT; + } + + kmask = kmem_get(sizeof(*kmask)); + + if (kmask) + { + lwp_get_from_user(kmask, (void *)mask, sizeof(*kmask)); + ret = signalfd(fd, mask, flags); + lwp_put_to_user((void *)mask, kmask, sizeof(*kmask)); + kmem_put(kmask); + } +#endif + + return (ret < 0 ? GET_ERRNO() : ret); +} + +sysret_t sys_memfd_create() +{ + return 0; +} + const static struct rt_syscall_def func_table[] = { SYSCALL_SIGN(sys_exit), /* 01 */ @@ -5798,6 +5859,13 @@ const static struct rt_syscall_def func_table[] = SYSCALL_SIGN(sys_epoll_create1), SYSCALL_SIGN(sys_epoll_ctl), SYSCALL_SIGN(sys_epoll_pwait), + SYSCALL_SIGN(sys_notimpl), /* 195 */ + SYSCALL_SIGN(sys_timerfd_create), + SYSCALL_SIGN(sys_timerfd_settime), + SYSCALL_SIGN(sys_timerfd_gettime), + SYSCALL_SIGN(sys_signalfd), + SYSCALL_SIGN(sys_memfd_create), /* 200 */ + SYSCALL_SIGN(sys_ftruncate), }; const void *lwp_get_sys_api(rt_uint32_t number)