aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartekgola@gmail.com>2018-04-14 22:20:53 +0200
committerBartosz Golaszewski <bartekgola@gmail.com>2018-04-15 19:15:28 +0200
commitd3ea4f41484693320153bae226c27c507afef00c (patch)
tree460d89b3d1e32227e7ff556a45fbe0dc1dc5c980
parenta178da8c95f2fda20278763e9bfea679718eec3e (diff)
downloadlibgpiod-d3ea4f41484693320153bae226c27c507afef00c.tar.gz
core: events: correctly handle POLLNVAL in gpiod_line_event_wait()
The only error that can be indicated by ppoll() in the revents field of struct pollfd when polling a line events file descriptor is POLLNVAL. It can happen if the user calls close() on said descriptor after retrieving it with gpiod_line_event_get_fd(). Currently we would act as if there's a line event to read. Make gpiod_line_event_wait() and its bulk variant return -1 and set errno to EINVAL in this case. Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
-rw-r--r--src/lib/core.c17
-rw-r--r--tests/tests-event.c40
2 files changed, 52 insertions, 5 deletions
diff --git a/src/lib/core.c b/src/lib/core.c
index 8b89517f..ed802737 100644
--- a/src/lib/core.c
+++ b/src/lib/core.c
@@ -698,16 +698,23 @@ int gpiod_line_event_wait_bulk(struct gpiod_line_bulk *bulk,
else if (rv == 0)
return 0;
- if (event_bulk) {
+ if (event_bulk)
gpiod_line_bulk_init(event_bulk);
- for (off = 0; off < num_lines; off++) {
- if (fds[off].revents) {
+ for (off = 0; off < num_lines; off++) {
+ if (fds[off].revents) {
+ if (fds[off].revents & POLLNVAL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (event_bulk) {
line = gpiod_line_bulk_get_line(bulk, off);
gpiod_line_bulk_add(event_bulk, line);
- if (!--rv)
- break;
}
+
+ if (!--rv)
+ break;
}
}
diff --git a/tests/tests-event.c b/tests/tests-event.c
index 9dbaa658..f91d80fe 100644
--- a/tests/tests-event.c
+++ b/tests/tests-event.c
@@ -9,6 +9,7 @@
#include "gpiod-test.h"
+#include <unistd.h>
#include <errno.h>
static void event_rising_edge_good(void)
@@ -293,3 +294,42 @@ static void event_request_bulk_fail(void)
TEST_DEFINE(event_request_bulk_fail,
"events - failed bulk request (test reversed release)",
0, { 8 });
+
+static void event_invalid_fd(void)
+{
+ TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
+ struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+ struct gpiod_line_bulk ev_bulk;
+ struct timespec ts = { 1, 0 };
+ struct gpiod_line *line;
+ int rv, fd;
+
+ chip = gpiod_chip_open(test_chip_path(0));
+ TEST_ASSERT_NOT_NULL(chip);
+
+ line = gpiod_chip_get_line(chip, 5);
+ TEST_ASSERT_NOT_NULL(line);
+
+ rv = gpiod_line_request_both_edges_events(line, TEST_CONSUMER);
+ TEST_ASSERT_RET_OK(rv);
+
+ fd = gpiod_line_event_get_fd(line);
+ close(fd);
+
+ rv = gpiod_line_event_wait(line, &ts);
+ TEST_ASSERT_EQ(rv, -1);
+ TEST_ASSERT_ERRNO_IS(EINVAL);
+
+ /*
+ * The single line variant calls gpiod_line_event_wait_bulk() with the
+ * event_bulk argument set to NULL, so test this use case explicitly
+ * as well.
+ */
+ gpiod_line_bulk_add(&bulk, line);
+ rv = gpiod_line_event_wait_bulk(&bulk, &ts, &ev_bulk);
+ TEST_ASSERT_EQ(rv, -1);
+ TEST_ASSERT_ERRNO_IS(EINVAL);
+}
+TEST_DEFINE(event_invalid_fd,
+ "events - gpiod_line_event_wait() error on closed fd",
+ 0, { 8 });