Hi,
Thanks for the fast answer.
-----Original Message-----
From: Rodolfo Giometti <giometti@xxxxxxxxxxxx>
Sent: Thursday, February 20, 2025 9:51 AM
To: Denis OSTERLAND-HEIM <denis.osterland@xxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
Subject: [EXT] Re: [PATCH] pps: add epoll support
Can you explain it a bit better?I will do my best.
In an application, that has more to do than just dealing with one PPS device,
to use PPS_FETCH with a timeout until next event, you need a thread which can sleep.
I would really like to avoid threads and the resulting synchronization complexity.
Alternative is to fetch the current assert value in at least twice the expected fequency.
This would definetly work, but epoll is the more efficent way to do.
Without epoll in one thread:
```c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/pps.h>
struct per_pps {
int dev_fd;
struct pps_fdata fdata;
unsigned int last_assert;
};
int main(int argc, const char* argv[]) {
int ret = 0;
struct per_pps instances[] = {
{ .dev_fd = open((argc > 1) ? argv[1] : "/dev/pps0", O_RDONLY) },
{ .dev_fd = open((argc > 2) ? argv[2] : "/dev/pps1", O_RDONLY) }
};
if (instances[0].dev_fd < 0 || instances[1].dev_fd < 0) {
perror("failed to open dev");
ret = 1;
goto out;
}
for (int loops = 10; --loops;) {
for (int i = 0; i < 2; ++i) {
if (ioctl(instances[i].dev_fd, PPS_FETCH, &instances[i].fdata) < 0) {
perror("failed to fetch data");
ret = 1;
goto out;
}
if (instances[i].last_assert != instances[i].fdata.info.assert_sequence) {
instances[i].last_assert = instances[i].fdata.info.assert_sequence;
printf(
"assert: %u\ntime: %lld.%09d\n",
instances[i].fdata.info.assert_sequence,
instances[i].fdata.info.assert_tu.sec,
instances[i].fdata.info.assert_tu.nsec
);
}
}
usleep(300000);
}
out:
if (instances[0].dev_fd >= 0)
close(instances[0].dev_fd);
if (instances[1].dev_fd >= 0)
close(instances[1].dev_fd);
return ret;
}
```
Syscalls are pretty expensive and epoll allows use to reduce them.
```c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/pps.h>
#include <poll.h>
int main(int argc, const char* argv[]) {
int ret = 0;
struct pollfd instances[] = {
{ .fd = open((argc > 1) ? argv[1] : "/dev/pps0", O_RDONLY), .events = POLLIN|POLLERR , .revents = 0 },
{ .fd = open((argc > 2) ? argv[2] : "/dev/pps1", O_RDONLY), .events = POLLIN|POLLERR , .revents = 0 }
};
if (instances[0].fd < 0 || instances[1].fd < 0) {
perror("failed to open dev");
ret = 1;
goto out;
}
for (int loops = 4; --loops;) {
if(poll(instances, 2, 2000/*ms*/)) {
struct pps_fdata fdata;
for (int i = 0; i < 2; ++i) {
if ((instances[i].revents & POLLIN) != POLLIN)
continue;
if (ioctl(instances[i].fd, PPS_FETCH, &fdata) < 0) {
perror("failed to fetch data");
ret = 1;
goto out;
}
printf(
"assert: %u\ntime: %lld.%09d\n",
fdata.info.assert_sequence,
fdata.info.assert_tu.sec,
fdata.info.assert_tu.nsec
);
}
} else {
printf("time-out\n");
}
}
out:
if (instances[0].fd >= 0)
close(instances[0].fd);
if (instances[1].fd >= 0)
close(instances[1].fd);
return ret;
}
```
RFC2783 states that to access to PPS timestamps we should use theTo me RFC reads like the spcification of pps-tools/timepps.h and not the one for the char device.
time_pps_fetch() function, where we may read:
3.4.3 New functions: access to PPS timestamps
The API includes one function that gives applications access to PPS
timestamps. As an implementation option, the application may request
the API to block until the next timestamp is captured. (The API does
not directly support the use of the select() or poll() system calls
to wait for PPS events.)
How do you think to use this new select()/poll() support without breaking the
RFC2783 compliance?
3.4.1 New functions: obtaining PPS sources
...
The definition of what special files are appropriate for use with the
PPS API is outside the scope of this specification, and may vary
based on both operating system implementation, and local system
configuration.
To me "The API does not directly support the use of the select() or poll() system calls" simply means:
there is no wrapper function that calls select() or poll() for you
I do not see why an additional function of the underlying character device would break the API.
You may just do not use it and everything works like before.
But I see your point.
If the char dev interface is ment to be the RFC interface only, there is no need to support epoll.
Maybe it would be better to add epoll support to sysfs assert/clear?