diff mbox series

[libgpiod,v2] treewide: allow polling functions to block indefinitely

Message ID 20220701110025.58399-1-brgl@bgdev.pl
State New
Headers show
Series [libgpiod,v2] treewide: allow polling functions to block indefinitely | expand

Commit Message

Bartosz Golaszewski July 1, 2022, 11 a.m. UTC
All polling system calls have some way of being instructed to block
indefinitely until some event is registered on the file descriptor.

Make both the gpiod_chip_wait_info_event() and
gpiod_line_request_wait_edge_event() accept negative timeout values in
which case the underlying ppoll() will block indefinitely.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
 include/gpiod.h    | 14 ++++++++++----
 lib/chip.c         |  2 +-
 lib/internal.c     | 10 ++++++----
 lib/internal.h     |  2 +-
 lib/line-request.c |  2 +-
 5 files changed, 19 insertions(+), 11 deletions(-)

Comments

Andy Shevchenko July 1, 2022, 11:10 a.m. UTC | #1
On Fri, Jul 1, 2022 at 1:06 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> All polling system calls have some way of being instructed to block
> indefinitely until some event is registered on the file descriptor.
>
> Make both the gpiod_chip_wait_info_event() and
> gpiod_line_request_wait_edge_event() accept negative timeout values in
> which case the underlying ppoll() will block indefinitely.

Long time no user space done by me, so here my silly question: how to
kill a task that is blocking indefinitely in ppoll()?
Kent Gibson July 1, 2022, 11:52 a.m. UTC | #2
On Fri, Jul 01, 2022 at 01:10:12PM +0200, Andy Shevchenko wrote:
> On Fri, Jul 1, 2022 at 1:06 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > All polling system calls have some way of being instructed to block
> > indefinitely until some event is registered on the file descriptor.
> >
> > Make both the gpiod_chip_wait_info_event() and
> > gpiod_line_request_wait_edge_event() accept negative timeout values in
> > which case the underlying ppoll() will block indefinitely.
> 
> Long time no user space done by me, so here my silly question: how to
> kill a task that is blocking indefinitely in ppoll()?
> 

Yeah, you don't.  In a multi-threaded app you never need to - that
thread is dedicated to handling events, and it will keep doing that
until the app exits.

But if you want to be able to cancel the wait then you add an eventFd,
or similar, that you signal to wake the thread to exit.  And that is why
libgpiod exposes the fd so the user can build their own ppoll should
they want to do that.

Cheers,
Kent.
Bartosz Golaszewski July 1, 2022, 11:52 a.m. UTC | #3
On Fri, Jul 1, 2022 at 1:10 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> On Fri, Jul 1, 2022 at 1:06 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > All polling system calls have some way of being instructed to block
> > indefinitely until some event is registered on the file descriptor.
> >
> > Make both the gpiod_chip_wait_info_event() and
> > gpiod_line_request_wait_edge_event() accept negative timeout values in
> > which case the underlying ppoll() will block indefinitely.
>
> Long time no user space done by me, so here my silly question: how to
> kill a task that is blocking indefinitely in ppoll()?
>

Send a signal to it. It will return -1 and set errno to EINTR. Unless
you explicitly masked all signals. In that case kill -9 still works.
:)

Bart
diff mbox series

Patch

diff --git a/include/gpiod.h b/include/gpiod.h
index 5595ff2..d8b5f39 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -135,11 +135,14 @@  int gpiod_chip_get_fd(struct gpiod_chip *chip);
  * @brief Wait for line status change events on any of the watched lines
  *	  on the chip.
  * @param chip GPIO chip object.
- * @param timeout_ns Wait time limit in nanoseconds.
+ * @param timeout_ns Wait time limit in nanoseconds. If set to 0, the function
+ *		     returns immediatelly. If set to a negative number, the
+ *		     function blocks indefinitely until an event becomes
+ *		     available.
  * @return 0 if wait timed out, -1 if an error occurred, 1 if an event is
  *	   pending.
  */
-int gpiod_chip_wait_info_event(struct gpiod_chip *chip, uint64_t timeout_ns);
+int gpiod_chip_wait_info_event(struct gpiod_chip *chip, int64_t timeout_ns);
 
 /**
  * @brief Read a single line status change event from the chip.
@@ -1320,7 +1323,10 @@  int gpiod_line_request_get_fd(struct gpiod_line_request *request);
 /**
  * @brief Wait for edge events on any of the requested lines.
  * @param request GPIO line request.
- * @param timeout_ns Wait time limit in nanoseconds.
+ * @param timeout_ns Wait time limit in nanoseconds. If set to 0, the function
+ *		     returns immediatelly. If set to a negative number, the
+ *		     function blocks indefinitely until an event becomes
+ *		     available.
  * @return 0 if wait timed out, -1 if an error occurred, 1 if an event is
  *	   pending.
  *q
@@ -1328,7 +1334,7 @@  int gpiod_line_request_get_fd(struct gpiod_line_request *request);
  * By default edge detection is disabled.
  */
 int gpiod_line_request_wait_edge_event(struct gpiod_line_request *request,
-				       uint64_t timeout_ns);
+				       int64_t timeout_ns);
 
 /**
  * @brief Read a number of edge events from a line request.
diff --git a/lib/chip.c b/lib/chip.c
index fc3dda2..038d3dd 100644
--- a/lib/chip.c
+++ b/lib/chip.c
@@ -145,7 +145,7 @@  GPIOD_API int gpiod_chip_get_fd(struct gpiod_chip *chip)
 }
 
 GPIOD_API int gpiod_chip_wait_info_event(struct gpiod_chip *chip,
-					 uint64_t timeout_ns)
+					 int64_t timeout_ns)
 {
 	return gpiod_poll_fd(chip->fd, timeout_ns);
 }
diff --git a/lib/internal.c b/lib/internal.c
index b7da67e..d948814 100644
--- a/lib/internal.c
+++ b/lib/internal.c
@@ -7,7 +7,7 @@ 
 
 #include "internal.h"
 
-int gpiod_poll_fd(int fd, uint64_t timeout_ns)
+int gpiod_poll_fd(int fd, int64_t timeout_ns)
 {
 	struct timespec ts;
 	struct pollfd pfd;
@@ -17,10 +17,12 @@  int gpiod_poll_fd(int fd, uint64_t timeout_ns)
 	pfd.fd = fd;
 	pfd.events = POLLIN | POLLPRI;
 
-	ts.tv_sec = timeout_ns / 1000000000ULL;
-	ts.tv_nsec = timeout_ns % 1000000000ULL;
+	if (timeout_ns >= 0) {
+		ts.tv_sec = timeout_ns / 1000000000ULL;
+		ts.tv_nsec = timeout_ns % 1000000000ULL;
+	}
 
-	ret = ppoll(&pfd, 1, &ts, NULL);
+	ret = ppoll(&pfd, 1, timeout_ns < 0 ? NULL : &ts, NULL);
 	if (ret < 0)
 		return -1;
 	else if (ret == 0)
diff --git a/lib/internal.h b/lib/internal.h
index c87df91..fab12c3 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -36,7 +36,7 @@  struct gpiod_info_event *
 gpiod_info_event_from_uapi(struct gpio_v2_line_info_changed *uapi_evt);
 struct gpiod_info_event *gpiod_info_event_read_fd(int fd);
 
-int gpiod_poll_fd(int fd, uint64_t timeout);
+int gpiod_poll_fd(int fd, int64_t timeout);
 
 void gpiod_line_mask_zero(uint64_t *mask);
 void gpiod_line_mask_fill(uint64_t *mask);
diff --git a/lib/line-request.c b/lib/line-request.c
index 33f7f67..04bd78d 100644
--- a/lib/line-request.c
+++ b/lib/line-request.c
@@ -200,7 +200,7 @@  GPIOD_API int gpiod_line_request_get_fd(struct gpiod_line_request *request)
 
 GPIOD_API int
 gpiod_line_request_wait_edge_event(struct gpiod_line_request *request,
-				   uint64_t timeout_ns)
+				   int64_t timeout_ns)
 {
 	return gpiod_poll_fd(request->fd, timeout_ns);
 }