diff options
Diffstat (limited to 'src/common/loop.c')
| -rw-r--r-- | src/common/loop.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/common/loop.c b/src/common/loop.c new file mode 100644 index 0000000..4c2da0d --- /dev/null +++ b/src/common/loop.c @@ -0,0 +1,124 @@ +#define _POSIX_C_SOURCE 200809L +#include "yasl/yasl.h" + +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#define YASL_MAX_FDS 64 + +typedef int (*yasl_loop_fd_fn)(int fd, short revents, void *ud); + +struct yasl_fd_source { + yasl_loop_fd_fn fn; + void *ud; + int id; + int fd; + short events; +}; + +struct yasl_loop { + struct yasl_fd_source fds[YASL_MAX_FDS]; + struct pollfd pollfds[YASL_MAX_FDS]; + int count; + int next_id; + bool running; +}; + +uint64_t yasl_loop_now_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; +} + +struct yasl_loop *yasl_loop_create(void) +{ + struct yasl_loop *l = calloc(1, sizeof(*l)); + if (!l) return NULL; + l->next_id = 1; + return l; +} + +void yasl_loop_destroy(struct yasl_loop *l) +{ + free(l); +} + +int yasl_loop_add_fd(struct yasl_loop *l, int fd, short events, + int (*fn)(int fd, short revents, void *ud), void *ud) +{ + if (!l || l->count >= YASL_MAX_FDS || fd < 0) + return -1; + int id = l->next_id++; + l->fds[l->count] = (struct yasl_fd_source){ + .fn = fn, .ud = ud, .id = id, .fd = fd, .events = events, + }; + l->pollfds[l->count] = (struct pollfd){ + .fd = fd, .events = events, .revents = 0, + }; + l->count++; + return id; +} + +int yasl_loop_del_fd(struct yasl_loop *l, int id) +{ + if (!l || id <= 0) return -1; + for (int i = 0; i < l->count; i++) { + if (l->fds[i].id == id) { + l->count--; + l->fds[i] = l->fds[l->count]; + l->pollfds[i] = l->pollfds[l->count]; + return 0; + } + } + return -1; +} + +int yasl_loop_set_fd_events(struct yasl_loop *l, int id, short events) +{ + if (!l || id <= 0) return -1; + for (int i = 0; i < l->count; i++) { + if (l->fds[i].id == id) { + l->fds[i].events = events; + l->pollfds[i].events = events; + return 0; + } + } + return -1; +} + +void yasl_loop_kick(struct yasl_loop *l) +{ + (void)l; +} + +int yasl_loop_run(struct yasl_loop *l) +{ + if (!l) return -1; + l->running = true; + while (l->running) { + int n = poll(l->pollfds, (nfds_t)l->count, -1); + if (n < 0) { + if (errno == EINTR) continue; + return -1; + } + for (int i = 0; i < l->count && l->running; i++) { + if (l->pollfds[i].revents) { + struct yasl_fd_source src = l->fds[i]; + short revents = l->pollfds[i].revents; + l->pollfds[i].revents = 0; + if (src.fn) + src.fn(src.fd, revents, src.ud); + } + } + } + return 0; +} + +void yasl_loop_quit(struct yasl_loop *l) +{ + if (l) l->running = false; +} |
