diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/loop.c | 168 | ||||
| -rw-r--r-- | src/common/timing.c | 9 | ||||
| -rw-r--r-- | src/common/utf8.c | 28 |
3 files changed, 176 insertions, 29 deletions
diff --git a/src/common/loop.c b/src/common/loop.c index 4c2da0d..de29c85 100644 --- a/src/common/loop.c +++ b/src/common/loop.c @@ -1,13 +1,16 @@ +#define _GNU_SOURCE #define _POSIX_C_SOURCE 200809L #include "yasl/yasl.h" #include <errno.h> +#include <fcntl.h> #include <poll.h> #include <stdlib.h> +#include <string.h> #include <time.h> #include <unistd.h> -#define YASL_MAX_FDS 64 +#define YASL_LOOP_INIT_CAP 32 typedef int (*yasl_loop_fd_fn)(int fd, short revents, void *ud); @@ -20,11 +23,15 @@ struct yasl_fd_source { }; struct yasl_loop { - struct yasl_fd_source fds[YASL_MAX_FDS]; - struct pollfd pollfds[YASL_MAX_FDS]; + struct yasl_fd_source *fds; + struct pollfd *pollfds; int count; + int capacity; int next_id; bool running; + int wake_rfd; + int wake_wfd; + int wake_watch; }; uint64_t yasl_loop_now_ns(void) @@ -34,25 +41,95 @@ uint64_t yasl_loop_now_ns(void) return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; } +static int loop_wake_cb(int fd, short revents, void *ud) +{ + (void)revents; + (void)ud; + char buf[128]; + ssize_t n; + while ((n = read(fd, buf, sizeof(buf))) > 0 || (n < 0 && errno == EINTR)) {} + return 0; +} + struct yasl_loop *yasl_loop_create(void) { struct yasl_loop *l = calloc(1, sizeof(*l)); if (!l) return NULL; + + l->capacity = YASL_LOOP_INIT_CAP; + l->fds = malloc((size_t)l->capacity * sizeof(*l->fds)); + l->pollfds = malloc((size_t)l->capacity * sizeof(*l->pollfds)); + if (!l->fds || !l->pollfds) { + free(l->fds); + free(l->pollfds); + free(l); + return NULL; + } + l->next_id = 1; + l->wake_rfd = -1; + l->wake_wfd = -1; + + int p[2]; +#if defined(__linux__) && defined(O_CLOEXEC) + if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == 0) { + l->wake_rfd = p[0]; + l->wake_wfd = p[1]; + } +#else + if (pipe(p) == 0) { + int f0 = fcntl(p[0], F_GETFL, 0); + int f1 = fcntl(p[1], F_GETFL, 0); + if (f0 >= 0) fcntl(p[0], F_SETFL, f0 | O_NONBLOCK); + if (f1 >= 0) fcntl(p[1], F_SETFL, f1 | O_NONBLOCK); + fcntl(p[0], F_SETFD, FD_CLOEXEC); + fcntl(p[1], F_SETFD, FD_CLOEXEC); + l->wake_rfd = p[0]; + l->wake_wfd = p[1]; + } +#endif + + if (l->wake_rfd >= 0) { + l->wake_watch = yasl_loop_add_fd(l, l->wake_rfd, POLLIN, loop_wake_cb, l); + } return l; } void yasl_loop_destroy(struct yasl_loop *l) { + if (!l) return; + if (l->wake_watch > 0) + yasl_loop_del_fd(l, l->wake_watch); + if (l->wake_rfd >= 0) + close(l->wake_rfd); + if (l->wake_wfd >= 0) + close(l->wake_wfd); + free(l->fds); + free(l->pollfds); 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) + if (!l || fd < 0) return -1; + + if (l->count >= l->capacity) { + int new_cap = l->capacity ? l->capacity * 2 : YASL_LOOP_INIT_CAP; + struct yasl_fd_source *new_fds = realloc(l->fds, (size_t)new_cap * sizeof(*new_fds)); + if (!new_fds) return -1; + l->fds = new_fds; + + struct pollfd *new_pollfds = realloc(l->pollfds, (size_t)new_cap * sizeof(*new_pollfds)); + if (!new_pollfds) return -1; + l->pollfds = new_pollfds; + l->capacity = new_cap; + } + int id = l->next_id++; + if (l->next_id <= 0) l->next_id = 1; + l->fds[l->count] = (struct yasl_fd_source){ .fn = fn, .ud = ud, .id = id, .fd = fd, .events = events, }; @@ -92,7 +169,74 @@ int yasl_loop_set_fd_events(struct yasl_loop *l, int id, short events) void yasl_loop_kick(struct yasl_loop *l) { - (void)l; + if (!l || l->wake_wfd < 0) return; + char b = 1; + ssize_t n; + do { + n = write(l->wake_wfd, &b, 1); + } while (n < 0 && errno == EINTR); +} + +int yasl_loop_step(struct yasl_loop *l, int timeout_ms) +{ + if (!l) return -1; + if (l->count <= 0) { + if (timeout_ms > 0) { + struct timespec req = { + .tv_sec = timeout_ms / 1000, + .tv_nsec = (long)(timeout_ms % 1000) * 1000000L, + }; + nanosleep(&req, NULL); + } + return 0; + } + + int n; + do { + n = poll(l->pollfds, (nfds_t)l->count, timeout_ms); + } while (n < 0 && errno == EINTR); + + if (n < 0) return -1; + if (n == 0) return 0; + + int handled = 0; + int count = l->count; + + struct yasl_fd_source sstack[32]; + struct pollfd pstack[32]; + struct yasl_fd_source *scopy = (count <= 32) ? sstack : malloc((size_t)count * sizeof(*scopy)); + struct pollfd *pcopy = (count <= 32) ? pstack : malloc((size_t)count * sizeof(*pcopy)); + if (!scopy || !pcopy) { + if (scopy && scopy != sstack) free(scopy); + if (pcopy && pcopy != pstack) free(pcopy); + return -1; + } + + memcpy(scopy, l->fds, (size_t)count * sizeof(*scopy)); + memcpy(pcopy, l->pollfds, (size_t)count * sizeof(*pcopy)); + + for (int i = 0; i < count; i++) { + if (pcopy[i].revents) { + short revents = pcopy[i].revents; + // Verify that the source was not deleted by an earlier callback in this step + bool valid = false; + for (int j = 0; j < l->count; j++) { + if (l->fds[j].id == scopy[i].id) { + l->pollfds[j].revents = 0; + valid = true; + break; + } + } + if (valid && scopy[i].fn) { + scopy[i].fn(scopy[i].fd, revents, scopy[i].ud); + handled++; + } + } + } + + if (scopy != sstack) free(scopy); + if (pcopy != pstack) free(pcopy); + return handled; } int yasl_loop_run(struct yasl_loop *l) @@ -100,20 +244,8 @@ 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; + if (yasl_loop_step(l, -1) < 0) 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; } diff --git a/src/common/timing.c b/src/common/timing.c index b5e342f..3e3a705 100644 --- a/src/common/timing.c +++ b/src/common/timing.c @@ -5,8 +5,8 @@ uint64_t yasl_clock_extend_ms(uint32_t ms, uint64_t now_ns) uint64_t now_ms = now_ns / 1000000; int64_t ahead = (int32_t)(ms - (uint32_t)now_ms); if (ahead < 0 && (uint64_t)-ahead > now_ms) - return (uint64_t)ms * 1000000; - return (now_ms + (uint64_t)ahead) * 1000000; + return (uint64_t)ms * 1000000ull; + return (uint64_t)((int64_t)now_ms + ahead) * 1000000ull; } void yasl_clock_presented(struct yasl_frame_clock *c, uint64_t now, bool sample) @@ -45,9 +45,8 @@ double yasl_clock_refresh_ms(const struct yasl_frame_clock *c) uint64_t yasl_clock_next_present_ns(const struct yasl_frame_clock *c) { - return c->last_present_ns - ? c->last_present_ns + (uint64_t)c->refresh_ns - : 0; + uint64_t next = c->last_present_ns + (uint64_t)c->refresh_ns; + return (uint64_t)-(c->last_present_ns != 0) & next; } uint64_t yasl_clock_frame_timestamp_ns(struct yasl_frame_clock *c, uint64_t now) diff --git a/src/common/utf8.c b/src/common/utf8.c index 089fd89..7f2e6f1 100644 --- a/src/common/utf8.c +++ b/src/common/utf8.c @@ -3,30 +3,46 @@ #include <stdbool.h> #include <stdint.h> +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + bool yasl_utf8_validate(const char *str, size_t len) { const unsigned char *p = (const unsigned char *)str; const unsigned char *end = p + len; while (p < end) { - if (*p < 0x80) { + while (p + 8 <= end) { + uint64_t v; + memcpy(&v, p, 8); + if (v & 0x8080808080808080ull) + break; + p += 8; + } + if (p >= end) break; + + if (likely(*p < 0x80)) { p++; } else if ((*p & 0xe0) == 0xc0) { - if (p + 1 >= end || (p[1] & 0xc0) != 0x80 || (*p & 0x1e) == 0) + if (unlikely(p + 1 >= end || (p[1] & 0xc0) != 0x80 || (*p & 0x1e) == 0)) return false; p += 2; } else if ((*p & 0xf0) == 0xe0) { - if (p + 2 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80) + if (unlikely(p + 2 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)) return false; uint32_t cp = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f); - if (cp < 0x800 || (cp >= 0xd800 && cp <= 0xdfff)) + if (unlikely(cp < 0x800 || (cp >= 0xd800 && cp <= 0xdfff))) return false; p += 3; } else if ((*p & 0xf8) == 0xf0) { - if (p + 3 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80) + if (unlikely(p + 3 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)) return false; uint32_t cp = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f); - if (cp < 0x10000 || cp > 0x10ffff) + if (unlikely(cp < 0x10000 || cp > 0x10ffff)) return false; p += 4; } else { |
