diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index efeb0a91a1..acd48844cd 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -410,7 +410,7 @@ UT_001: UT_002: extends: .unit_test_esp32_template - parallel: 13 + parallel: 15 tags: - ESP32_IDF - UT_T1_1 diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 1608892d01..a8fe25e352 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -151,7 +151,7 @@ static spp_slot_t *spp_malloc_slot(void) break; } if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) { - if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, -1, /*permanent=*/true, &(*slot)->fd) != ESP_OK) { + if (esp_vfs_register_fd(spp_local_param.spp_vfs_id, &(*slot)->fd) != ESP_OK) { BTC_TRACE_ERROR("%s unable to register fd!", __func__); err_no = 3; break; diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 9c80bffdf9..4765f14433 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -242,7 +242,7 @@ Event fds ``eventfd()`` call is a powerful tool to notify a ``select()`` based loop of custom events. The ``eventfd()`` implementation in ESP-IDF is generally the same as described in ``man(2) eventfd`` except for: - ``esp_vfs_eventfd_register()`` has to be called before calling ``eventfd()`` -- Option ``EFD_CLOEXEC``, ``EFD_NONBLOCK`` and ``EFD_SEMAPHORE`` is not supported in flags. +- Options ``EFD_CLOEXEC``, ``EFD_NONBLOCK`` and ``EFD_SEMAPHORE`` are not supported in flags. - Option ``EFD_SUPPORT_ISR`` has been added in flags. This flag is required to read and the write the eventfd in an interrupt handler. Note that creating an eventfd with ``EFD_SUPPORT_ISR`` will cause interrupts to be temporarily disabled when reading, writing the file and during the beginning and the ending of the ``select()`` when this file is set. diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 30689d6d89..7ba6364530 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -339,15 +339,28 @@ esp_err_t esp_vfs_unregister_with_id(esp_vfs_id_t vfs_id); * by esp_vfs_register_with_id. * * @param vfs_id VFS identificator returned by esp_vfs_register_with_id. - * @param local_fd The fd in the local vfs. Passing -1 will set the local fd as the (*fd) value. - * @param permanenent Whether the fd should be treated as permannet (not removed after close()) * @param fd The registered file descriptor will be written to this address. * * @return ESP_OK if the registration is successful, * ESP_ERR_NO_MEM if too many file descriptors are registered, * ESP_ERR_INVALID_ARG if the arguments are incorrect. */ -esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd); +esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd); + +/** + * Special function for registering another file descriptor with given local_fd + * for a VFS registered by esp_vfs_register_with_id. + * + * @param vfs_id VFS identificator returned by esp_vfs_register_with_id. + * @param local_fd The fd in the local vfs. Passing -1 will set the local fd as the (*fd) value. + * @param permanent Whether the fd should be treated as permannet (not removed after close()) + * @param fd The registered file descriptor will be written to this address. + * + * @return ESP_OK if the registration is successful, + * ESP_ERR_NO_MEM if too many file descriptors are registered, + * ESP_ERR_INVALID_ARG if the arguments are incorrect. + */ +esp_err_t esp_vfs_register_fd_with_local_fd(esp_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd); /** * Special function for unregistering a file descriptor belonging to a VFS diff --git a/components/vfs/include/esp_vfs_eventfd.h b/components/vfs/include/esp_vfs_eventfd.h index bae1a93f13..430112111a 100644 --- a/components/vfs/include/esp_vfs_eventfd.h +++ b/components/vfs/include/esp_vfs_eventfd.h @@ -1,4 +1,4 @@ -// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// Copyright 2021 Espressif Systems (Shanghai) CO LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,8 +25,11 @@ extern "C" { #endif +/** + * @brief Eventfd vfs initialization settings + */ typedef struct { - size_t max_fds; + size_t max_fds; /*!< The maxinum number of eventfds supported */ } esp_vfs_eventfd_config_t; #define ESP_VFS_EVENTD_CONFIG_DEFAULT() (esp_vfs_eventfd_config_t) { \ diff --git a/components/vfs/test/test_vfs_eventfd.c b/components/vfs/test/test_vfs_eventfd.c index f6500955ea..0d051008f1 100644 --- a/components/vfs/test/test_vfs_eventfd.c +++ b/components/vfs/test/test_vfs_eventfd.c @@ -217,7 +217,7 @@ TEST_CASE("eventfd signal from task", "[vfs][eventfd]") TEST_ESP_OK(esp_vfs_eventfd_unregister()); } -static void IRAM_ATTR eventfd_select_test_isr(void *arg) +static void eventfd_select_test_isr(void *arg) { int fd = *((int *)arg); uint64_t val = 1; @@ -248,7 +248,7 @@ TEST_CASE("eventfd signal from ISR", "[vfs][eventfd]") TEST_ESP_OK(timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, TIMER_BASE_CLK / 16)); TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0)); TEST_ESP_OK(timer_isr_register(TIMER_GROUP_0, TIMER_0, eventfd_select_test_isr, - &fd, ESP_INTR_FLAG_IRAM, NULL)); + &fd, ESP_INTR_FLAG_LOWMED, NULL)); TEST_ESP_OK(timer_start(TIMER_GROUP_0, TIMER_0)); struct timeval wait_time; @@ -300,7 +300,6 @@ TEST_CASE("eventfd select closed fd", "[vfs][eventfd]") TEST_ASSERT_EQUAL(1, ret); TEST_ASSERT(FD_ISSET(fd, &error_fds)); - TEST_ASSERT_EQUAL(0, close(fd)); TEST_ESP_OK(esp_vfs_eventfd_unregister()); } diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 6468232c2c..46890e3e64 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -209,10 +209,16 @@ esp_err_t esp_vfs_unregister(const char* base_path) return ESP_ERR_INVALID_STATE; } -esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd) +esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd) +{ + return esp_vfs_register_fd_with_local_fd(vfs_id, -1, true, fd); +} + +esp_err_t esp_vfs_register_fd_with_local_fd(esp_vfs_id_t vfs_id, int local_fd, bool permanent, int *fd) { if (vfs_id < 0 || vfs_id >= s_vfs_count || fd == NULL) { - ESP_LOGD(TAG, "Invalid arguments for esp_vfs_register_fd(%d, 0x%x)", vfs_id, (int) fd); + ESP_LOGD(TAG, "Invalid arguments for esp_vfs_register_fd_with_local_fd(%d, %d, %d, 0x%p)", + vfs_id, local_fd, permanent, fd); return ESP_ERR_INVALID_ARG; } @@ -234,7 +240,8 @@ esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int local_fd, bool permanent, } _lock_release(&s_fd_table_lock); - ESP_LOGD(TAG, "esp_vfs_register_fd(%d, 0x%x) finished with %s", vfs_id, (int) fd, esp_err_to_name(ret)); + ESP_LOGD(TAG, "esp_vfs_register_fd_with_local_fd(%d, %d, %d, 0x%p) finished with %s", + vfs_id, local_fd, permanent, fd, esp_err_to_name(ret)); return ret; } @@ -906,7 +913,6 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds } if (is_socket_fd) { - assert(false); if (!socket_select) { // no socket_select found yet so take a look if (esp_vfs_safe_fd_isset(fd, readfds) || diff --git a/components/vfs/vfs_eventfd.c b/components/vfs/vfs_eventfd.c index a32833b6e3..f5f3c49ed5 100644 --- a/components/vfs/vfs_eventfd.c +++ b/components/vfs/vfs_eventfd.c @@ -34,14 +34,30 @@ #define FD_INVALID -1 #define FD_PENDING_SELECT -2 +/* + * About the event_select_args_t linked list + * + * Each event_select_args_t structure records a pending select from a select call + * on a file descriptor. + * + * For each select() call, we form a linked list in end_select_args containing + * all the pending selects in this select call. + * + * For each file descriptor, we form a double linked list in event_context_t::select_args. + * This list contains all the pending selects on this file descriptor from + * different select() calls. + * + */ typedef struct event_select_args_t { int fd; fd_set *read_fds; fd_set *error_fds; esp_vfs_select_sem_t signal_sem; + // linked list node in event_context_t::select_args struct event_select_args_t *prev_in_fd; struct event_select_args_t *next_in_fd; - struct event_select_args_t *next_in_args; // a linked list for all pending select args for one select call + // linked list node in end_select_arg + struct event_select_args_t *next_in_args; } event_select_args_t; typedef struct { @@ -49,9 +65,11 @@ typedef struct { bool support_isr; volatile bool is_set; volatile uint64_t value; - event_select_args_t *select_args; // a double-linked list for all pending select args with this fd + // a double-linked list for all pending select args with this fd + event_select_args_t *select_args; _lock_t lock; - spinlock_t data_spin_lock; // only for event fds that support ISR. + // only for event fds that support ISR. + spinlock_t data_spin_lock; } event_context_t; esp_vfs_id_t s_eventfd_vfs_id = -1; @@ -79,6 +97,7 @@ static void trigger_select_for_event_isr(event_context_t *event, BaseType_t *tas } } +#ifdef CONFIG_VFS_SUPPORT_SELECT static esp_err_t event_start_select(int nfds, fd_set *readfds, fd_set *writefds, @@ -100,7 +119,8 @@ static esp_err_t event_start_select(int nfds, portENTER_CRITICAL(&s_events[i].data_spin_lock); } - event_select_args_t *event_select_args = (event_select_args_t *)malloc(sizeof(event_select_args_t)); + event_select_args_t *event_select_args = + (event_select_args_t *)malloc(sizeof(event_select_args_t)); event_select_args->fd = i; event_select_args->signal_sem = signal_sem; @@ -200,6 +220,7 @@ static esp_err_t event_end_select(void *end_select_args) return ESP_OK; } +#endif // CONFIG_VFS_SUPPORT_SELECT static ssize_t signal_event_fd_from_isr(int fd, const void *data, size_t size) { @@ -353,15 +374,12 @@ esp_err_t esp_vfs_eventfd_register(const esp_vfs_eventfd_config_t *config) esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, .write = &event_write, - .open = NULL, - .fstat = NULL, .close = &event_close, .read = &event_read, - .fcntl = NULL, - .fsync = NULL, - .access = NULL, +#ifdef CONFIG_VFS_SUPPORT_SELECT .start_select = &event_start_select, .end_select = &event_end_select, +#endif }; return esp_vfs_register_with_id(&vfs, NULL, &s_eventfd_vfs_id); } @@ -401,7 +419,7 @@ int eventfd(unsigned int initval, int flags) _lock_acquire_recursive(&s_events[i].lock); if (s_events[i].fd == FD_INVALID) { - error = esp_vfs_register_fd(s_eventfd_vfs_id, i, /*permanent=*/false, &global_fd); + error = esp_vfs_register_fd_with_local_fd(s_eventfd_vfs_id, i, /*permanent=*/false, &global_fd); if (error != ESP_OK) { _lock_release_recursive(&s_events[i].lock); break; diff --git a/examples/system/eventfd/Makefile b/examples/system/eventfd/Makefile index e70931d40b..c26394d601 100644 --- a/examples/system/eventfd/Makefile +++ b/examples/system/eventfd/Makefile @@ -3,6 +3,6 @@ # project subdirectory. # -PROJECT_NAME := select +PROJECT_NAME := eventfd include $(IDF_PATH)/make/project.mk diff --git a/examples/system/eventfd/README.md b/examples/system/eventfd/README.md index 9bcfc0acaa..2cbb444295 100644 --- a/examples/system/eventfd/README.md +++ b/examples/system/eventfd/README.md @@ -6,4 +6,69 @@ The example demonstrates the use of `eventfd()` to collect events from other tas 2. The timer interrupt handler writes to the second `eventfd`. 3. The second task collects the event from two fds with a `select()` loop. -See the README.md file in the upper level 'examples' directory for more information about examples. +## How to use example + +### Hardware Required + +This example should be able to run on any commonly available ESP32, ESP32S2, ESP32S3 or ESP32C3 development board. + +### Configure the project + +``` +idf.py menuconfig +``` + +The default config will work. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +The following log output should appear when the example runs (note that the bootloader log has been omitted). + +``` +I (4310) eventfd_example: Time: 1.99s +I (4310) eventfd_example: Select timeout +I (4310) eventfd_example: ================================= +I (4310) eventfd_example: Select timeouted for 1 times +I (4320) eventfd_example: Timer triggerred for 0 times +I (4320) eventfd_example: Progress triggerred for 0 times +I (4330) eventfd_example: ================================= +I (4810) eventfd_example: Time: 2.50s +I (4810) eventfd_example: TimerEvent fd event triggered +I (5810) eventfd_example: Time: 3.49s +I (5810) eventfd_example: Progress fd event triggered +I (7310) eventfd_example: Time: 5.00s +I (7310) eventfd_example: TimerEvent fd event triggered +I (9310) eventfd_example: Time: 6.99s +I (9310) eventfd_example: Select timeout +I (9310) eventfd_example: Time: 6.99s +I (9310) eventfd_example: Progress fd event triggered +I (9810) eventfd_example: Time: 7.50s +I (9810) eventfd_example: TimerEvent fd event triggered +I (11810) eventfd_example: Time: 9.49s +I (11810) eventfd_example: Select timeout +I (12310) eventfd_example: Time: 10.00s +I (12310) eventfd_example: TimerEvent fd event triggered +I (12810) eventfd_example: Time: 10.49s +I (12810) eventfd_example: Progress fd event triggered +I (14810) eventfd_example: Time: 12.49s +I (14810) eventfd_example: Select timeout +I (14810) eventfd_example: ================================= +I (14810) eventfd_example: Select timeouted for 4 times +I (14820) eventfd_example: Timer triggerred for 4 times +I (14820) eventfd_example: Progress triggerred for 3 times +I (14830) eventfd_example: ================================= +``` diff --git a/examples/system/eventfd/example_test.py b/examples/system/eventfd/example_test.py new file mode 100644 index 0000000000..8cce7fdad6 --- /dev/null +++ b/examples/system/eventfd/example_test.py @@ -0,0 +1,29 @@ +from __future__ import unicode_literals + +import os + +import ttfw_idf +from tiny_test_fw import Env, Utility + + +@ttfw_idf.idf_example_test(env_tag='Example_GENERIC') +def test_examples_eventfd(env, extra_data): + # type: (Env, None) -> None + + dut = env.get_dut('eventfd', 'examples/system/eventfd') + dut.start_app() + + dut.expect('cpu_start: Starting scheduler', timeout=30) + + exp_list = [ + 'eventfd_example: Select timeouted for 4 times', + 'eventfd_example: Timer triggerred for 4 times', + 'eventfd_example: Progress triggerred for 3 times', + ] + + Utility.console_log('Expecting:{}{}'.format(os.linesep, os.linesep.join(exp_list))) + dut.expect_all(*exp_list, timeout=60) + + +if __name__ == '__main__': + test_examples_eventfd() diff --git a/examples/system/eventfd/main/CMakeLists.txt b/examples/system/eventfd/main/CMakeLists.txt index 52e676a338..dafbf41a79 100644 --- a/examples/system/eventfd/main/CMakeLists.txt +++ b/examples/system/eventfd/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "eventfd_example.c" + LDFRAGMENTS linker.lf INCLUDE_DIRS ".") diff --git a/examples/system/eventfd/main/component.mk b/examples/system/eventfd/main/component.mk index a98f634eae..f3cf3c2887 100644 --- a/examples/system/eventfd/main/component.mk +++ b/examples/system/eventfd/main/component.mk @@ -2,3 +2,5 @@ # "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +COMPONENT_ADD_LDFRAGMENTS += linker.lf diff --git a/examples/system/eventfd/main/eventfd_example.c b/examples/system/eventfd/main/eventfd_example.c index fb0f0ecdbd..727c145a7b 100644 --- a/examples/system/eventfd/main/eventfd_example.c +++ b/examples/system/eventfd/main/eventfd_example.c @@ -34,7 +34,7 @@ static const char *TAG = "eventfd_example"; int s_timer_fd; int s_progress_fd; -static void IRAM_ATTR eventfd_timer_group0_isr(void *para) +static void eventfd_timer_group0_isr(void *para) { timer_spinlock_take(TIMER_GROUP_0); int timer_idx = (int) para; diff --git a/examples/system/eventfd/main/linker.lf b/examples/system/eventfd/main/linker.lf new file mode 100644 index 0000000000..c171663891 --- /dev/null +++ b/examples/system/eventfd/main/linker.lf @@ -0,0 +1,4 @@ +[mapping:main] +archive: libmain.a +entries: + eventfd_example:eventfd_timer_group0_isr (noflash)