GCC Code Coverage Report


Directory: src/
File: src/event_loop.c
Date: 2024-04-25 03:45:42
Exec Total Coverage
Lines: 111 131 84.7%
Branches: 39 76 51.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2023 Egor Tensin <egor@tensin.name>
3 * This file is part of the "cimple" project.
4 * For details, see https://github.com/egor-tensin/cimple.
5 * Distributed under the MIT License.
6 */
7
8 #include "event_loop.h"
9 #include "log.h"
10 #include "string.h"
11
12 #include <poll.h>
13 #include <stddef.h>
14 #include <stdlib.h>
15 #include <sys/queue.h>
16
17 SIMPLEQ_HEAD(event_fd_queue, event_fd);
18
19 struct event_fd {
20 int fd;
21 short events;
22 event_handler handler;
23 void *arg;
24 int once;
25
26 SIMPLEQ_ENTRY(event_fd) entries;
27 };
28
29 36966 static struct event_fd *event_fd_create(int fd, short events, event_handler handler, void *arg)
30 {
31 36966 struct event_fd *res = calloc(1, sizeof(struct event_fd));
32
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36966 times.
36966 if (!res) {
33 log_errno("calloc");
34 return NULL;
35 }
36
37 36966 res->fd = fd;
38 36966 res->events = events;
39 36966 res->handler = handler;
40 36966 res->arg = arg;
41 36966 res->once = 0;
42
43 36966 return res;
44 }
45
46 36966 static void event_fd_destroy(struct event_fd *entry)
47 {
48 36966 free(entry);
49 36966 }
50
51 83 static void event_fd_queue_create(struct event_fd_queue *queue)
52 {
53 83 SIMPLEQ_INIT(queue);
54 83 }
55
56 83 static void event_fd_queue_destroy(struct event_fd_queue *queue)
57 {
58 83 struct event_fd *entry1 = SIMPLEQ_FIRST(queue);
59
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 83 times.
249 while (entry1) {
60 166 struct event_fd *entry2 = SIMPLEQ_NEXT(entry1, entries);
61 166 event_fd_destroy(entry1);
62 166 entry1 = entry2;
63 }
64 83 SIMPLEQ_INIT(queue);
65 83 }
66
67 struct event_loop {
68 nfds_t nfds;
69 struct event_fd_queue entries;
70 };
71
72 83 int event_loop_create(struct event_loop **_loop)
73 {
74 83 int ret = 0;
75
76 83 struct event_loop *loop = calloc(1, sizeof(struct event_loop));
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (!loop) {
78 log_errno("calloc");
79 return -1;
80 }
81 83 *_loop = loop;
82
83 83 event_fd_queue_create(&loop->entries);
84
85 83 return ret;
86 }
87
88 83 void event_loop_destroy(struct event_loop *loop)
89 {
90 83 event_fd_queue_destroy(&loop->entries);
91 83 free(loop);
92 83 }
93
94 36966 static void event_loop_add_internal(struct event_loop *loop, struct event_fd *entry)
95 {
96
1/2
✓ Branch 1 taken 36966 times.
✗ Branch 2 not taken.
36966 log_debug("Adding descriptor %d to event loop\n", entry->fd);
97
98 36966 nfds_t nfds = loop->nfds + 1;
99 36966 SIMPLEQ_INSERT_TAIL(&loop->entries, entry, entries);
100 36966 loop->nfds = nfds;
101 36966 }
102
103 112 int event_loop_add(struct event_loop *loop, int fd, short events, event_handler handler, void *arg)
104 {
105 112 struct event_fd *entry = event_fd_create(fd, events, handler, arg);
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!entry)
107 return -1;
108 112 event_loop_add_internal(loop, entry);
109 112 return 0;
110 }
111
112 36854 int event_loop_add_once(struct event_loop *loop, int fd, short events, event_handler handler,
113 void *arg)
114 {
115 36854 struct event_fd *entry = event_fd_create(fd, events, handler, arg);
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36854 times.
36854 if (!entry)
117 return -1;
118 36854 entry->once = 1;
119 36854 event_loop_add_internal(loop, entry);
120 36854 return 0;
121 }
122
123 36800 static void event_loop_remove(struct event_loop *loop, struct event_fd *entry)
124 {
125
1/2
✓ Branch 1 taken 36800 times.
✗ Branch 2 not taken.
36800 log_debug("Removing descriptor %d from event loop\n", entry->fd);
126
127
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 36800 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 48335 times.
✓ Branch 5 taken 36800 times.
✓ Branch 6 taken 25199 times.
✓ Branch 7 taken 11601 times.
85135 SIMPLEQ_REMOVE(&loop->entries, entry, event_fd, entries);
128 36800 event_fd_destroy(entry);
129 36800 --loop->nfds;
130 36800 }
131
132 305444 static char *append_event(char *buf, size_t sz, char *ptr, const char *event)
133 {
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (ptr > buf)
135 ptr = string_append(ptr, buf + sz, ",");
136 305444 return string_append(ptr, buf + sz, event);
137 }
138
139 305444 static char *events_to_string(short events)
140 {
141 305444 const size_t sz = 128;
142 305444 char *buf = calloc(1, sz);
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (!buf)
144 return NULL;
145
146 305444 char *ptr = buf;
147
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLNVAL)
149 ptr = append_event(buf, sz, ptr, "POLLNVAL");
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLERR)
151 ptr = append_event(buf, sz, ptr, "POLLERR");
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLHUP)
153 ptr = append_event(buf, sz, ptr, "POLLHUP");
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLRDHUP)
155 ptr = append_event(buf, sz, ptr, "POLLRDHUP");
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLPRI)
157 ptr = append_event(buf, sz, ptr, "POLLPRI");
158
1/2
✓ Branch 0 taken 305444 times.
✗ Branch 1 not taken.
305444 if (events & POLLIN)
159 305444 ptr = append_event(buf, sz, ptr, "POLLIN");
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305444 times.
305444 if (events & POLLOUT)
161 ptr = append_event(buf, sz, ptr, "POLLOUT");
162
163 305444 return buf;
164 }
165
166 63268 static struct pollfd *make_pollfds(const struct event_loop *loop)
167 {
168 63268 struct pollfd *fds = calloc(loop->nfds, sizeof(struct pollfd));
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63268 times.
63268 if (!fds) {
170 log_errno("calloc");
171 return NULL;
172 }
173
174 63268 struct event_fd *entry = SIMPLEQ_FIRST(&loop->entries);
175
2/2
✓ Branch 0 taken 240941 times.
✓ Branch 1 taken 63268 times.
304209 for (nfds_t i = 0; i < loop->nfds; ++i, entry = SIMPLEQ_NEXT(entry, entries)) {
176 240941 fds[i].fd = entry->fd;
177 240941 fds[i].events = entry->events;
178 }
179
180
1/2
✓ Branch 1 taken 63268 times.
✗ Branch 2 not taken.
63268 log_debug("Descriptors:\n");
181
2/2
✓ Branch 0 taken 240941 times.
✓ Branch 1 taken 63268 times.
304209 for (nfds_t i = 0; i < loop->nfds; ++i) {
182 240941 char *events = events_to_string(fds[i].events);
183
1/4
✓ Branch 1 taken 240941 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
240941 log_debug(" %d (%s)\n", fds[i].fd, events ? events : "");
184 240941 free(events);
185 }
186
187 63268 return fds;
188 }
189
190 63268 int event_loop_run(struct event_loop *loop)
191 {
192 /* Cache the number of event descriptors so that event handlers can
193 * append new ones. */
194 63268 const nfds_t nfds = loop->nfds;
195
196 63268 struct pollfd *fds = make_pollfds(loop);
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63268 times.
63268 if (!fds)
198 return -1;
199
200 63268 int ret = poll(fds, nfds, -1);
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63268 times.
63268 if (ret < 0) {
202 log_errno("poll");
203 return ret;
204 }
205 63268 ret = 0;
206
207 63268 struct event_fd *entry = SIMPLEQ_FIRST(&loop->entries);
208
2/2
✓ Branch 0 taken 240941 times.
✓ Branch 1 taken 63268 times.
304209 for (nfds_t i = 0; i < nfds; ++i) {
209 240941 struct event_fd *next = SIMPLEQ_NEXT(entry, entries);
210
211
2/2
✓ Branch 0 taken 176438 times.
✓ Branch 1 taken 64503 times.
240941 if (!fds[i].revents)
212 176438 goto next;
213
214 64503 char *events = events_to_string(fds[i].revents);
215
1/4
✓ Branch 1 taken 64503 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
64503 log_debug("Descriptor %d is ready: %s\n", fds[i].fd, events ? events : "");
216 64503 free(events);
217
218 /* Execute all handlers but notice if any of them fail. */
219 64503 const int handler_ret = entry->handler(loop, fds[i].fd, fds[i].revents, entry->arg);
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64503 times.
64503 if (handler_ret < 0)
221 ret = handler_ret;
222
223
2/2
✓ Branch 0 taken 27703 times.
✓ Branch 1 taken 36800 times.
64503 if (entry->once)
224 36800 event_loop_remove(loop, entry);
225
226 27703 next:
227 240941 entry = next;
228 240941 continue;
229 }
230
231 63268 free(fds);
232 63268 return ret;
233 }
234