2

我正在编写一个 CAN 记录器程序。我记录数据的方式类似于candump调用时 -tool的candump方式candump anyhttps ://github.com/linux-can/can-utils/blob/master/candump.c

candump anycandump绑定到任何设备,即它addr.can_ifindex = 0;用于recvmsg获取 CAN 帧,然后它获取struct msghdr msg;附加时间戳以将其写入日志文件或屏幕上。

我的问题是,内核是否确保以下assert内容始终有效?

struct msghdr msg;
// init stuff
// ...
s[0] = _skt_1; // can0
s[1] = _skt_2; // can1
// configure and bind sockets
// ...
select(s[1]+1, &rdfs, NULL, NULL, NULL));
recvmsg(s[0], &msg, 0); // https://linux.die.net/man/2/recvmsg
timestamp_1 = getTimestamp(msg);
recvmsg(s[1], &msg, 0); // https://linux.die.net/man/2/recvmsg
timestamp_2 = getTimestamp(msg);
// Always valid?
assert(timestamp_1 < timestamp_2);

对 SocketCAN 驱动程序中的源代码位置的提示也会有所帮助。

4

2 回答 2

2

简短的回答是肯定的,除非你的司机做了一些很奇怪的事情。CAN 使用与其他网络设备相同的 netif 子系统。SKB 有几种方法可以获取时间戳。

硬件时间戳:

如果您的驱动程序使用硬件时间戳,则时间戳基于硬件提供的任何内容。

软件时间戳:

如果启用了netdev_tstamp_prequeue,那么在您的驱动程序将 skb 提交给 netif_receive_skb 后不久就会有一个时间戳

https://elixir.bootlin.com/linux/v4.14.202/source/net/core/dev.c#L4554

如果netdev_tstamp_prequeue未启用,则在更多处理后应用时间戳,但仍在同一个 NAPI 接收线程中。

https://elixir.bootlin.com/linux/v4.14.202/source/net/core/dev.c#L4352

这是模糊的部分:

有一些特殊模式(RSP/RFP)允许内核使用 SMP 对 skb 处理进行负载平衡。内核不是在 napi 接收线程中处理 skb,而是将 skb 放入每个 cpu 队列中。现在,如果netdev_tstamp_prequeue未启用,则时间戳会在一段时间后从 per cpu 队列中退出时添加。但是,文档说接收顺序没有修改,因此时间戳也应该保持顺序。

于 2020-10-23T18:14:14.303 回答
0

我想在@user14508498 的答案中添加一些内容。

我终于做了一些测量。如果我将中断固定到不同的 CPU(例如 CAN0 到 CPU0 和 CAN1 到 CPU1),candump确实会以非时间顺序接收一些 CAN 帧,即上述断言在这种特定情况下并不总是正确的。至少在我的系统上的数量级约为 1-2 微秒。当两个中断都固定在同一个处理器上时,我无法观察到相同的情况。

于 2020-11-03T14:22:24.373 回答