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