summaryrefslogtreecommitdiff
path: root/src/common/loop.c
blob: 4c2da0d5d8f6892d1c7c9f6e33634ad7a31b9d1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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;
}