[PATCH] pps: fix poll support

Denis OSTERLAND-HEIM posted 1 patch 1 year ago
There is a newer version of this series
drivers/pps/pps.c          | 11 +++++++++--
include/linux/pps_kernel.h |  1 +
2 files changed, 10 insertions(+), 2 deletions(-)
[PATCH] pps: fix poll support
Posted by Denis OSTERLAND-HEIM 1 year ago
[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.

Signed-off-by: Denis OSTERLAND-HEIM <denis.osterland@diehl.com>
Co-developed-by: Rodolfo Giometti <giometti@enneenne.com>
Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
Fixes: eae9d2ba0cfc ("LinuxPPS: core support")
CC: stable@vger.linux.org # 5.4+
---
 drivers/pps/pps.c          | 11 +++++++++--
 include/linux/pps_kernel.h |  1 +
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 6a02245ea35f..9463232af8d2 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -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;
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index c7abce28ed29..aab0aebb529e 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -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 */
-- 
2.47.2
Re: [PATCH] pps: fix poll support
Posted by Rodolfo Giometti 1 year ago
On 03/03/25 09:02, Denis OSTERLAND-HEIM wrote:
> [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.
> 
> Signed-off-by: Denis OSTERLAND-HEIM <denis.osterland@diehl.com>
> Co-developed-by: Rodolfo Giometti <giometti@enneenne.com>
> Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>

Acked-by: Rodolfo Giometti <giometti@enneenne.com>

If needed. :)

> Fixes: eae9d2ba0cfc ("LinuxPPS: core support")
> CC: stable@vger.linux.org # 5.4+
> ---
>   drivers/pps/pps.c          | 11 +++++++++--
>   include/linux/pps_kernel.h |  1 +
>   2 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
> index 6a02245ea35f..9463232af8d2 100644
> --- a/drivers/pps/pps.c
> +++ b/drivers/pps/pps.c
> @@ -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;
> diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
> index c7abce28ed29..aab0aebb529e 100644
> --- a/include/linux/pps_kernel.h
> +++ b/include/linux/pps_kernel.h
> @@ -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 */

-- 
GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming