blob: 75fb2529a996fd88cdf346b0f3a7140552d62391 (
plain) (
tree)
|
|
#include <stdlib.h>
#include <string.h>
#include <kogata/mainloop.h>
mainloop_fd_t *mainloop_fds = 0;
bool mainloop_fds_change = false;
bool mainloop_must_exit = false;
idle_callback_t mainloop_idle_cb = 0;
void* mainloop_idle_cb_data = 0;
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_when_idle(idle_callback_t cb, void* data) {
mainloop_idle_cb = cb;
mainloop_idle_cb_data = data;
}
void mainloop_run() {
sel_fd_t *sel_arg = 0;
int nfds = 0;
mainloop_fds_change = true;
mainloop_must_exit = false;
bool after_idle_step = 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 (nfds == 0) return;
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
/*dbg_printf("(mainloop) begin select\n");*/
bool ok = sc_select(sel_arg, nfds, (after_idle_step || mainloop_idle_cb == 0 ? -1 : 0));
if (!ok) {
// nothing happenned
if (mainloop_idle_cb != 0) mainloop_idle_cb(mainloop_idle_cb_data);
after_idle_step = true;
continue;
}
/*dbg_printf("(mainloop) end select\n");*/
{ // 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) {
ASSERT(fd->on_error != 0);
fd->on_error(fd);
} else if ((sel_arg[i].got_flags & SEL_READ) && fd->rd_buf != 0) {
fd->rd_buf_filled +=
sc_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) {
/*dbg_printf("(mainloop) finish read %d\n", fd->rd_buf_expect_size);*/
fd->rd_buf_filled = 0;
ASSERT(fd->rd_on_full != 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 += sc_write(fd->fd, 0, remain_size, write_ptr);
if (fd->wr_bufs[0].written == fd->wr_bufs[0].size) {
/*dbg_printf("(mainloop) finish write %d\n", 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];
}
fd->wr_bufs[MAINLOOP_MAX_WR_BUFS-1].buf = 0;
}
}
i++;
}
after_idle_step = false;
}
}
}
void mainloop_exit() {
mainloop_must_exit = true;
}
/* vim: set ts=4 sw=4 tw=0 noet :*/
|