1 // Copyright 2021 Espressif Systems (Shanghai) CO LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License
14
15
16 #include "esp_vfs_eventfd.h"
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/lock.h>
24 #include <sys/select.h>
25 #include <sys/types.h>
26
27 #include "esp_err.h"
28 #include "esp_log.h"
29 #include "esp_vfs.h"
30 #include "freertos/FreeRTOS.h"
31 #include "freertos/portmacro.h"
32 #include "soc/spinlock.h"
33
34 #define FD_INVALID -1
35 #define FD_PENDING_SELECT -2
36
37 /*
38 * About the event_select_args_t linked list
39 *
40 * Each event_select_args_t structure records a pending select from a select call
41 * on a file descriptor.
42 *
43 * For each select() call, we form a linked list in end_select_args containing
44 * all the pending selects in this select call.
45 *
46 * For each file descriptor, we form a double linked list in event_context_t::select_args.
47 * This list contains all the pending selects on this file descriptor from
48 * different select() calls.
49 *
50 */
51 typedef struct event_select_args_t {
52 int fd;
53 fd_set *read_fds;
54 fd_set *error_fds;
55 esp_vfs_select_sem_t signal_sem;
56 // linked list node in event_context_t::select_args
57 struct event_select_args_t *prev_in_fd;
58 struct event_select_args_t *next_in_fd;
59 // linked list node in end_select_arg
60 struct event_select_args_t *next_in_args;
61 } event_select_args_t;
62
63 typedef struct {
64 int fd;
65 bool support_isr;
66 volatile bool is_set;
67 volatile uint64_t value;
68 // a double-linked list for all pending select args with this fd
69 event_select_args_t *select_args;
70 _lock_t lock;
71 // only for event fds that support ISR.
72 spinlock_t data_spin_lock;
73 } event_context_t;
74
75 esp_vfs_id_t s_eventfd_vfs_id = -1;
76
77 static size_t s_event_size;
78 static event_context_t *s_events;
79
trigger_select_for_event(event_context_t * event)80 static void trigger_select_for_event(event_context_t *event)
81 {
82 event_select_args_t *select_args = event->select_args;
83 while (select_args != NULL) {
84 esp_vfs_select_triggered(select_args->signal_sem);
85 select_args = select_args->next_in_fd;
86 }
87 }
88
trigger_select_for_event_isr(event_context_t * event,BaseType_t * task_woken)89 static void trigger_select_for_event_isr(event_context_t *event, BaseType_t *task_woken)
90 {
91 event_select_args_t *select_args = event->select_args;
92 while (select_args != NULL) {
93 BaseType_t local_woken;
94 esp_vfs_select_triggered_isr(select_args->signal_sem, &local_woken);
95 *task_woken = (local_woken || *task_woken);
96 select_args = select_args->next_in_fd;
97 }
98 }
99
100 #ifdef CONFIG_VFS_SUPPORT_SELECT
event_start_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,esp_vfs_select_sem_t signal_sem,void ** end_select_args)101 static esp_err_t event_start_select(int nfds,
102 fd_set *readfds,
103 fd_set *writefds,
104 fd_set *exceptfds,
105 esp_vfs_select_sem_t signal_sem,
106 void **end_select_args)
107 {
108 esp_err_t error = ESP_OK;
109 bool should_trigger = false;
110 nfds = nfds < s_event_size ? nfds : (int)s_event_size;
111 event_select_args_t *select_args_list = NULL;
112
113 // FIXME: end_select_args should be a list to all select args
114
115 for (int i = 0; i < nfds; i++) {
116 _lock_acquire_recursive(&s_events[i].lock);
117 if (s_events[i].fd == i) {
118 if (s_events[i].support_isr) {
119 portENTER_CRITICAL(&s_events[i].data_spin_lock);
120 }
121
122 event_select_args_t *event_select_args =
123 (event_select_args_t *)malloc(sizeof(event_select_args_t));
124 event_select_args->fd = i;
125 event_select_args->signal_sem = signal_sem;
126
127 if (FD_ISSET(i, exceptfds)) {
128 FD_CLR(i, exceptfds);
129 event_select_args->error_fds = exceptfds;
130 } else {
131 event_select_args->error_fds = NULL;
132 }
133 FD_CLR(i, exceptfds);
134 // event fds are always writable
135 if (FD_ISSET(i, writefds)) {
136 should_trigger = true;
137 }
138 if (FD_ISSET(i, readfds)) {
139 event_select_args->read_fds = readfds;
140 if (s_events[i].is_set) {
141 should_trigger = true;
142 } else {
143 FD_CLR(i, readfds);
144 }
145 } else {
146 event_select_args->read_fds = NULL;
147 }
148 event_select_args->prev_in_fd = NULL;
149 event_select_args->next_in_fd = s_events[i].select_args;
150 if (s_events[i].select_args) {
151 s_events[i].select_args->prev_in_fd = event_select_args;
152 }
153 event_select_args->next_in_args = select_args_list;
154 select_args_list = event_select_args;
155 s_events[i].select_args = event_select_args;
156
157 if (s_events[i].support_isr) {
158 portEXIT_CRITICAL(&s_events[i].data_spin_lock);
159 }
160 }
161 _lock_release_recursive(&s_events[i].lock);
162 }
163
164 *end_select_args = select_args_list;
165
166 if (should_trigger) {
167 esp_vfs_select_triggered(signal_sem);
168 }
169
170 return error;
171 }
172
event_end_select(void * end_select_args)173 static esp_err_t event_end_select(void *end_select_args)
174 {
175 event_select_args_t *select_args = (event_select_args_t *)end_select_args;
176
177 while (select_args != NULL) {
178 event_context_t *event = &s_events[select_args->fd];
179
180 _lock_acquire_recursive(&event->lock);
181 if (event->support_isr) {
182 portENTER_CRITICAL(&event->data_spin_lock);
183 }
184
185 if (event->fd != select_args->fd) { // already closed
186 if (select_args->error_fds) {
187 FD_SET(select_args->fd, select_args->error_fds);
188 }
189 } else {
190 if (select_args->read_fds && event->is_set) {
191 FD_SET(select_args->fd, select_args->read_fds);
192 }
193 }
194
195 event_select_args_t *prev_in_fd = select_args->prev_in_fd;
196 event_select_args_t *next_in_fd = select_args->next_in_fd;
197 event_select_args_t *next_in_args = select_args->next_in_args;
198 if (prev_in_fd != NULL) {
199 prev_in_fd->next_in_fd = next_in_fd;
200 } else {
201 event->select_args = next_in_fd;
202 }
203 if (next_in_fd != NULL) {
204 next_in_fd->prev_in_fd = prev_in_fd;
205 }
206 if (prev_in_fd == NULL && next_in_fd == NULL) { // The last pending select
207 if (event->fd == FD_PENDING_SELECT) {
208 event->fd = FD_INVALID;
209 }
210 }
211
212 if (event->support_isr) {
213 portEXIT_CRITICAL(&event->data_spin_lock);
214 }
215 _lock_release_recursive(&event->lock);
216
217 free(select_args);
218 select_args = next_in_args;
219 }
220
221 return ESP_OK;
222 }
223 #endif // CONFIG_VFS_SUPPORT_SELECT
224
signal_event_fd_from_isr(int fd,const void * data,size_t size)225 static ssize_t signal_event_fd_from_isr(int fd, const void *data, size_t size)
226 {
227 BaseType_t task_woken = pdFALSE;
228 const uint64_t *val = (const uint64_t *)data;
229 ssize_t ret = size;
230
231 portENTER_CRITICAL_ISR(&s_events[fd].data_spin_lock);
232
233 if (s_events[fd].fd == fd) {
234 s_events[fd].is_set = true;
235 s_events[fd].value += *val;
236 trigger_select_for_event_isr(&s_events[fd], &task_woken);
237 } else {
238 errno = EBADF;
239 ret = -1;
240 }
241
242 portEXIT_CRITICAL_ISR(&s_events[fd].data_spin_lock);
243
244 if (task_woken) {
245 portYIELD_FROM_ISR();
246 }
247 return ret;
248 }
249
event_write(int fd,const void * data,size_t size)250 static ssize_t event_write(int fd, const void *data, size_t size)
251 {
252 ssize_t ret = -1;
253
254 if (fd >= s_event_size || data == NULL || size != sizeof(uint64_t)) {
255 errno = EINVAL;
256 return ret;
257 }
258 if (size != sizeof(uint64_t)) {
259 errno = EINVAL;
260 return ret;
261 }
262
263 if (!xPortCanYield()) {
264 ret = signal_event_fd_from_isr(fd, data, size);
265 } else {
266 const uint64_t *val = (const uint64_t *)data;
267
268 _lock_acquire_recursive(&s_events[fd].lock);
269 if (s_events[fd].support_isr) {
270 portENTER_CRITICAL(&s_events[fd].data_spin_lock);
271 }
272
273 if (s_events[fd].fd == fd) {
274 s_events[fd].is_set = true;
275 s_events[fd].value += *val;
276 ret = size;
277 trigger_select_for_event(&s_events[fd]);
278
279 if (s_events[fd].support_isr) {
280 portEXIT_CRITICAL(&s_events[fd].data_spin_lock);
281 }
282 } else {
283 errno = EBADF;
284 ret = -1;
285 }
286 _lock_release_recursive(&s_events[fd].lock);
287 }
288 return ret;
289 }
290
event_read(int fd,void * data,size_t size)291 static ssize_t event_read(int fd, void *data, size_t size)
292 {
293 ssize_t ret = -1;
294
295 if (fd >= s_event_size || data == NULL || size != sizeof(uint64_t)) {
296 errno = EINVAL;
297 return ret;
298 }
299
300 uint64_t *val = (uint64_t *)data;
301
302 _lock_acquire_recursive(&s_events[fd].lock);
303 if (s_events[fd].support_isr) {
304 portENTER_CRITICAL(&s_events[fd].data_spin_lock);
305 }
306
307 if (s_events[fd].fd == fd) {
308 *val = s_events[fd].value;
309 s_events[fd].is_set = false;
310 ret = size;
311 s_events[fd].value = 0;
312 } else {
313 errno = EBADF;
314 ret = -1;
315 }
316
317 if (s_events[fd].support_isr) {
318 portEXIT_CRITICAL(&s_events[fd].data_spin_lock);
319 }
320 _lock_release_recursive(&s_events[fd].lock);
321
322 return ret;
323 }
324
event_close(int fd)325 static int event_close(int fd)
326 {
327 int ret = -1;
328
329 if (fd >= s_event_size) {
330 errno = EINVAL;
331 return ret;
332 }
333
334 _lock_acquire_recursive(&s_events[fd].lock);
335 if (s_events[fd].fd == fd) {
336 if (s_events[fd].support_isr) {
337 portENTER_CRITICAL(&s_events[fd].data_spin_lock);
338 }
339 if (s_events[fd].select_args == NULL) {
340 s_events[fd].fd = FD_INVALID;
341 } else {
342 s_events[fd].fd = FD_PENDING_SELECT;
343 trigger_select_for_event(&s_events[fd]);
344 }
345 s_events[fd].value = 0;
346 if (s_events[fd].support_isr) {
347 portEXIT_CRITICAL(&s_events[fd].data_spin_lock);
348 }
349 ret = 0;
350 } else {
351 errno = EBADF;
352 }
353 _lock_release_recursive(&s_events[fd].lock);
354
355 return ret;
356 }
357
esp_vfs_eventfd_register(const esp_vfs_eventfd_config_t * config)358 esp_err_t esp_vfs_eventfd_register(const esp_vfs_eventfd_config_t *config)
359 {
360 if (config == NULL || config->max_fds >= MAX_FDS) {
361 return ESP_ERR_INVALID_ARG;
362 }
363 if (s_eventfd_vfs_id != -1) {
364 return ESP_ERR_INVALID_STATE;
365 }
366
367 s_event_size = config->max_fds;
368 s_events = (event_context_t *)calloc(s_event_size, sizeof(event_context_t));
369 for (size_t i = 0; i < s_event_size; i++) {
370 _lock_init_recursive(&s_events[i].lock);
371 s_events[i].fd = FD_INVALID;
372 }
373
374 esp_vfs_t vfs = {
375 .flags = ESP_VFS_FLAG_DEFAULT,
376 .write = &event_write,
377 .close = &event_close,
378 .read = &event_read,
379 #ifdef CONFIG_VFS_SUPPORT_SELECT
380 .start_select = &event_start_select,
381 .end_select = &event_end_select,
382 #endif
383 };
384 return esp_vfs_register_with_id(&vfs, NULL, &s_eventfd_vfs_id);
385 }
386
esp_vfs_eventfd_unregister(void)387 esp_err_t esp_vfs_eventfd_unregister(void)
388 {
389 if (s_eventfd_vfs_id == -1) {
390 return ESP_ERR_INVALID_STATE;
391 }
392 esp_err_t error = esp_vfs_unregister_with_id(s_eventfd_vfs_id);
393 if (error == ESP_OK) {
394 s_eventfd_vfs_id = -1;
395 }
396 for (size_t i = 0; i < s_event_size; i++) {
397 _lock_close_recursive(&s_events[i].lock);
398 }
399 free(s_events);
400 return error;
401 }
402
eventfd(unsigned int initval,int flags)403 int eventfd(unsigned int initval, int flags)
404 {
405 int fd = FD_INVALID;
406 int global_fd = FD_INVALID;
407 esp_err_t error = ESP_OK;
408
409 if ((flags & (~EFD_SUPPORT_ISR)) != 0) {
410 errno = EINVAL;
411 return FD_INVALID;
412 }
413 if (s_eventfd_vfs_id == -1) {
414 errno = EACCES;
415 return FD_INVALID;
416 }
417
418 for (size_t i = 0; i < s_event_size; i++) {
419 _lock_acquire_recursive(&s_events[i].lock);
420 if (s_events[i].fd == FD_INVALID) {
421
422 error = esp_vfs_register_fd_with_local_fd(s_eventfd_vfs_id, i, /*permanent=*/false, &global_fd);
423 if (error != ESP_OK) {
424 _lock_release_recursive(&s_events[i].lock);
425 break;
426 }
427
428 bool support_isr = flags & EFD_SUPPORT_ISR;
429 fd = i;
430 s_events[i].fd = i;
431 s_events[i].support_isr = support_isr;
432 spinlock_initialize(&s_events[i].data_spin_lock);
433
434 if (support_isr) {
435 portENTER_CRITICAL(&s_events[i].data_spin_lock);
436 }
437 s_events[i].is_set = false;
438 s_events[i].value = initval;
439 s_events[i].select_args = NULL;
440 if (support_isr) {
441 portEXIT_CRITICAL(&s_events[i].data_spin_lock);
442 }
443 _lock_release_recursive(&s_events[i].lock);
444 break;
445 }
446 _lock_release_recursive(&s_events[i].lock);
447 }
448
449 switch (error) {
450 case ESP_OK:
451 fd = global_fd;
452 break;
453 case ESP_ERR_NO_MEM:
454 errno = ENOMEM;
455 break;
456 case ESP_ERR_INVALID_ARG:
457 errno = EINVAL;
458 break;
459 default:
460 errno = EIO;
461 break;
462 }
463
464 return fd;
465 }
466