aboutsummaryrefslogtreecommitdiff
path: root/src/lib/libkogata/mainloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libkogata/mainloop.c')
-rw-r--r--src/lib/libkogata/mainloop.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/lib/libkogata/mainloop.c b/src/lib/libkogata/mainloop.c
new file mode 100644
index 0000000..d3c0c50
--- /dev/null
+++ b/src/lib/libkogata/mainloop.c
@@ -0,0 +1,135 @@
+#include <malloc.h>
+#include <string.h>
+
+#include <mainloop.h>
+
+mainloop_fd_t *mainloop_fds = 0;
+bool mainloop_fds_change = false;
+bool mainloop_must_exit = false;
+
+void mainloop_add_fd(mainloop_fd_t* fd) {
+ mainloop_fds_change = true;
+
+ fd->next = mainloop_fds;
+ mainloop_fds = fd;
+
+ fd->rd_buf_filled = 0;
+}
+
+void mainloop_rm_fd(mainloop_fd_t* fd) {
+ mainloop_fds_change = true;
+
+ if (mainloop_fds == fd) {
+ mainloop_fds = fd->next;
+ } else {
+ for (mainloop_fd_t *it = mainloop_fds; it->next != 0; it = it->next) {
+ if (it->next == fd) {
+ it->next = fd->next;
+ break;
+ }
+ }
+ }
+}
+
+void mainloop_expect(mainloop_fd_t *fd, void* buf, size_t size, buf_full_callback_t cb) {
+ fd->rd_buf = buf;
+ fd->rd_on_full = cb;
+ fd->rd_buf_expect_size = size;
+ fd->rd_buf_filled = 0;
+}
+
+bool mainloop_nonblocking_write(mainloop_fd_t *fd, void* buf, size_t size, bool must_free_buf) {
+ for (int i = 0; i < MAINLOOP_MAX_WR_BUFS; i++) {
+ if (fd->wr_bufs[i].buf == 0) {
+ fd->wr_bufs[i].buf = buf;
+ fd->wr_bufs[i].written = 0;
+ fd->wr_bufs[i].size = size;
+ fd->wr_bufs[i].must_free = must_free_buf;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void mainloop_run() {
+ sel_fd_t *sel_arg = 0;
+ int nfds = 0;
+
+ mainloop_fds_change = true;
+ mainloop_must_exit = false;
+ while(!mainloop_must_exit) {
+ if (mainloop_fds_change) {
+ nfds = 0;
+ for (mainloop_fd_t *fd = mainloop_fds; fd != 0; fd = fd->next)
+ nfds++;
+
+ if (sel_arg != 0) free(sel_arg);
+ sel_arg = (sel_fd_t*)malloc(nfds * sizeof(sel_fd_t));
+ if (sel_arg == 0) {
+ dbg_printf("(mainloop) Out of memory.\n");
+ return;
+ }
+
+
+ mainloop_fds_change = false;
+ }
+
+ { // Setup flags we are waiting for
+ int i = 0;
+ for (mainloop_fd_t *fd = mainloop_fds; fd != 0; fd = fd->next) {
+ sel_arg[i].fd = fd->fd;
+ sel_arg[i].req_flags =
+ (fd->rd_buf != 0 ? SEL_READ : 0)
+ | (fd->wr_bufs[0].buf != 0 ? SEL_WRITE : 0) | SEL_ERROR;
+ i++;
+ }
+ }
+
+ // ---- Do the select
+ bool ok = select(sel_arg, nfds, -1);
+ if (!ok) {
+ dbg_printf("(mainloop) Failed to select.\n");
+ free(sel_arg);
+ return;
+ }
+
+ { // Parse result
+ int i = 0;
+ for (mainloop_fd_t *fd = mainloop_fds; fd != 0 && !mainloop_fds_change; fd = fd->next) {
+ if (sel_arg[i].got_flags & SEL_ERROR) {
+ fd->on_error(fd);
+ } else if ((sel_arg[i].got_flags & SEL_READ) && fd->rd_buf != 0) {
+ fd->rd_buf_filled +=
+ read(fd->fd, 0, fd->rd_buf_expect_size - fd->rd_buf_filled, fd->rd_buf + fd->rd_buf_filled);
+ if (fd->rd_buf_filled == fd->rd_buf_expect_size) {
+ fd->rd_buf_filled = 0;
+ fd->rd_on_full(fd);
+ }
+ } else if ((sel_arg[i].got_flags & SEL_WRITE) && fd->wr_bufs[0].buf != 0) {
+ size_t remain_size = fd->wr_bufs[0].size - fd->wr_bufs[0].written;
+ void* write_ptr = fd->wr_bufs[0].buf + fd->wr_bufs[0].written;
+
+ fd->wr_bufs[0].written += write(fd->fd, 0, remain_size, write_ptr);
+
+ if (fd->wr_bufs[0].written == fd->wr_bufs[0].size) {
+ if (fd->wr_bufs[0].must_free) free(fd->wr_bufs[0].buf);
+ for (int i = 1; i < MAINLOOP_MAX_WR_BUFS; i++) {
+ fd->wr_bufs[i-1] = fd->wr_bufs[i];
+ }
+ memset(&fd->wr_bufs[MAINLOOP_MAX_WR_BUFS-1].buf, 0, sizeof(mainloop_wr_buf_t));
+ }
+ }
+ i++;
+ }
+ }
+ }
+}
+
+void mainloop_exit() {
+ mainloop_must_exit = true;
+}
+
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/