123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /*
- * 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);
- }
|