vfs: add unit tests for eventfd

This commit is contained in:
Jiacheng Guo
2021-03-02 10:12:54 +08:00
parent f6fd2eb164
commit 30e9345bc7
3 changed files with 414 additions and 150 deletions

View File

@@ -14,171 +14,242 @@
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include <stdint.h> #include <errno.h>
#include <stdio.h>
#include <sys/select.h> #include <sys/select.h>
#include "driver/periph_ctrl.h"
#include "driver/timer.h" #include "driver/timer.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_vfs.h" #include "esp_vfs.h"
#include "freertos/FreeRTOS.h" #include "sys/_stdint.h"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "hal/timer_types.h"
#include "unity.h" #include "unity.h"
#define TIMER_DIVIDER 16 TEST_CASE("Test eventfd create and close", "[vfs][eventfd]")
#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), TEST_ESP_OK(esp_vfs_eventfd_register());
(uint32_t) (counter_value)); int fd = eventfd(0, 0);
printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE); TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
TEST_ASSERT_EQUAL(0, close(fd));
fd = eventfd(0, EFD_SUPPORT_ISR);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
TEST_ASSERT_EQUAL(0, close(fd));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
} }
void IRAM_ATTR timer_group0_isr(void *para) TEST_CASE("Test eventfd reject unknown flags", "[vfs][eventfd]")
{ {
timer_spinlock_take(TIMER_GROUP_0); TEST_ESP_OK(esp_vfs_eventfd_register());
int timer_idx = (int) para; int fd = eventfd(0, 1);
TEST_ASSERT_LESS_THAN(0, fd);
TEST_ASSERT_EQUAL(EINVAL, errno);
uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0); fd = eventfd(0, INT_MAX);
uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx); TEST_ASSERT_LESS_THAN(0, fd);
TEST_ASSERT_EQUAL(EINVAL, errno);
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
if (timer_intr & TIMER_INTR_T0) { TEST_CASE("Test eventfd read", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
unsigned int initval = 123;
int fd = eventfd(initval, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
uint64_t val = 0;
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(initval, val);
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(0, val);
TEST_ASSERT_EQUAL(0, close(fd));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
TEST_CASE("Test eventfd read invalid size", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
uint32_t val = 0;
TEST_ASSERT_LESS_THAN(0, read(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(EINVAL, errno);
TEST_ASSERT_EQUAL(0, close(fd));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
TEST_CASE("Test eventfd write invalid size", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
uint32_t val = 0;
TEST_ASSERT_LESS_THAN(0, write(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(EINVAL, errno);
TEST_ASSERT_EQUAL(0, close(fd));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
TEST_CASE("Test eventfd write then read", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
uint64_t val = 123;
TEST_ASSERT_EQUAL(sizeof(val), write(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(123, val);
val = 4;
TEST_ASSERT_EQUAL(sizeof(val), write(fd, &val, sizeof(val)));
val = 5;
TEST_ASSERT_EQUAL(sizeof(val), write(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
TEST_ASSERT_EQUAL(9, val);
TEST_ASSERT_EQUAL(0, close(fd));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
TEST_CASE("Test eventfd instant select", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
struct timeval zero_time;
fd_set read_fds, write_fds, error_fds;
zero_time.tv_sec = 0;
zero_time.tv_usec = 0;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
int ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &zero_time);
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT(!FD_ISSET(fd, &read_fds));
uint64_t val = 1;
printf("Write to fd\n");
TEST_ASSERT_EQUAL(sizeof(val), write(fd, &val, sizeof(val)));
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &zero_time);
TEST_ASSERT_EQUAL(1, ret);
TEST_ASSERT(FD_ISSET(fd, &read_fds));
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &zero_time);
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT(!FD_ISSET(fd, &read_fds));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
static void signal_task(void *arg)
{
int fd = *((int *)arg);
vTaskDelay(pdMS_TO_TICKS(1000));
uint64_t val = 1;
TEST_ASSERT_EQUAL(sizeof(val), write(fd, &val, sizeof(val)));
vTaskDelete(NULL);
}
TEST_CASE("Test eventfd signal from task", "[vfs][eventfd]")
{
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, 0);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
xTaskCreate(signal_task, "signal_task", 2048, &fd, 5, NULL);
struct timeval wait_time;
struct timeval zero_time;
fd_set read_fds, write_fds, error_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
wait_time.tv_sec = 2;
wait_time.tv_usec = 0;
zero_time.tv_sec = 0;
zero_time.tv_usec = 0;
FD_SET(fd, &read_fds);
int ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &wait_time);
TEST_ASSERT_EQUAL(1, ret);
TEST_ASSERT(FD_ISSET(fd, &read_fds));
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &zero_time);
TEST_ASSERT_EQUAL(1, ret);
TEST_ASSERT(FD_ISSET(fd, &read_fds));
uint64_t val;
TEST_ASSERT_EQUAL(sizeof(val), read(fd, &val, sizeof(val)));
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &zero_time);
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT(!FD_ISSET(fd, &read_fds));
TEST_ESP_OK(esp_vfs_eventfd_unregister());
}
static void IRAM_ATTR eventfd_select_test_isr(void *arg)
{
int fd = *((int *)arg);
uint64_t val = 1;
timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0); timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); int ret = write(fd, &val, sizeof(val));
timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value); assert(ret == sizeof(val));
}
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) TEST_CASE("Test eventfd signal from ISR", "[vfs][eventfd]")
{ {
TEST_ESP_OK(esp_vfs_eventfd_register());
int fd = eventfd(0, EFD_SUPPORT_ISR);
TEST_ASSERT_GREATER_OR_EQUAL(0, fd);
timer_config_t config = { timer_config_t config = {
.divider = TIMER_DIVIDER, .divider = 16,
.counter_dir = TIMER_COUNT_UP, .counter_dir = TIMER_COUNT_UP,
.counter_en = TIMER_PAUSE, .counter_en = TIMER_PAUSE,
.alarm_en = TIMER_ALARM_EN, .alarm_en = TIMER_ALARM_EN,
.auto_reload = false, .auto_reload = false,
}; };
timer_init(TIMER_GROUP_0, timer_idx, &config); TEST_ESP_OK(timer_init(TIMER_GROUP_0, TIMER_0, &config));
timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL); TEST_ESP_OK(timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL));
timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); TEST_ESP_OK(timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, TIMER_BASE_CLK / 16));
timer_enable_intr(TIMER_GROUP_0, timer_idx); TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0));
timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, TEST_ESP_OK(timer_isr_register(TIMER_GROUP_0, TIMER_0, eventfd_select_test_isr,
(void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL); &fd, ESP_INTR_FLAG_IRAM, NULL));
TEST_ESP_OK(timer_start(TIMER_GROUP_0, TIMER_0));
timer_start(TIMER_GROUP_0, timer_idx); struct timeval wait_time;
} fd_set read_fds, write_fds, error_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &read_fds);
wait_time.tv_sec = 2;
wait_time.tv_usec = 0;
static void eventfd_timer_deinit(int timer_idx) FD_SET(fd, &read_fds);
{ int ret = select(fd + 1, &read_fds, &write_fds, &error_fds, &wait_time);
timer_pause(TIMER_GROUP_0, timer_idx); TEST_ASSERT_EQUAL(1, ret);
timer_deinit(TIMER_GROUP_0, timer_idx); TEST_ASSERT(FD_ISSET(fd, &read_fds));
} timer_deinit(TIMER_GROUP_0, TIMER_0);
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);
TEST_ESP_OK(esp_vfs_eventfd_register());
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);
eventfd_timer_init(TIMER_0, TIMER_INTERVAL0_SEC);
int selectTimeoutCount = 0;
int timerTriggerCount = 0;
int progressTriggerCount = 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;
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(ret == sizeof(signal));
TEST_ASSERT(signal == PROGRESS_SIGNAL);
progressTriggerCount++;
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);
timerTriggerCount++;
printf("TimerEvent fd\n");
} else {
selectTimeoutCount++;
printf("Select timeout\n");
}
}
printf("Select timeout: %d\n", selectTimeoutCount);
printf("Timer trigger: %d\n", timerTriggerCount);
printf("Progress trigger: %d\n", progressTriggerCount);
TEST_ASSERT(selectTimeoutCount == 3);
TEST_ASSERT(timerTriggerCount == 4);
TEST_ASSERT(progressTriggerCount == 3);
printf("Test done\n");
close(s_progress_fd);
close(s_timer_fd);
eventfd_timer_deinit(TIMER_0);
TEST_ESP_OK(esp_vfs_eventfd_unregister()); TEST_ESP_OK(esp_vfs_eventfd_unregister());
} }

View File

@@ -0,0 +1,183 @@
// 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);
TEST_ESP_OK(esp_vfs_eventfd_register());
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());
}

View File

@@ -15,6 +15,7 @@
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -59,7 +60,7 @@ static esp_err_t event_start_select(int nfds,
_lock_acquire_recursive(&s_events[i].lock); _lock_acquire_recursive(&s_events[i].lock);
int fd = s_events[i].fd; int fd = s_events[i].fd;
if (fd != FD_INVALID) { if (fd != FD_INVALID && fd < nfds) {
if (s_events[i].support_isr) { if (s_events[i].support_isr) {
portENTER_CRITICAL(&s_events[i].data_spin_lock); portENTER_CRITICAL(&s_events[i].data_spin_lock);
} }
@@ -76,7 +77,6 @@ static esp_err_t event_start_select(int nfds,
if (FD_ISSET(fd, readfds)) { if (FD_ISSET(fd, readfds)) {
s_events[i].read_fds = readfds; s_events[i].read_fds = readfds;
if (s_events[i].is_set) { if (s_events[i].is_set) {
s_events[i].is_set = false;
should_trigger = true; should_trigger = true;
} else { } else {
FD_CLR(fd, readfds); FD_CLR(fd, readfds);
@@ -108,7 +108,6 @@ static esp_err_t event_end_select(void *end_select_args)
memset(&s_events[i].signal_sem, 0, sizeof(s_events[i].signal_sem)); memset(&s_events[i].signal_sem, 0, sizeof(s_events[i].signal_sem));
if (s_events[i].read_fds && s_events[i].is_set) { if (s_events[i].read_fds && s_events[i].is_set) {
FD_SET(s_events[i].fd, s_events[i].read_fds); FD_SET(s_events[i].fd, s_events[i].read_fds);
s_events[i].is_set = false;
s_events[i].read_fds = NULL; s_events[i].read_fds = NULL;
} }
if (s_events[i].write_fds) { if (s_events[i].write_fds) {
@@ -145,7 +144,7 @@ static int event_open(const char *path, int flags, int mode)
} }
ssize_t esp_signal_event_fd_from_isr(int fd, const void *data, size_t size) static ssize_t signal_event_fd_from_isr(int fd, const void *data, size_t size)
{ {
BaseType_t task_woken = pdFALSE; BaseType_t task_woken = pdFALSE;
const uint64_t *val = (const uint64_t *)data; const uint64_t *val = (const uint64_t *)data;
@@ -171,14 +170,16 @@ static ssize_t event_write(int fd, const void *data, size_t size)
ssize_t ret = -1; ssize_t ret = -1;
if (fd >= NUM_EVENT_FDS || data == NULL || size != sizeof(uint64_t)) { if (fd >= NUM_EVENT_FDS || data == NULL || size != sizeof(uint64_t)) {
errno = EINVAL;
return ret; return ret;
} }
if (size != sizeof(uint64_t)) { if (size != sizeof(uint64_t)) {
errno = EINVAL;
return ret; return ret;
} }
if (xPortInIsrContext()) { if (xPortInIsrContext()) {
ret = esp_signal_event_fd_from_isr(fd, data, size); ret = signal_event_fd_from_isr(fd, data, size);
} else { } else {
const uint64_t *val = (const uint64_t *)data; const uint64_t *val = (const uint64_t *)data;
_lock_acquire_recursive(&s_events[fd].lock); _lock_acquire_recursive(&s_events[fd].lock);
@@ -206,9 +207,11 @@ static ssize_t event_read(int fd, void *data, size_t size)
ssize_t ret = -1; ssize_t ret = -1;
if (fd >= NUM_EVENT_FDS) { if (fd >= NUM_EVENT_FDS) {
errno = EINVAL;
return ret; return ret;
} }
if (size != sizeof(uint64_t)) { if (size != sizeof(uint64_t)) {
errno = EINVAL;
return ret; return ret;
} }
@@ -220,6 +223,7 @@ static ssize_t event_read(int fd, void *data, size_t size)
portENTER_CRITICAL(&s_events[fd].data_spin_lock); portENTER_CRITICAL(&s_events[fd].data_spin_lock);
} }
*val = s_events[fd].value; *val = s_events[fd].value;
s_events[fd].is_set = false;
ret = size; ret = size;
s_events[fd].value = 0; s_events[fd].value = 0;
if (s_events[fd].support_isr) { if (s_events[fd].support_isr) {
@@ -255,7 +259,7 @@ static int event_close(int fd)
} }
_lock_release_recursive(&s_events[fd].lock); _lock_release_recursive(&s_events[fd].lock);
_lock_close(&s_events[fd].lock); _lock_close_recursive(&s_events[fd].lock);
return ret; return ret;
} }
@@ -294,12 +298,18 @@ esp_err_t esp_vfs_eventfd_unregister(void)
int eventfd(unsigned int initval, int flags) int eventfd(unsigned int initval, int flags)
{ {
int fd = -1; int fd = FD_INVALID;
if ((flags & (~EFD_SUPPORT_ISR)) != 0) {
errno = EINVAL;
return FD_INVALID;
}
for (size_t i = 0; i < NUM_EVENT_FDS; i++) { for (size_t i = 0; i < NUM_EVENT_FDS; i++) {
bool support_isr = flags & EFD_SUPPORT_ISR; bool support_isr = flags & EFD_SUPPORT_ISR;
bool has_allocated = false; bool has_allocated = false;
_lock_init_recursive(&s_events[i].lock);
_lock_acquire_recursive(&s_events[i].lock); _lock_acquire_recursive(&s_events[i].lock);
if (s_events[i].fd == FD_INVALID) { if (s_events[i].fd == FD_INVALID) {
s_events[i].fd = i; s_events[i].fd = i;
@@ -327,5 +337,5 @@ int eventfd(unsigned int initval, int flags)
return fd; return fd;
} }
} }
return -1; return FD_INVALID;
} }