diff options
| author | zmq810150896 <[email protected]> | 2023-09-11 14:06:08 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-11 14:06:08 +0800 |
| commit | 7c3d966df6402e5b975ea4d5a7345a58f4746491 (patch) | |
| tree | 634498114bdff05f04639f560b8a731d317b4c7c /components/libc | |
| parent | e8e980879e7471ef27220a3ecddf65e982622205 (diff) | |
Add the system call signalfd (#8001)
Diffstat (limited to 'components/libc')
| -rw-r--r-- | components/libc/posix/io/signalfd/SConscript | 15 | ||||
| -rw-r--r-- | components/libc/posix/io/signalfd/signalfd.c | 302 |
2 files changed, 317 insertions, 0 deletions
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 <rtthread.h> +#include <sys/signalfd.h> +#include <dfs_file.h> +#include <signal.h> +#include <rthw.h> +#include <sys/time.h> +#include <lwp_signal.h> +#include <lwp.h> +#include <poll.h> + +#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); +} |
