Forráskód Böngészése

vfs: add example for eventfd

Jiacheng Guo 5 éve
szülő
commit
37a992bbde

+ 0 - 186
components/vfs/test/test_vfs_eventfd_integration.c

@@ -1,186 +0,0 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License
-
-#include "esp_vfs_eventfd.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/select.h>
-
-#include "driver/periph_ctrl.h"
-#include "driver/timer.h"
-#include "esp_err.h"
-#include "esp_types.h"
-#include "esp_vfs.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/queue.h"
-#include "freertos/task.h"
-#include "hal/timer_types.h"
-#include "unity.h"
-
-#define TIMER_DIVIDER         16
-#define TIMER_SCALE           (TIMER_BASE_CLK / TIMER_DIVIDER)
-#define TIMER_INTERVAL0_SEC   (0.25)
-#define TEST_WITHOUT_RELOAD   0
-#define PROGRESS_INTERVAL_MS  350
-#define TIMER_SIGNAL          1
-#define PROGRESS_SIGNAL       2
-
-int s_timer_fd;
-int s_progress_fd;
-
-/*
- * A simple helper function to print the raw timer counter value
- * and the counter value converted to seconds
- */
-static void inline print_timer_counter(uint64_t counter_value)
-{
-    printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),
-           (uint32_t) (counter_value));
-    printf("Time   : %.8f s\n", (double) counter_value / TIMER_SCALE);
-}
-
-static void IRAM_ATTR eventfd_timer_group0_isr(void *para)
-{
-    timer_spinlock_take(TIMER_GROUP_0);
-    int timer_idx = (int) para;
-
-    uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
-    uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx);
-
-    if (timer_intr & TIMER_INTR_T0) {
-        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
-        timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
-        timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value);
-    }
-
-    timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx);
-
-    uint64_t signal = TIMER_SIGNAL;
-    ssize_t val = write(s_timer_fd, &signal, sizeof(signal));
-    assert(val == sizeof(signal));
-    timer_spinlock_give(TIMER_GROUP_0);
-}
-
-static void eventfd_timer_init(int timer_idx, double timer_interval_sec)
-{
-    timer_config_t config = {
-        .divider = TIMER_DIVIDER,
-        .counter_dir = TIMER_COUNT_UP,
-        .counter_en = TIMER_PAUSE,
-        .alarm_en = TIMER_ALARM_EN,
-        .auto_reload = false,
-    };
-    TEST_ESP_OK(timer_init(TIMER_GROUP_0, timer_idx, &config));
-
-    TEST_ESP_OK(timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL));
-
-    TEST_ESP_OK(timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE));
-    TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, timer_idx));
-    TEST_ESP_OK(timer_isr_register(TIMER_GROUP_0, timer_idx, eventfd_timer_group0_isr,
-                                   (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL));
-
-    TEST_ESP_OK(timer_start(TIMER_GROUP_0, timer_idx));
-}
-
-static void eventfd_timer_deinit(int timer_idx)
-{
-    timer_pause(TIMER_GROUP_0, timer_idx);
-    timer_deinit(TIMER_GROUP_0, timer_idx);
-}
-
-static void worker_task(void *arg)
-{
-    for (int i = 0; i < 3; i++) {
-        vTaskDelay(pdMS_TO_TICKS(PROGRESS_INTERVAL_MS));
-        uint64_t signal = PROGRESS_SIGNAL;
-        ssize_t val = write(s_progress_fd, &signal, sizeof(signal));
-        assert(val == sizeof(signal));
-    }
-    vTaskDelete(NULL);
-}
-
-TEST_CASE("Test eventfd triggered correctly", "[vfs][eventfd]")
-{
-    xTaskCreate(worker_task, "worker_task", 1024, NULL, 5, NULL);
-    esp_vfs_eventfd_config_t config = {
-        .eventfd_max_num = 5,
-    };
-    TEST_ESP_OK(esp_vfs_eventfd_register(&config));
-    s_timer_fd = eventfd(0, EFD_SUPPORT_ISR);
-    s_progress_fd = eventfd(0, 0);
-    int maxFd = s_progress_fd > s_timer_fd ? s_progress_fd : s_timer_fd;
-    printf("Timer fd %d progress fd %d\n", s_timer_fd, s_progress_fd);
-    TEST_ASSERT_GREATER_OR_EQUAL(0, s_timer_fd);
-    TEST_ASSERT_GREATER_OR_EQUAL(0, s_progress_fd);
-    eventfd_timer_init(TIMER_0, TIMER_INTERVAL0_SEC);
-
-    int select_timeout_count = 0;
-    int timer_trigger_count = 0;
-    int progress_trigger_count = 0;
-
-    for (size_t i = 0; i < 10; i++) {
-        struct timeval timeout;
-        uint64_t signal;
-
-        timeout.tv_sec = 0;
-        timeout.tv_usec = 200 * 1000;
-
-        fd_set readfds;
-        fd_set writefds;
-        fd_set errorfds;
-
-        FD_ZERO(&readfds);
-        FD_ZERO(&writefds);
-        FD_ZERO(&errorfds);
-
-        FD_SET(s_timer_fd, &readfds);
-        FD_SET(s_progress_fd, &readfds);
-
-        select(maxFd + 1, &readfds, &writefds, &errorfds, &timeout);
-
-        printf("-------- TASK TIME --------\n");
-        uint64_t task_counter_value;
-        TEST_ESP_OK(timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &task_counter_value));
-        print_timer_counter(task_counter_value);
-
-        if (FD_ISSET(s_progress_fd, &readfds)) {
-            ssize_t ret = read(s_progress_fd, &signal, sizeof(signal));
-            TEST_ASSERT_EQUAL(ret, sizeof(signal));
-            TEST_ASSERT_EQUAL(signal, PROGRESS_SIGNAL);
-            progress_trigger_count++;
-            printf("Progress fd\n");
-        } else if (FD_ISSET(s_timer_fd, &readfds)) {
-            ssize_t ret = read(s_timer_fd, &signal, sizeof(signal));
-            TEST_ASSERT(ret == sizeof(signal));
-            TEST_ASSERT(signal == TIMER_SIGNAL);
-            timer_trigger_count++;
-            printf("TimerEvent fd\n");
-        } else {
-            select_timeout_count++;
-            printf("Select timeout\n");
-        }
-    }
-
-    printf("Select timeout: %d\n", select_timeout_count);
-    printf("Timer trigger: %d\n", timer_trigger_count);
-    printf("Progress trigger: %d\n", progress_trigger_count);
-    TEST_ASSERT_EQUAL(3, select_timeout_count);
-    TEST_ASSERT_EQUAL(4, timer_trigger_count);
-    TEST_ASSERT_EQUAL(3, progress_trigger_count);
-    TEST_ASSERT_EQUAL(0, close(s_progress_fd));
-    TEST_ASSERT_EQUAL(0, close(s_timer_fd));
-    eventfd_timer_deinit(TIMER_0);
-    TEST_ESP_OK(esp_vfs_eventfd_unregister());
-}

+ 6 - 0
examples/system/eventfd/CMakeLists.txt

@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(eventfd)

+ 8 - 0
examples/system/eventfd/Makefile

@@ -0,0 +1,8 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := select
+
+include $(IDF_PATH)/make/project.mk

+ 9 - 0
examples/system/eventfd/README.md

@@ -0,0 +1,9 @@
+# eventfd example
+
+The example demonstrates the use of `eventfd()` to collect events from other tasks and ISRs in a
+`select()` based main loop.  The example starts two tasks and installs a timer interrupt handler:
+1. The first task writes to the first `eventfd` periodically.
+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.

+ 2 - 0
examples/system/eventfd/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "eventfd_example.c"
+                       INCLUDE_DIRS ".")

+ 4 - 0
examples/system/eventfd/main/component.mk

@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

+ 168 - 0
examples/system/eventfd/main/eventfd_example.c

@@ -0,0 +1,168 @@
+/* eventfd example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <sys/select.h>
+
+#include "driver/timer.h"
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_vfs.h"
+#include "esp_vfs_dev.h"
+#include "esp_vfs_eventfd.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "hal/timer_types.h"
+
+#define TIMER_DIVIDER         16
+#define TIMER_SCALE           (TIMER_BASE_CLK / TIMER_DIVIDER)
+#define MS_PER_S              1000
+#define TIMER_INTERVAL_SEC    2.5
+#define TEST_WITHOUT_RELOAD   0
+#define PROGRESS_INTERVAL_MS  3500
+#define TIMER_SIGNAL          1
+#define PROGRESS_SIGNAL       2
+
+static const char *TAG = "eventfd_example";
+
+int s_timer_fd;
+int s_progress_fd;
+
+static void IRAM_ATTR eventfd_timer_group0_isr(void *para)
+{
+    timer_spinlock_take(TIMER_GROUP_0);
+    int timer_idx = (int) para;
+
+    uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
+    uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx);
+
+    if (timer_intr & TIMER_INTR_T0) {
+        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
+        timer_counter_value += (uint64_t) (TIMER_INTERVAL_SEC * TIMER_SCALE);
+        timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value);
+    }
+
+    timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx);
+
+    uint64_t signal = TIMER_SIGNAL;
+    ssize_t val = write(s_timer_fd, &signal, sizeof(signal));
+    assert(val == sizeof(signal));
+    timer_spinlock_give(TIMER_GROUP_0);
+}
+
+static void eventfd_timer_init(int timer_idx, double timer_interval_sec)
+{
+    timer_config_t config = {
+        .divider = TIMER_DIVIDER,
+        .counter_dir = TIMER_COUNT_UP,
+        .counter_en = TIMER_PAUSE,
+        .alarm_en = TIMER_ALARM_EN,
+        .auto_reload = false,
+    };
+    ESP_ERROR_CHECK(timer_init(TIMER_GROUP_0, timer_idx, &config));
+
+    ESP_ERROR_CHECK(timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL));
+
+    ESP_ERROR_CHECK(timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE));
+    ESP_ERROR_CHECK(timer_enable_intr(TIMER_GROUP_0, timer_idx));
+    ESP_ERROR_CHECK(timer_isr_register(TIMER_GROUP_0, timer_idx, eventfd_timer_group0_isr,
+                                       NULL, ESP_INTR_FLAG_IRAM, NULL));
+
+    ESP_ERROR_CHECK(timer_start(TIMER_GROUP_0, timer_idx));
+}
+
+static void worker_task(void *arg)
+{
+    while (true) {
+        vTaskDelay(pdMS_TO_TICKS(PROGRESS_INTERVAL_MS));
+        uint64_t signal = PROGRESS_SIGNAL;
+        ssize_t val = write(s_progress_fd, &signal, sizeof(signal));
+        assert(val == sizeof(signal));
+    }
+    vTaskDelete(NULL);
+}
+
+static void collector_task(void *arg)
+{
+    esp_vfs_eventfd_config_t config = {
+        .eventfd_max_num = 2,
+    };
+    ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config));
+
+    s_timer_fd = eventfd(0, EFD_SUPPORT_ISR);
+    s_progress_fd = eventfd(0, 0);
+    assert(s_timer_fd > 0);
+    assert(s_progress_fd > 0);
+
+    int maxFd = s_progress_fd > s_timer_fd ? s_progress_fd : s_timer_fd;
+    int select_timeout_count = 0;
+    int timer_trigger_count = 0;
+    int progress_trigger_count = 0;
+
+    for (size_t i = 0; ; i++) {
+        struct timeval timeout;
+        uint64_t signal;
+
+        timeout.tv_sec = 2;
+        timeout.tv_usec = 0;
+
+        fd_set readfds;
+        FD_ZERO(&readfds);
+        FD_SET(s_timer_fd, &readfds);
+        FD_SET(s_progress_fd, &readfds);
+
+        int num_triggered = select(maxFd + 1, &readfds, NULL, NULL, &timeout);
+        assert(num_triggered >= 0);
+
+        uint64_t task_counter_value;
+        timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &task_counter_value);
+        ESP_LOGI(TAG, "Time: %.2fs", (double)task_counter_value / TIMER_SCALE);
+
+        if (FD_ISSET(s_progress_fd, &readfds)) {
+            ssize_t ret = read(s_progress_fd, &signal, sizeof(signal));
+            assert(ret == sizeof(signal));
+            assert(signal == PROGRESS_SIGNAL);
+            progress_trigger_count++;
+            ESP_LOGI(TAG, "Progress fd event triggered");
+        }
+        if (FD_ISSET(s_timer_fd, &readfds)) {
+            ssize_t ret = read(s_timer_fd, &signal, sizeof(signal));
+            assert(ret == sizeof(signal));
+            assert(signal == TIMER_SIGNAL);
+            timer_trigger_count++;
+            ESP_LOGI(TAG, "TimerEvent fd event triggered");
+        }
+        if (num_triggered == 0) {
+            select_timeout_count++;
+            ESP_LOGI(TAG, "Select timeout");
+        }
+
+        if (i % 10 == 0) {
+            ESP_LOGI(TAG, "=================================");
+            ESP_LOGI(TAG, "Select timeouted for %d times", select_timeout_count);
+            ESP_LOGI(TAG, "Timer triggerred for %d times", timer_trigger_count);
+            ESP_LOGI(TAG, "Progress triggerred for %d times", progress_trigger_count);
+            ESP_LOGI(TAG, "=================================");
+
+        }
+    }
+
+    timer_deinit(TIMER_GROUP_0, TIMER_0);
+    close(s_timer_fd);
+    close(s_progress_fd);
+    esp_vfs_eventfd_unregister();
+    vTaskDelete(NULL);
+}
+
+void app_main(void)
+{
+    eventfd_timer_init(TIMER_0, TIMER_INTERVAL_SEC);
+    xTaskCreate(worker_task, "worker_task", 4 * 1024, NULL, 5, NULL);
+    xTaskCreate(collector_task, "collector_task", 4 * 1024, NULL, 5, NULL);
+}