Browse Source

Add the system call signalfd (#8001)

zmq810150896 1 year ago
parent
commit
7c3d966df6

+ 15 - 0
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')

+ 302 - 0
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);
+}

+ 9 - 0
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;

+ 16 - 0
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
             {

+ 68 - 0
components/lwp/lwp_syscall.c

@@ -53,6 +53,10 @@
 #include <stdio.h> /* rename() */
 #include <sys/stat.h>
 #include <sys/statfs.h> /* statfs() */
+#include <sys/timerfd.h>
+#ifdef RT_USING_MUSLLIBC
+#include <sys/signalfd.h>
+#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)