From 307e9e5e98675da7c1fa32f15ab4130ca5f73a8a Mon Sep 17 00:00:00 2001 From: zmq810150896 <50894086+zmq810150896@users.noreply.github.com> Date: Thu, 27 Jul 2023 17:24:56 +0800 Subject: [PATCH] Add the system call eventfd (#7835) --- components/libc/posix/Kconfig | 5 + components/libc/posix/io/eventfd/SConscript | 14 + components/libc/posix/io/eventfd/eventfd.c | 274 ++++++++++++++++++++ components/libc/posix/io/eventfd/eventfd.h | 16 ++ components/lwp/lwp_syscall.c | 10 + 5 files changed, 319 insertions(+) create mode 100644 components/libc/posix/io/eventfd/SConscript create mode 100644 components/libc/posix/io/eventfd/eventfd.c create mode 100644 components/libc/posix/io/eventfd/eventfd.h diff --git a/components/libc/posix/Kconfig b/components/libc/posix/Kconfig index f8c929b45c..b3f0e7cb84 100644 --- a/components/libc/posix/Kconfig +++ b/components/libc/posix/Kconfig @@ -25,6 +25,11 @@ if RT_USING_POSIX_FS bool "Enable I/O Multiplexing select() " select RT_USING_POSIX_POLL default n + + config RT_USING_POSIX_EVENTFD + bool "Enable I/O event eventfd " + select RT_USING_POSIX_POLL + default n config RT_USING_POSIX_SOCKET bool "Enable BSD Socket I/O " diff --git a/components/libc/posix/io/eventfd/SConscript b/components/libc/posix/io/eventfd/SConscript new file mode 100644 index 0000000000..b4becfce4b --- /dev/null +++ b/components/libc/posix/io/eventfd/SConscript @@ -0,0 +1,14 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd] + +if GetDepend('RT_USING_POSIX_EVENTFD'): + src += ['eventfd.c'] + +group = DefineGroup('POSIX', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/posix/io/eventfd/eventfd.c b/components/libc/posix/io/eventfd/eventfd.c new file mode 100644 index 0000000000..1d6c79b809 --- /dev/null +++ b/components/libc/posix/io/eventfd/eventfd.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-20 zmq810150896 first version + */ + +#include +#include +#include +#include +#include +#include +#include "poll.h" +#include "eventfd.h" + +#define EFD_SEMAPHORE (1 << 0) +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK + +#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) +#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE) + +#define ULLONG_MAX (~0ULL) + +#define EVENTFD_MUTEX_NAME "eventfd" + +struct eventfd_ctx +{ + rt_wqueue_t reader_queue; + rt_wqueue_t writer_queue; + rt_uint64_t count; + unsigned int flags; + struct rt_mutex lock; +}; + +#ifndef RT_USING_DFS_V2 +static int eventfd_close(struct dfs_file *file); +static int eventfd_poll(struct dfs_file *file, struct rt_pollreq *req); +static int eventfd_read(struct dfs_file *file, void *buf, size_t count); +static int eventfd_write(struct dfs_file *file, const void *buf, size_t count); +#else +static int eventfd_close(struct dfs_file *file); +static int eventfd_poll(struct dfs_file *file, struct rt_pollreq *req); +static int eventfd_read(struct dfs_file *file, void *buf, size_t count, off_t *pos); +static int eventfd_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos); +#endif + +static const struct dfs_file_ops eventfd_fops = +{ + .close = eventfd_close, + .poll = eventfd_poll, + .read = eventfd_read, + .write = eventfd_write, +}; + +static int eventfd_close(struct dfs_file *file) +{ + struct eventfd_ctx *ctx = file->vnode->data; + + rt_mutex_detach(&ctx->lock); + rt_free(ctx); + + return 0; +} + +static int eventfd_poll(struct dfs_file *file, struct rt_pollreq *req) +{ + struct eventfd_ctx *ctx = (struct eventfd_ctx *)file->vnode->data; + int events = 0; + rt_uint64_t count; + + count = ctx->count; + + rt_poll_add(&ctx->reader_queue, req); + rt_poll_add(&ctx->writer_queue, req); + + if (count > 0) + events |= POLLIN; + + if (count == ULLONG_MAX) + events |= POLLERR; + + if ((ULLONG_MAX - 1) > count) + events |= POLLOUT; + + return events; +} + +#ifndef RT_USING_DFS_V2 +static int eventfd_read(struct dfs_file *file, void *buf, size_t count) +#else +static int eventfd_read(struct dfs_file *file, void *buf, size_t count, off_t *pos) +#endif +{ + struct eventfd_ctx *ctx = (struct eventfd_ctx *)file->vnode->data; + rt_uint64_t counter_num = 0; + rt_uint64_t *buffer; + + if (count < sizeof(counter_num)) + return -EINVAL; + + buffer = (rt_uint64_t *)buf; + + rt_mutex_take(&ctx->lock, RT_WAITING_FOREVER); + + if (ctx->count == 0) + { + if (file->flags & O_NONBLOCK) + { + rt_wqueue_wakeup(&ctx->writer_queue, (void*)POLLOUT); + rt_mutex_release(&ctx->lock); + return -EAGAIN; + } + else + { + /* In this case, when the data is read in blocked mode, when ctx->count is 0, the mutex needs to be released and wait for writing */ + rt_mutex_release(&ctx->lock); + rt_wqueue_wakeup(&ctx->writer_queue, (void*)POLLOUT); + rt_wqueue_wait(&ctx->reader_queue, 0, RT_WAITING_FOREVER); + rt_mutex_take(&ctx->lock, RT_WAITING_FOREVER); + } + } + + if (ctx->flags & EFD_SEMAPHORE) + { + counter_num = 1; + } + else + { + counter_num = ctx->count; + } + + ctx->count -= counter_num; + + (*buffer) = counter_num; + + rt_mutex_release(&ctx->lock); + + return sizeof(counter_num); +} + +#ifndef RT_USING_DFS_V2 +static int eventfd_write(struct dfs_file *file, const void *buf, size_t count) +#else +static int eventfd_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos) +#endif +{ + struct eventfd_ctx *ctx = (struct eventfd_ctx *)file->vnode->data; + rt_ssize_t ret = 0; + + rt_uint64_t counter_num; + + if (count < sizeof(counter_num)) + return -EINVAL; + + counter_num = *(rt_uint64_t *)buf; + + if (counter_num == ULLONG_MAX) + return -EINVAL; + + ret = -EAGAIN; + + rt_mutex_take(&ctx->lock, RT_WAITING_FOREVER); + + if ((ULLONG_MAX - ctx->count) > counter_num) + { + ret = sizeof(counter_num); + } + else if (!(file->flags & O_NONBLOCK)) + { + for (;;) + { + if ((ULLONG_MAX - ctx->count) >= counter_num) + { + ret = sizeof(counter_num); + break; + } + /* Release the mutex to avoid a deadlock */ + rt_mutex_release(&ctx->lock); + rt_wqueue_wait(&ctx->writer_queue, 0, RT_WAITING_FOREVER); + rt_wqueue_wakeup(&ctx->reader_queue, (void *)POLLIN); + rt_mutex_take(&ctx->lock, RT_WAITING_FOREVER); + } + } + + if (ret > 0) + { + ctx->count += counter_num; + rt_wqueue_wakeup(&ctx->reader_queue, (void *)POLLIN); + } + + rt_mutex_release(&ctx->lock); + + return ret; +} + +static int rt_eventfd_create(struct dfs_file *df, unsigned int count, int flags) +{ + struct eventfd_ctx *ctx = RT_NULL; + rt_err_t ret = 0; + + ctx = (struct eventfd_ctx *)rt_malloc(sizeof(struct eventfd_ctx)); + if (ctx == RT_NULL) + { + ret = -ENOMEM; + } + else + { + ctx->count = count; + ctx->flags = flags; + flags &= EFD_SHARED_FCNTL_FLAGS; + flags |= O_RDWR; + + rt_mutex_init(&ctx->lock, EVENTFD_MUTEX_NAME, RT_IPC_FLAG_FIFO); + rt_wqueue_init(&ctx->reader_queue); + rt_wqueue_init(&ctx->writer_queue); + + df->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode)); + if (df->vnode) + { + dfs_vnode_init(df->vnode, FT_REGULAR, &eventfd_fops); + df->vnode->data = ctx; + df->flags = flags; + } + else + { + rt_mutex_detach(&ctx->lock); + rt_free(ctx); + ret = -ENOMEM; + } + } + + return ret; +} + +static int do_eventfd(unsigned int count, int flags) +{ + struct dfs_file *file; + int fd; + int status; + rt_ssize_t ret = 0; + + if (flags & ~EFD_FLAGS_SET) + return -RT_EINVAL; + + fd = fd_new(); + if (fd >= 0) + { + ret = fd; + file = fd_get(fd); + + status = rt_eventfd_create(file, count, flags); + if (status < 0) + { + fd_release(fd); + ret = status; + } + } + else + { + ret = fd; + } + + return ret; +} + +int eventfd(unsigned int count, int flags) +{ + return do_eventfd(count, flags); +} diff --git a/components/libc/posix/io/eventfd/eventfd.h b/components/libc/posix/io/eventfd/eventfd.h new file mode 100644 index 0000000000..8b3bc4edc4 --- /dev/null +++ b/components/libc/posix/io/eventfd/eventfd.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-20 zmq810150896 First version + */ + +#ifndef __EVENTFD_H__ +#define __EVENTFD_H__ + +int eventfd(unsigned int count, int flags); + +#endif /* __EVENTFD_H__ */ diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 7f04271dac..3dc743b182 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -41,6 +41,7 @@ #include #ifdef RT_USING_DFS +#include #include #include #include @@ -5317,6 +5318,14 @@ sysret_t sys_symlink(const char *existing, const char *new) return (ret < 0 ? GET_ERRNO() : ret); } +sysret_t sys_eventfd2(unsigned int count, int flags) +{ + int ret; + + ret = eventfd(count, flags); + return (ret < 0 ? GET_ERRNO() : ret); +} + static const struct rt_syscall_def func_table[] = { SYSCALL_SIGN(sys_exit), /* 01 */ @@ -5548,6 +5557,7 @@ static const struct rt_syscall_def func_table[] = SYSCALL_SIGN(sys_sigtimedwait), SYSCALL_SIGN(sys_notimpl), SYSCALL_SIGN(sys_notimpl), /* 190 */ + SYSCALL_SIGN(sys_eventfd2), }; const void *lwp_get_sys_api(rt_uint32_t number)