Skip to content

Commit

Permalink
ptp4l: Use poll() instead of a try-again loop
Browse files Browse the repository at this point in the history
This patch modifies sk_receive in order to use poll() on POLLERR instead of the
tryagain loop as this resolves issues with drivers who do not return timestamps
quickly enough. It also resolves the issue of wasting time repeating every
microsecond. It lets the kernel sleep our application until the data or timeout arrives.

This change also replaces the old tx_timestamp_retries config value with
tx_timestamp_timeout specified in milliseconds (the smallest length of time poll
accepts). This does have the side effect of increasing the minimum delay before
missing a timestamp by up to 1ms, but the poll should return sooner in the
normal case where a packet timestamp was not dropped.

This change vastly improves some devices and cleans the code up by simplifying a
race condition window due to drivers returning tx timestamp on the error queue.

[ RC - removed the unused 'try_again' variable. ]

Signed-off-by: Jacob Keller <[email protected]>
  • Loading branch information
jacob-keller authored and richardcochran committed Apr 5, 2013
1 parent 2ec3829 commit 76e10e9
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 34 deletions.
4 changes: 2 additions & 2 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,10 @@ static enum parser_result parse_global_setting(const char *option,
return BAD_VALUE;
*cfg->assume_two_step = val ? 1 : 0;

} else if (!strcmp(option, "tx_timestamp_retries")) {
} else if (!strcmp(option, "tx_timestamp_timeout")) {
if (1 != sscanf(value, "%u", &val) || !(val > 0))
return BAD_VALUE;
*cfg->tx_timestamp_retries = val;
*cfg->tx_timestamp_timeout = val;

} else if (!strcmp(option, "pi_proportional_const")) {
if (1 != sscanf(value, "%lf", &df) || !(df >= 0.0 && df < 1.0))
Expand Down
2 changes: 1 addition & 1 deletion config.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct config {
struct default_ds dds;
struct port_defaults pod;
int *assume_two_step;
int *tx_timestamp_retries;
int *tx_timestamp_timeout;

enum servo_type clock_servo;

Expand Down
2 changes: 1 addition & 1 deletion default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ assume_two_step 0
logging_level 6
path_trace_enabled 0
follow_up_info 0
tx_timestamp_retries 100
tx_timestamp_timeout 1
use_syslog 1
verbose 0
summary_interval 0
Expand Down
2 changes: 1 addition & 1 deletion gPTP.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ assume_two_step 1
logging_level 6
path_trace_enabled 1
follow_up_info 1
tx_timestamp_retries 100
tx_timestamp_timeout 1
use_syslog 1
verbose 0
summary_interval 0
Expand Down
8 changes: 4 additions & 4 deletions ptp4l.8
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,10 @@ Treat one-step responses as two-step if enabled. It is used to work around
buggy 802.1AS switches.
The default is 0 (disabled).
.TP
.B tx_timestamp_retries
The number of retries to fetch the tx time stamp from the kernel when a message
is sent.
The default is 100.
.B tx_timestamp_timeout
The number of milliseconds to poll waiting for the tx time stamp from the kernel
when a message has recently been sent.
The default is 1.
.TP
.B clock_servo
The servo which is used to synchronize the local clock. Currently only one
Expand Down
2 changes: 1 addition & 1 deletion ptp4l.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ static struct config cfg_settings = {
.transport = TRANS_UDP_IPV4,

.assume_two_step = &assume_two_step,
.tx_timestamp_retries = &sk_tx_retries,
.tx_timestamp_timeout = &sk_tx_timeout,

.clock_servo = CLOCK_SERVO_PI,

Expand Down
37 changes: 16 additions & 21 deletions sk.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@
#include <unistd.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <poll.h>

#include "print.h"
#include "sk.h"

/* globals */

int sk_tx_retries = 100;
int sk_tx_timeout = 1;

/* private methods */

Expand Down Expand Up @@ -200,7 +201,7 @@ int sk_receive(int fd, void *buf, int buflen,
struct hw_timestamp *hwts, int flags)
{
char control[256];
int cnt = 0, level, try_again, type;
int cnt = 0, res = 0, level, type;
struct cmsghdr *cm;
struct iovec iov = { buf, buflen };
struct msghdr msg;
Expand All @@ -213,28 +214,22 @@ int sk_receive(int fd, void *buf, int buflen,
msg.msg_control = control;
msg.msg_controllen = sizeof(control);

try_again = flags == MSG_ERRQUEUE ? sk_tx_retries : 1;

for ( ; try_again; try_again--) {
cnt = recvmsg(fd, &msg, flags);
if (cnt >= 0) {
break;
}
if (errno == EINTR) {
try_again++;
} else if (errno == EAGAIN) {
usleep(1);
} else {
break;
if (flags == MSG_ERRQUEUE) {
struct pollfd pfd = { fd, 0, 0 };
res = poll(&pfd, 1, sk_tx_timeout);
if (res < 1) {
pr_err("poll tx timestamp failed: %m");
return res;
} else if (!(pfd.revents & POLLERR)) {
pr_err("poll tx woke up on non ERR event");
return -1;
}
}

if (cnt < 1) {
if (flags == MSG_ERRQUEUE)
pr_err("recvmsg tx timestamp failed: %m");
else
pr_err("recvmsg failed: %m");
}
cnt = recvmsg(fd, &msg, flags);
if (cnt < 1)
pr_err("recvmsg%sfailed: %m",
flags == MSG_ERRQUEUE ? " tx timestamp " : " ");

for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
level = cm->cmsg_level;
Expand Down
6 changes: 3 additions & 3 deletions sk.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
enum transport_type transport);

/**
* Limits the number of RECVMSG(2) calls when attempting to obtain a
* transmit time stamp on an event message.
* Limits the time that RECVMSG(2) will poll while waiting for the tx timestamp
* if MSG_ERRQUEUE is set. Specified in milliseconds.
*/
extern int sk_tx_retries;
extern int sk_tx_timeout;

#endif

0 comments on commit 76e10e9

Please sign in to comment.