summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKacper <kacper@mail.openlinux.dev>2025-12-15 02:01:33 +0100
committerKacper <kacper@mail.openlinux.dev>2025-12-15 02:01:59 +0100
commit3b3325f761b09ebbfef04c44eed546cc4fdeb329 (patch)
treeaa19ea259bcda2410c2b3dd4512f19fb85aeaf8f /lib
parent15d2df7811ef3cb79cc3e501d0d5f9b993d42bea (diff)
Added aio and eventfd support, along with sleep and yes utilities
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/Kbuild1
-rw-r--r--lib/libc/aio/Kbuild9
-rw-r--r--lib/libc/aio/aio.c150
-rw-r--r--lib/libc/aio/aio_cancel.c47
-rw-r--r--lib/libc/aio/aio_error.c26
-rw-r--r--lib/libc/aio/aio_fsync.c26
-rw-r--r--lib/libc/aio/aio_read.c16
-rw-r--r--lib/libc/aio/aio_return.c26
-rw-r--r--lib/libc/aio/aio_suspend.c57
-rw-r--r--lib/libc/aio/aio_write.c16
-rw-r--r--lib/libc/aio/lio_listio.c82
-rw-r--r--lib/libc/arch/x86_64/crt0.c15
-rw-r--r--lib/libc/err/err.c1
-rw-r--r--lib/libc/err/errx.c1
-rw-r--r--lib/libc/err/verr.c1
-rw-r--r--lib/libc/err/verrx.c1
-rw-r--r--lib/libc/err/vwarn.c1
-rw-r--r--lib/libc/err/vwarnx.c1
-rw-r--r--lib/libc/include/__aio.h35
-rw-r--r--lib/libc/include/io_uring.h53
-rw-r--r--lib/libc/string/strerror.c1
-rw-r--r--lib/libc/sys/Kbuild6
-rw-r--r--lib/libc/sys/eventfd.c6
-rw-r--r--lib/libc/sys/eventfd_read.c8
-rw-r--r--lib/libc/sys/eventfd_write.c8
-rw-r--r--lib/libc/sys/io_uring_enter.c10
-rw-r--r--lib/libc/sys/io_uring_register.c7
-rw-r--r--lib/libc/sys/io_uring_setup.c81
28 files changed, 688 insertions, 4 deletions
diff --git a/lib/libc/Kbuild b/lib/libc/Kbuild
index 55ec6422..7de874f6 100644
--- a/lib/libc/Kbuild
+++ b/lib/libc/Kbuild
@@ -2,6 +2,7 @@ lib-y := libc.a
cflags-y += -I $(src)/include
+obj-y += aio/
obj-y += arch/
obj-y += arpa/
obj-y += assert/
diff --git a/lib/libc/aio/Kbuild b/lib/libc/aio/Kbuild
new file mode 100644
index 00000000..6bd83c98
--- /dev/null
+++ b/lib/libc/aio/Kbuild
@@ -0,0 +1,9 @@
+obj-y += aio.o
+obj-y += aio_cancel.o
+obj-y += aio_error.o
+obj-y += aio_fsync.o
+obj-y += aio_read.o
+obj-y += aio_return.o
+obj-y += aio_suspend.o
+obj-y += aio_write.o
+obj-y += lio_listio.o
diff --git a/lib/libc/aio/aio.c b/lib/libc/aio/aio.c
new file mode 100644
index 00000000..0ca2ec64
--- /dev/null
+++ b/lib/libc/aio/aio.c
@@ -0,0 +1,150 @@
+#include <__aio.h>
+#include <io_uring.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct aio_context __aio_context = { 0 };
+
+// TODO
+// static void *__aio_thread_notify(void *arg)
+// {
+// struct sigevent *sev = arg;
+// sev->sigev_notify_function(sev->sigev_value);
+// return NULL;
+// }
+
+static void __aio_deliver_signal(struct sigevent *sev)
+{
+ if (!sev)
+ return;
+
+ switch (sev->sigev_notify) {
+ case SIGEV_SIGNAL:
+ kill(getpid(), sev->sigev_signo);
+ break;
+
+ case SIGEV_THREAD: {
+ // TODO
+ // pthread_t thread;
+ // pthread_create(&thread, NULL, __aio_thread_notify, sev);
+ // pthread_detach(thread);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+static void __aio_complete(struct aio_request *req, int res)
+{
+ req->result = res;
+ req->status = AIO_REQUEST_STATUS_COMPLETED;
+
+ if (req->grp) {
+ if (res < 0)
+ req->grp->error = 1;
+
+ if (--req->grp->pending == 0) {
+ uint64_t one = 1;
+ write(req->grp->eventfd, &one, sizeof(one));
+
+ if (req->grp->sig) {
+ __aio_deliver_signal(req->grp->sig);
+ }
+ }
+ }
+}
+
+int __aio_request(struct aio_request *req, int opcode)
+{
+ struct io_uring_sqe *sqe;
+ unsigned index, tail;
+
+ if (req == NULL)
+ return -1;
+
+ tail = *__io_uring.sq.tail;
+ index = tail & *__io_uring.sq.ring_mask;
+
+ sqe = &__io_uring.sq.sqes[index];
+ memset(sqe, 0, sizeof(*sqe));
+ sqe->opcode = opcode;
+ sqe->fd = req->aiocbp->aio_fildes;
+ sqe->addr = (uint64_t)req->aiocbp->aio_buf;
+ sqe->len = req->aiocbp->aio_nbytes;
+ sqe->off = req->aiocbp->aio_offset;
+ sqe->user_data = (uint64_t)req;
+
+ __io_uring.sq.array[index] = index;
+ *__io_uring.sq.tail = tail + 1;
+
+ io_uring_enter(__io_uring.fd, 1, 0, IORING_ENTER_GETEVENTS, NULL, 0);
+
+ req->status = AIO_REQUEST_STATUS_PENDING;
+ req->next = NULL;
+
+ if (__aio_context.head == NULL) {
+ __aio_context.head = __aio_context.tail = req;
+ } else {
+ __aio_context.tail->next = req;
+ __aio_context.tail = req;
+ }
+
+ return 0;
+}
+
+void __aio_poll(void)
+{
+ unsigned head = *__io_uring.cq.head;
+ unsigned tail = *__io_uring.cq.tail;
+
+ while (head != tail) {
+ struct io_uring_cqe *cqe =
+ &__io_uring.cq.cqes[head & *__io_uring.cq.ring_mask];
+
+ struct aio_request *req = (struct aio_request *)cqe->user_data;
+
+ __aio_complete(req, cqe->res);
+
+ head++;
+ }
+
+ *__io_uring.cq.head = head;
+}
+
+struct aio_request *__aio_lookup(const struct aiocb *aiocbp)
+{
+ struct aio_request *req = __aio_context.head;
+
+ while (req != NULL) {
+ if (req->aiocbp == aiocbp)
+ return req;
+
+ req = req->next;
+ }
+
+ return NULL;
+}
+
+struct aio_request *__aio_remove(const struct aiocb *aiocbp)
+{
+ struct aio_request **cur = &__aio_context.head;
+ struct aio_request *req = NULL;
+
+ while (*cur) {
+ if ((*cur)->aiocbp == aiocbp) {
+ req = *cur;
+ *cur = req->next;
+ if (__aio_context.tail == req)
+ __aio_context.tail = NULL;
+ break;
+ }
+ cur = &(*cur)->next;
+ }
+
+ return req;
+}
diff --git a/lib/libc/aio/aio_cancel.c b/lib/libc/aio/aio_cancel.c
new file mode 100644
index 00000000..b4d373bf
--- /dev/null
+++ b/lib/libc/aio/aio_cancel.c
@@ -0,0 +1,47 @@
+#include <__aio.h>
+#include <errno.h>
+#include <io_uring.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+int aio_cancel(int __unused fildes, struct aiocb *aiocbp)
+{
+ unsigned tail;
+ struct aio_request *req;
+ struct io_uring_sqe sqe;
+
+ if (aiocbp == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ req = __aio_lookup(aiocbp);
+
+ if (req == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (req->status == AIO_REQUEST_STATUS_COMPLETED) {
+ return AIO_ALLDONE;
+ }
+
+ memset(&sqe, 0, sizeof(sqe));
+ sqe.opcode = IORING_OP_ASYNC_CANCEL;
+ sqe.user_data = (uint64_t)req;
+
+ tail = *__io_uring.sq.tail;
+ __io_uring.sq.sqes[tail % IO_URING_ENTRIES] = sqe;
+ __io_uring.sq.array[tail % IO_URING_ENTRIES] = tail % IO_URING_ENTRIES;
+ *__io_uring.sq.tail = tail + 1;
+
+ io_uring_enter(__io_uring.fd, 1, 0, IORING_ENTER_GETEVENTS, NULL, 0);
+
+ __aio_remove(aiocbp);
+ free(req);
+
+ return AIO_CANCELED;
+}
diff --git a/lib/libc/aio/aio_error.c b/lib/libc/aio/aio_error.c
new file mode 100644
index 00000000..27c7f134
--- /dev/null
+++ b/lib/libc/aio/aio_error.c
@@ -0,0 +1,26 @@
+#include <__aio.h>
+#include <errno.h>
+#include <stddef.h>
+
+int aio_error(const struct aiocb *aiocbp)
+{
+ struct aio_request *req;
+
+ if (aiocbp == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ req = __aio_lookup(aiocbp);
+
+ if (req == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (req->status == AIO_REQUEST_STATUS_PENDING) {
+ return EINPROGRESS;
+ }
+
+ return req->result < 0 ? -req->result : 0;
+}
diff --git a/lib/libc/aio/aio_fsync.c b/lib/libc/aio/aio_fsync.c
new file mode 100644
index 00000000..00d56b42
--- /dev/null
+++ b/lib/libc/aio/aio_fsync.c
@@ -0,0 +1,26 @@
+#include <__aio.h>
+#include <aio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io_uring.h>
+
+int aio_fsync(int op, struct aiocb *aiocbp)
+{
+ int opcode;
+ struct aio_request *req;
+
+ req = __aio_lookup(aiocbp);
+
+ if (req == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (op == O_DSYNC) {
+ opcode = IORING_OP_FSYNC | IORING_FSYNC_DATASYNC;
+ } else {
+ opcode = IORING_OP_FSYNC;
+ }
+
+ return __aio_request(req, opcode);
+}
diff --git a/lib/libc/aio/aio_read.c b/lib/libc/aio/aio_read.c
new file mode 100644
index 00000000..286b2d02
--- /dev/null
+++ b/lib/libc/aio/aio_read.c
@@ -0,0 +1,16 @@
+#include <__aio.h>
+#include <aio.h>
+#include <io_uring.h>
+#include <stdlib.h>
+
+int aio_read(struct aiocb *aiocbp)
+{
+ struct aio_request *req = malloc(sizeof(*req));
+
+ if (req == NULL)
+ return -1;
+
+ req->aiocbp = aiocbp;
+
+ return __aio_request(req, IORING_OP_READ);
+}
diff --git a/lib/libc/aio/aio_return.c b/lib/libc/aio/aio_return.c
new file mode 100644
index 00000000..45b0d795
--- /dev/null
+++ b/lib/libc/aio/aio_return.c
@@ -0,0 +1,26 @@
+#include <__aio.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+ssize_t aio_return(struct aiocb *aiocbp)
+{
+ ssize_t result;
+ struct aio_request *req;
+
+ if (aiocbp == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ req = __aio_remove(aiocbp);
+
+ if (req->status == AIO_REQUEST_STATUS_PENDING) {
+ free(req);
+ return -1;
+ }
+
+ result = req->result;
+ free(req);
+ return result;
+}
diff --git a/lib/libc/aio/aio_suspend.c b/lib/libc/aio/aio_suspend.c
new file mode 100644
index 00000000..939b9d6b
--- /dev/null
+++ b/lib/libc/aio/aio_suspend.c
@@ -0,0 +1,57 @@
+#include <__aio.h>
+#include <aio.h>
+#include <errno.h>
+#include <io_uring.h>
+#include <poll.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+
+int aio_suspend(const struct aiocb *const list[], int nent,
+ const struct timespec *timeout)
+{
+ struct pollfd pfd;
+ struct aio_request *req;
+
+ if ((void *)list == NULL || nent <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (1) {
+ int timeout_ms, ret;
+ __aio_poll();
+
+ for (int i = 0; i < nent; i++) {
+ req = __aio_lookup((struct aiocb *)list[i]);
+ if (req && req->status == AIO_REQUEST_STATUS_COMPLETED)
+ return 0;
+ }
+
+ pfd.fd = __io_uring.eventfd;
+ pfd.events = POLLIN;
+
+ if (timeout) {
+ timeout_ms = timeout->tv_sec * 1000 +
+ timeout->tv_nsec / 1000000;
+ } else {
+ timeout_ms = -1;
+ }
+
+ ret = poll(&pfd, 1, timeout_ms);
+
+ if (ret == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (ret < 0) {
+ return -1;
+ }
+
+ uint64_t val;
+ read(__io_uring.eventfd, &val, sizeof(val));
+ io_uring_enter(__io_uring.fd, 0, 0, IORING_ENTER_GETEVENTS,
+ NULL, 0);
+ }
+}
diff --git a/lib/libc/aio/aio_write.c b/lib/libc/aio/aio_write.c
new file mode 100644
index 00000000..4254fdcd
--- /dev/null
+++ b/lib/libc/aio/aio_write.c
@@ -0,0 +1,16 @@
+#include <__aio.h>
+#include <aio.h>
+#include <io_uring.h>
+#include <stdlib.h>
+
+int aio_write(struct aiocb *aiocbp)
+{
+ struct aio_request *req = malloc(sizeof(*req));
+
+ if (req == NULL)
+ return -1;
+
+ req->aiocbp = aiocbp;
+
+ return __aio_request(req, IORING_OP_WRITE);
+}
diff --git a/lib/libc/aio/lio_listio.c b/lib/libc/aio/lio_listio.c
new file mode 100644
index 00000000..0a345c16
--- /dev/null
+++ b/lib/libc/aio/lio_listio.c
@@ -0,0 +1,82 @@
+#include <__aio.h>
+#include <aio.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <stdint.h>
+
+int lio_listio(int mode, struct aiocb *restrict const list[restrict], int nent,
+ struct sigevent *restrict sig)
+{
+ struct lio_group *grp = NULL;
+
+ if ((void *)list == NULL || nent <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (mode != LIO_WAIT && mode != LIO_NOWAIT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ grp = malloc(sizeof(*grp));
+ memset(grp, 0, sizeof(*grp));
+
+ grp->eventfd = eventfd(0, EFD_CLOEXEC);
+ grp->sig = sig;
+
+ for (int i = 0; i < nent; i++) {
+ int ret;
+ struct aio_request *req;
+ struct aiocb *aiocbp = list[i];
+
+ if (aiocbp == NULL) {
+ continue;
+ }
+
+ switch (aiocbp->aio_lio_opcode) {
+ case LIO_READ:
+ ret = aio_read(aiocbp);
+ break;
+ case LIO_WRITE:
+ ret = aio_write(aiocbp);
+ break;
+ case LIO_NOP:
+ ret = 0;
+ continue;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ret < 0) {
+ return -1;
+ }
+
+ req = __aio_lookup(aiocbp);
+ req->grp = grp;
+ grp->pending++;
+ }
+
+ if (mode == LIO_NOWAIT) {
+ return 0;
+ }
+
+ while (grp->pending > 0) {
+ uint64_t val;
+ if (read(grp->eventfd, &val, sizeof(val)) < 0) {
+ return -1;
+ }
+ }
+
+ if (grp->error) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/arch/x86_64/crt0.c b/lib/libc/arch/x86_64/crt0.c
index a278c525..c60239d3 100644
--- a/lib/libc/arch/x86_64/crt0.c
+++ b/lib/libc/arch/x86_64/crt0.c
@@ -1,9 +1,9 @@
+#include "asm/auxvec.h" // for AT_SYSINFO_EHDR
+#include <io_uring.h>
#include <linux/auxvec.h> // for AT_NULL
#include <linux/elf.h> // for Elf64_Ehdr
-#include "asm/auxvec.h" // for AT_SYSINFO_EHDR
-
-#include <stdint.h> // for uintptr_t
-#include <stdlib.h> // for exit
+#include <stdint.h> // for uintptr_t
+#include <stdlib.h> // for exit
#define weak_reference(old, new) \
extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
@@ -23,6 +23,11 @@ static void __vdso_setup(Elf64_Ehdr *vdso_addr __attribute__((unused)))
weak_reference(__vdso_setup, vdso_setup);
+static void __io_uring_setup_(void)
+{
+}
+weak_reference(__io_uring_setup_, __io_uring_setup);
+
__attribute__((used)) void __libc_start(uintptr_t *sp)
{
char **argv;
@@ -46,6 +51,8 @@ __attribute__((used)) void __libc_start(uintptr_t *sp)
__auxv++;
}
+ __io_uring_setup_();
+
exit(main(argc, argv));
}
diff --git a/lib/libc/err/err.c b/lib/libc/err/err.c
index 5b1b2b02..95e079d5 100644
--- a/lib/libc/err/err.c
+++ b/lib/libc/err/err.c
@@ -1,3 +1,4 @@
+#include "sys/cdefs.h"
#include <err.h>
#include <stdarg.h>
diff --git a/lib/libc/err/errx.c b/lib/libc/err/errx.c
index 0afe999e..ab9c609d 100644
--- a/lib/libc/err/errx.c
+++ b/lib/libc/err/errx.c
@@ -1,3 +1,4 @@
+#include "sys/cdefs.h"
#include <err.h>
#include <stdarg.h>
diff --git a/lib/libc/err/verr.c b/lib/libc/err/verr.c
index d769c15c..75023ab3 100644
--- a/lib/libc/err/verr.c
+++ b/lib/libc/err/verr.c
@@ -1,3 +1,4 @@
+#include "sys/cdefs.h"
#include <err.h>
#include <stdarg.h>
#include <stdlib.h>
diff --git a/lib/libc/err/verrx.c b/lib/libc/err/verrx.c
index d769c15c..75023ab3 100644
--- a/lib/libc/err/verrx.c
+++ b/lib/libc/err/verrx.c
@@ -1,3 +1,4 @@
+#include "sys/cdefs.h"
#include <err.h>
#include <stdarg.h>
#include <stdlib.h>
diff --git a/lib/libc/err/vwarn.c b/lib/libc/err/vwarn.c
index 2f485d93..c90286fb 100644
--- a/lib/libc/err/vwarn.c
+++ b/lib/libc/err/vwarn.c
@@ -1,3 +1,4 @@
+#include "stddef.h"
#include <stdarg.h>
#include <stdio.h>
diff --git a/lib/libc/err/vwarnx.c b/lib/libc/err/vwarnx.c
index 2f485d93..c90286fb 100644
--- a/lib/libc/err/vwarnx.c
+++ b/lib/libc/err/vwarnx.c
@@ -1,3 +1,4 @@
+#include "stddef.h"
#include <stdarg.h>
#include <stdio.h>
diff --git a/lib/libc/include/__aio.h b/lib/libc/include/__aio.h
new file mode 100644
index 00000000..93cb1f79
--- /dev/null
+++ b/lib/libc/include/__aio.h
@@ -0,0 +1,35 @@
+#ifndef __LIBC_AIO_H
+#define __LIBC_AIO_H
+
+#include <aio.h>
+
+#define AIO_REQUEST_STATUS_PENDING 0
+#define AIO_REQUEST_STATUS_COMPLETED 1
+
+struct lio_group {
+ int pending;
+ int error;
+ int eventfd;
+ struct sigevent *sig;
+};
+
+struct aio_context {
+ struct aio_request *head;
+ struct aio_request *tail;
+};
+
+struct aio_request {
+ struct aiocb *aiocbp;
+ int status;
+ ssize_t result;
+ struct aio_request *next;
+ struct lio_group *grp;
+};
+
+void __aio_poll(void);
+
+int __aio_request(struct aio_request *, int);
+struct aio_request *__aio_lookup(const struct aiocb *);
+struct aio_request *__aio_remove(const struct aiocb *);
+
+#endif
diff --git a/lib/libc/include/io_uring.h b/lib/libc/include/io_uring.h
new file mode 100644
index 00000000..4dac4583
--- /dev/null
+++ b/lib/libc/include/io_uring.h
@@ -0,0 +1,53 @@
+#ifndef __LIBC_IO_URING_H
+#define __LIBC_IO_URING_H
+
+#include <linux/io_uring.h>
+#include <signal.h>
+
+#define IO_URING_ENTRIES 256
+
+struct io_uring_sq {
+ void *ring;
+ size_t ring_size;
+ struct io_uring_sqe *sqes;
+
+ unsigned *head;
+ unsigned *tail;
+ unsigned *ring_mask;
+ unsigned *ring_entries;
+ unsigned *flags;
+ unsigned *dropped;
+ unsigned *array;
+};
+
+struct io_uring_cq {
+ void *ring;
+ size_t ring_size;
+
+ unsigned *head;
+ unsigned *tail;
+ unsigned *ring_mask;
+ unsigned *ring_entries;
+ unsigned *overflow;
+ struct io_uring_cqe *cqes;
+ unsigned *flags;
+};
+
+struct io_uring {
+ int fd;
+ int eventfd;
+
+ struct io_uring_sq sq;
+ struct io_uring_cq cq;
+};
+
+extern struct io_uring __io_uring;
+
+int io_uring_setup(unsigned int, struct io_uring_params *);
+
+int io_uring_register(unsigned int, unsigned int, void *, unsigned int);
+
+int io_uring_enter(unsigned int, unsigned int, unsigned int, unsigned int,
+ sigset_t *, size_t);
+
+#endif
diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c
index 2d3ea611..62bcea76 100644
--- a/lib/libc/string/strerror.c
+++ b/lib/libc/string/strerror.c
@@ -1,5 +1,6 @@
#include "features.h" // for __weak
+#include "stddef.h"
#include <errno.h> // for ERANGE, E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL
#include <libc.h> // for __unused
#include <string.h> // for memcpy, size_t, strerror, strlen, locale_t
diff --git a/lib/libc/sys/Kbuild b/lib/libc/sys/Kbuild
index 1bf1dcba..fe9d0bfc 100644
--- a/lib/libc/sys/Kbuild
+++ b/lib/libc/sys/Kbuild
@@ -1,3 +1,9 @@
+obj-y += eventfd_read.o
+obj-y += eventfd_write.o
+obj-y += eventfd.o
+obj-y += io_uring_enter.o
+obj-y += io_uring_register.o
+obj-y += io_uring_setup.o
obj-y += ioctl.o
obj-y += mount.o
obj-y += reboot.o
diff --git a/lib/libc/sys/eventfd.c b/lib/libc/sys/eventfd.c
new file mode 100644
index 00000000..b0fb5d86
--- /dev/null
+++ b/lib/libc/sys/eventfd.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int eventfd(unsigned int initval, int flags)
+{
+ return syscall(eventfd2, initval, flags);
+}
diff --git a/lib/libc/sys/eventfd_read.c b/lib/libc/sys/eventfd_read.c
new file mode 100644
index 00000000..78d73623
--- /dev/null
+++ b/lib/libc/sys/eventfd_read.c
@@ -0,0 +1,8 @@
+#include <sys/eventfd.h>
+#include <syscall.h>
+#include <unistd.h>
+
+int eventfd_read(int fildes, eventfd_t *value)
+{
+ return (sizeof(*value) == read(fildes, value, sizeof(*value))) ? 0 : -1;
+}
diff --git a/lib/libc/sys/eventfd_write.c b/lib/libc/sys/eventfd_write.c
new file mode 100644
index 00000000..9c89b388
--- /dev/null
+++ b/lib/libc/sys/eventfd_write.c
@@ -0,0 +1,8 @@
+#include <sys/eventfd.h>
+#include <syscall.h>
+#include <unistd.h>
+
+int eventfd_write(int fildes, eventfd_t value)
+{
+ return (sizeof(value) == write(fildes, &value, sizeof(value))) ? 0 : -1;
+}
diff --git a/lib/libc/sys/io_uring_enter.c b/lib/libc/sys/io_uring_enter.c
new file mode 100644
index 00000000..5fe0773d
--- /dev/null
+++ b/lib/libc/sys/io_uring_enter.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+#include <syscall.h>
+
+int io_uring_enter(unsigned int fd, unsigned int to_submit,
+ unsigned int min_complete, unsigned int flags, sigset_t *sig,
+ size_t sz)
+{
+ return syscall(io_uring_enter, fd, to_submit, min_complete, flags, sig,
+ sz);
+}
diff --git a/lib/libc/sys/io_uring_register.c b/lib/libc/sys/io_uring_register.c
new file mode 100644
index 00000000..bee2355f
--- /dev/null
+++ b/lib/libc/sys/io_uring_register.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+
+int io_uring_register(unsigned int fd, unsigned int opcode, void *arg,
+ unsigned int nr_args)
+{
+ return syscall(io_uring_register, fd, opcode, arg, nr_args);
+}
diff --git a/lib/libc/sys/io_uring_setup.c b/lib/libc/sys/io_uring_setup.c
new file mode 100644
index 00000000..0a368a81
--- /dev/null
+++ b/lib/libc/sys/io_uring_setup.c
@@ -0,0 +1,81 @@
+#include <sys/eventfd.h>
+#include <io_uring.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <syscall.h>
+
+struct io_uring __io_uring;
+
+int io_uring_setup(unsigned int entries, struct io_uring_params *params)
+{
+ return syscall(io_uring_setup, entries, params);
+}
+
+int __io_uring_setup(void)
+{
+ struct io_uring_params p;
+ memset(&p, 0, sizeof(p));
+
+ __io_uring.fd = io_uring_setup(IO_URING_ENTRIES, &p);
+
+ if (__io_uring.fd < 0)
+ return -1;
+
+ __io_uring.sq.ring_size =
+ p.sq_off.array + p.sq_entries * sizeof(unsigned int);
+ __io_uring.sq.ring = mmap(NULL, __io_uring.sq.ring_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, __io_uring.fd,
+ IORING_OFF_SQ_RING);
+
+ if (__io_uring.sq.ring == MAP_FAILED)
+ return -1;
+
+ __io_uring.sq.head = __io_uring.sq.ring + p.sq_off.head;
+ __io_uring.sq.tail = __io_uring.sq.ring + p.sq_off.tail;
+ __io_uring.sq.ring_mask = __io_uring.sq.ring + p.sq_off.ring_mask;
+ __io_uring.sq.ring_entries = __io_uring.sq.ring + p.sq_off.ring_entries;
+ __io_uring.sq.flags = __io_uring.sq.ring + p.sq_off.flags;
+ __io_uring.sq.dropped = __io_uring.sq.ring + p.sq_off.dropped;
+ __io_uring.sq.array = __io_uring.sq.ring + p.sq_off.array;
+ __io_uring.sq.sqes =
+ mmap(NULL, p.sq_entries * sizeof(struct io_uring_sqe),
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
+ __io_uring.fd, IORING_OFF_SQES);
+
+ if (__io_uring.sq.sqes == MAP_FAILED) {
+ munmap(__io_uring.sq.ring, __io_uring.sq.ring_size);
+ return -1;
+ }
+
+ __io_uring.cq.ring_size =
+ p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
+ __io_uring.cq.ring = mmap(NULL, __io_uring.cq.ring_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, __io_uring.fd,
+ IORING_OFF_CQ_RING);
+
+ if (__io_uring.cq.ring == MAP_FAILED) {
+ munmap(__io_uring.sq.ring, __io_uring.sq.ring_size);
+ munmap(__io_uring.sq.sqes,
+ p.sq_entries * sizeof(struct io_uring_sqe));
+ return -1;
+ }
+
+ __io_uring.eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+ if (__io_uring.eventfd < 0)
+ return -1;
+
+ io_uring_register(__io_uring.fd, IORING_REGISTER_EVENTFD,
+ &__io_uring.eventfd, 1);
+
+ __io_uring.cq.head = __io_uring.cq.ring + p.cq_off.head;
+ __io_uring.cq.tail = __io_uring.cq.ring + p.cq_off.tail;
+ __io_uring.cq.ring_mask = __io_uring.cq.ring + p.cq_off.ring_mask;
+ __io_uring.cq.ring_entries = __io_uring.cq.ring + p.cq_off.ring_entries;
+ __io_uring.cq.overflow = __io_uring.cq.ring + p.cq_off.overflow;
+ __io_uring.cq.cqes = __io_uring.cq.ring + p.cq_off.cqes;
+ __io_uring.cq.flags = __io_uring.cq.ring + p.cq_off.flags;
+
+ return 0;
+}