-// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2018-2019 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.
// 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.
+
#ifndef _ESP_PLATFORM_SYS_POLL_H_
#define _ESP_PLATFORM_SYS_POLL_H_
-#define POLLIN 0x0001 /* any readable data available */
-#define POLLOUT 0x0004 /* file descriptor is writeable */
-#define POLLPRI 0x0002 /* OOB/Urgent readable data */
-#define POLLERR 0x0008 /* some poll error occurred */
-#define POLLHUP 0x0010 /* file descriptor was "hung up" */
+#define POLLIN (1u << 0) /* data other than high-priority may be read without blocking */
+#define POLLRDNORM (1u << 1) /* normal data may be read without blocking */
+#define POLLRDBAND (1u << 2) /* priority data may be read without blocking */
+#define POLLPRI (POLLRDBAND) /* high-priority data may be read without blocking */
+// Note: POLLPRI is made equivalent to POLLRDBAND in order to fit all these events into one byte
+#define POLLOUT (1u << 3) /* normal data may be written without blocking */
+#define POLLWRNORM (POLLOUT) /* equivalent to POLLOUT */
+#define POLLWRBAND (1u << 4) /* priority data my be written */
+#define POLLERR (1u << 5) /* some poll error occurred */
+#define POLLHUP (1u << 6) /* file descriptor was "hung up" */
+#define POLLNVAL (1u << 7) /* the specified file descriptor is invalid */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
struct pollfd {
- int fd; /* The descriptor. */
- short events; /* The event(s) is/are specified here. */
- short revents; /* Events found are returned here. */
+ int fd; /* The descriptor. */
+ short events; /* The event(s) is/are specified here. */
+ short revents; /* Events found are returned here. */
};
typedef unsigned int nfds_t;
+
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif // _ESP_PLATFORM_SYS_POLL_H_
-// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2018-2019 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.
deinit(uart_fd, socket_fd);
}
+TEST_CASE("UART can do poll()", "[vfs]")
+{
+ int uart_fd;
+ int socket_fd;
+ char recv_message[sizeof(message)];
+
+ init(&uart_fd, &socket_fd);
+
+ struct pollfd poll_fds[] = {
+ {
+ .fd = uart_fd,
+ .events = POLLIN,
+ },
+ {
+ .fd = -1, // should be ignored according to the documentation of poll()
+ },
+ };
+
+ const test_task_param_t test_task_param = {
+ .fd = uart_fd,
+ .delay_ms = 50,
+ .sem = xSemaphoreCreateBinary(),
+ };
+ TEST_ASSERT_NOT_NULL(test_task_param.sem);
+ start_task(&test_task_param);
+
+ int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100);
+ TEST_ASSERT_EQUAL(s, 1);
+ TEST_ASSERT_EQUAL(uart_fd, poll_fds[0].fd);
+ TEST_ASSERT_EQUAL(POLLIN, poll_fds[0].revents);
+ TEST_ASSERT_EQUAL(-1, poll_fds[1].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[1].revents);
+
+ int read_bytes = read(uart_fd, recv_message, sizeof(message));
+ TEST_ASSERT_EQUAL(read_bytes, sizeof(message));
+ TEST_ASSERT_EQUAL_MEMORY(message, recv_message, sizeof(message));
+
+ TEST_ASSERT_EQUAL(xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS), pdTRUE);
+
+ poll_fds[1].fd = socket_fd;
+ poll_fds[1].events = POLLIN;
+
+ start_task(&test_task_param);
+
+ s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100);
+ TEST_ASSERT_EQUAL(s, 1);
+ TEST_ASSERT_EQUAL(uart_fd, poll_fds[0].fd);
+ TEST_ASSERT_EQUAL(POLLIN, poll_fds[0].revents);
+ TEST_ASSERT_EQUAL(socket_fd, poll_fds[1].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[1].revents);
+
+ read_bytes = read(uart_fd, recv_message, sizeof(message));
+ TEST_ASSERT_EQUAL(read_bytes, sizeof(message));
+ TEST_ASSERT_EQUAL_MEMORY(message, recv_message, sizeof(message));
+
+ TEST_ASSERT_EQUAL(xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS), pdTRUE);
+ vSemaphoreDelete(test_task_param.sem);
+
+ deinit(uart_fd, socket_fd);
+}
+
TEST_CASE("socket can do select()", "[vfs]")
{
int uart_fd;
close(dummy_socket_fd);
}
+TEST_CASE("socket can do poll()", "[vfs]")
+{
+ int uart_fd;
+ int socket_fd;
+ char recv_message[sizeof(message)];
+
+ init(&uart_fd, &socket_fd);
+ const int dummy_socket_fd = open_dummy_socket();
+
+ struct pollfd poll_fds[] = {
+ {
+ .fd = uart_fd,
+ .events = POLLIN,
+ },
+ {
+ .fd = socket_fd,
+ .events = POLLIN,
+ },
+ {
+ .fd = dummy_socket_fd,
+ .events = POLLIN,
+ },
+ };
+
+ const test_task_param_t test_task_param = {
+ .fd = socket_fd,
+ .delay_ms = 50,
+ .sem = xSemaphoreCreateBinary(),
+ };
+ TEST_ASSERT_NOT_NULL(test_task_param.sem);
+ start_task(&test_task_param);
+
+ int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100);
+ TEST_ASSERT_EQUAL(s, 1);
+ TEST_ASSERT_EQUAL(uart_fd, poll_fds[0].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[0].revents);
+ TEST_ASSERT_EQUAL(socket_fd, poll_fds[1].fd);
+ TEST_ASSERT_EQUAL(POLLIN, poll_fds[1].revents);
+ TEST_ASSERT_EQUAL(dummy_socket_fd, poll_fds[2].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[2].revents);
+
+ int read_bytes = read(socket_fd, recv_message, sizeof(message));
+ TEST_ASSERT_EQUAL(read_bytes, sizeof(message));
+ TEST_ASSERT_EQUAL_MEMORY(message, recv_message, sizeof(message));
+
+ TEST_ASSERT_EQUAL(xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS), pdTRUE);
+ vSemaphoreDelete(test_task_param.sem);
+
+ deinit(uart_fd, socket_fd);
+ close(dummy_socket_fd);
+}
+
TEST_CASE("select() timeout", "[vfs]")
{
int uart_fd;
deinit(uart_fd, socket_fd);
}
+TEST_CASE("poll() timeout", "[vfs]")
+{
+ int uart_fd;
+ int socket_fd;
+
+ init(&uart_fd, &socket_fd);
+
+ struct pollfd poll_fds[] = {
+ {
+ .fd = uart_fd,
+ .events = POLLIN,
+ },
+ {
+ .fd = socket_fd,
+ .events = POLLIN,
+ },
+ };
+
+ int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100);
+ TEST_ASSERT_EQUAL(s, 0);
+ TEST_ASSERT_EQUAL(uart_fd, poll_fds[0].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[0].revents);
+ TEST_ASSERT_EQUAL(socket_fd, poll_fds[1].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[1].revents);
+
+ poll_fds[0].fd = -1;
+ poll_fds[1].fd = -1;
+
+ s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100);
+ TEST_ASSERT_EQUAL(s, 0);
+ TEST_ASSERT_EQUAL(-1, poll_fds[0].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[0].revents);
+ TEST_ASSERT_EQUAL(-1, poll_fds[1].fd);
+ TEST_ASSERT_EQUAL(0, poll_fds[1].revents);
+
+ deinit(uart_fd, socket_fd);
+}
+
static void select_task(void *param)
{
const test_task_param_t *test_task_param = param;
-// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2015-2019 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.
CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times);
return ret;
}
+
+int esp_vfs_poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ struct timeval tv = {
+ // timeout is in milliseconds
+ .tv_sec = timeout / 1000,
+ .tv_usec = (timeout % 1000) * 1000,
+ };
+ int max_fd = -1;
+ fd_set readfds;
+ fd_set writefds;
+ fd_set errorfds;
+ struct _reent* r = __getreent();
+ int ret = 0;
+
+ if (fds == NULL) {
+ __errno_r(r) = ENOENT;
+ return -1;
+ }
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&errorfds);
+
+ for (int i = 0; i < nfds; ++i) {
+ fds[i].revents = 0;
+
+ if (fds[i].fd < 0) {
+ // revents should remain 0 and events ignored (according to the documentation of poll()).
+ continue;
+ }
+
+ if (fds[i].fd >= MAX_FDS) {
+ fds[i].revents |= POLLNVAL;
+ ++ret;
+ continue;
+ }
+
+ if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
+ FD_SET(fds[i].fd, &readfds);
+ FD_SET(fds[i].fd, &errorfds);
+ max_fd = MAX(max_fd, fds[i].fd);
+ }
+
+ if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
+ FD_SET(fds[i].fd, &writefds);
+ FD_SET(fds[i].fd, &errorfds);
+ max_fd = MAX(max_fd, fds[i].fd);
+ }
+ }
+
+ const int select_ret = esp_vfs_select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL: &tv);
+
+ if (select_ret > 0) {
+ ret += select_ret;
+
+ for (int i = 0; i < nfds; ++i) {
+ if (FD_ISSET(fds[i].fd, &readfds)) {
+ fds[i].revents |= POLLIN;
+ }
+
+ if (FD_ISSET(fds[i].fd, &writefds)) {
+ fds[i].revents |= POLLOUT;
+ }
+
+ if (FD_ISSET(fds[i].fd, &errorfds)) {
+ fds[i].revents |= POLLERR;
+ }
+ }
+ } else {
+ ret = select_ret;
+ // keeping the errno from select()
+ }
+
+ return ret;
+}