Skip to contentSkip to conversation

pps: fix poll support

PATCH In review Denis OSTERLAND-HEIM 2 participants 2 messages Mar 3, 2025

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pps: fix poll support

[BUG]
A user space program that calls select/poll get always an immediate data ready-to-read response. As a result the intended use to wait until next data becomes ready does not work.

User space snippet:

    struct pollfd pollfd = {
      .fd = open("/dev/pps0", O_RDONLY),
      .events = POLLIN|POLLERR,
      .revents = 0 };
    while(1) {
      poll(&pollfd, 1, 2000/*ms*/); // returns immediate, but should wait
      if(revents & EPOLLIN) { // always true
        struct pps_fdata fdata;
        memset(&fdata, 0, sizeof(memdata));
        ioctl(PPS_FETCH, &fdata); // currently fetches data at max speed
      }
    }

[CAUSE]
pps_cdev_poll() returns unconditionally EPOLLIN.

[FIX]
Remember the last fetch event counter and compare this value in pps_cdev_poll() with most recent event counter
and return 0 if they are equal.

Fixes eae9d2ba0cfc ("LinuxPPS: core support")
---
 drivers/pps/pps.c          | 11 +++++++++--
 include/linux/pps_kernel.h |  1 +
 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/pps/pps.c +9 -2
index 6a02245ea35f..9463232af8d2 100644
@@ -41,6 +41,9 @@ static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
 
 	poll_wait(file, &pps->queue, wait);
 
+	if (pps->last_fetched_ev == pps->last_ev)
+		return 0;
+
 	return EPOLLIN | EPOLLRDNORM;
 }
 
@@ -186,9 +189,11 @@ static long pps_cdev_ioctl(struct file *file,
 		if (err)
 			return err;
 
-		/* Return the fetched timestamp */
+		/* Return the fetched timestamp and save last fetched event  */
 		spin_lock_irq(&pps->lock);
 
+		pps->last_fetched_ev = pps->last_ev;
+
 		fdata.info.assert_sequence = pps->assert_sequence;
 		fdata.info.clear_sequence = pps->clear_sequence;
 		fdata.info.assert_tu = pps->assert_tu;
@@ -272,9 +277,11 @@ static long pps_cdev_compat_ioctl(struct file *file,
 		if (err)
 			return err;
 
-		/* Return the fetched timestamp */
+		/* Return the fetched timestamp and save last fetched event  */
 		spin_lock_irq(&pps->lock);
 
+		pps->last_fetched_ev = pps->last_ev;
+
 		compat.info.assert_sequence = pps->assert_sequence;
 		compat.info.clear_sequence = pps->clear_sequence;
 		compat.info.current_mode = pps->current_mode;
include/linux/pps_kernel.h +1 -0
index c7abce28ed29..aab0aebb529e 100644
@@ -52,6 +52,7 @@ struct pps_device {
 	int current_mode;			/* PPS mode at event time */
 
 	unsigned int last_ev;			/* last PPS event id */
+	unsigned int last_fetched_ev;		/* last fetched PPS event id */
 	wait_queue_head_t queue;		/* PPS event queue */
 
 	unsigned int id;			/* PPS source unique ID */
Signature · 1 line
2.47.2
maintainer Acked-by on v1 1/1
#1 lore raw
Quoted 23 lines · Denis OSTERLAND-HEIM

[BUG]
A user space program that calls select/poll get always an immediate data ready-to-read response. As a result the intended use to wait until next data becomes ready does not work.

User space snippet:

     struct pollfd pollfd = {
       .fd = open("/dev/pps0", O_RDONLY),
       .events = POLLIN|POLLERR,
       .revents = 0 };
     while(1) {
       poll(&pollfd, 1, 2000/*ms*/); // returns immediate, but should wait
       if(revents & EPOLLIN) { // always true
         struct pps_fdata fdata;
         memset(&fdata, 0, sizeof(memdata));
         ioctl(PPS_FETCH, &fdata); // currently fetches data at max speed
       }
     }

[CAUSE]
pps_cdev_poll() returns unconditionally EPOLLIN.

Quoted 8 lines

[FIX]
Remember the last fetch event counter and compare this value in pps_cdev_poll() with most recent event counter
and return 0 if they are equal.

If needed. :)

Quoted 59 lines
Fixes eae9d2ba0cfc ("LinuxPPS: core support")
---
  drivers/pps/pps.c          | 11 +++++++++--
  include/linux/pps_kernel.h |  1 +
  2 files changed, 10 insertions(+), 2 deletions(-)
drivers/pps/pps.c +9 -2
index 6a02245ea35f..9463232af8d2 100644
@@ -41,6 +41,9 @@ static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
 
  	poll_wait(file, &pps->queue, wait);
 
+	if (pps->last_fetched_ev == pps->last_ev)
+		return 0;
+
  	return EPOLLIN | EPOLLRDNORM;
  }
 
@@ -186,9 +189,11 @@ static long pps_cdev_ioctl(struct file *file,
  		if (err)
  			return err;
 
-		/* Return the fetched timestamp */
+		/* Return the fetched timestamp and save last fetched event  */
  		spin_lock_irq(&pps->lock);
 
+		pps->last_fetched_ev = pps->last_ev;
+
  		fdata.info.assert_sequence = pps->assert_sequence;
  		fdata.info.clear_sequence = pps->clear_sequence;
  		fdata.info.assert_tu = pps->assert_tu;
@@ -272,9 +277,11 @@ static long pps_cdev_compat_ioctl(struct file *file,
  		if (err)
  			return err;
 
-		/* Return the fetched timestamp */
+		/* Return the fetched timestamp and save last fetched event  */
  		spin_lock_irq(&pps->lock);
 
+		pps->last_fetched_ev = pps->last_ev;
+
  		compat.info.assert_sequence = pps->assert_sequence;
  		compat.info.clear_sequence = pps->clear_sequence;
  		compat.info.current_mode = pps->current_mode;
include/linux/pps_kernel.h +1 -0
index c7abce28ed29..aab0aebb529e 100644
@@ -52,6 +52,7 @@ struct pps_device {
  	int current_mode;			/* PPS mode at event time */
 
  	unsigned int last_ev;			/* last PPS event id */
+	unsigned int last_fetched_ev;		/* last fetched PPS event id */
  	wait_queue_head_t queue;		/* PPS event queue */
 
  	unsigned int id;			/* PPS source unique ID */
Signature · 4 lines
GNU/Linux Solutions                  e-mail: [email protected]
Linux Device Driver                          [email protected]
Embedded Systems                     phone:  +39 349 2432127
UNIX programming