Linux recvmsg 的 SocketCAN 行为
Linux SocketCAN behaviour of recvmsg
我正在编写一个 CAN 记录器程序。我记录数据的方式类似于 candump
-工具在调用 candump
时的方式,例如 candump any
:
https://github.com/linux-can/can-utils/blob/master/candump.c
candump any
使 candump
绑定到任何设备,即 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 驱动程序中源代码位置的提示也会有所帮助。
简短的回答是肯定的,除非你的 driver 做了一些非常奇怪的事情。 CAN 使用与其他网络设备相同的 netif 子系统。 SKB 获取时间戳的方法有几种。
硬件时间戳:
如果您的 driver 使用硬件时间戳,则时间戳基于硬件提供的任何内容。
软件时间戳:
如果启用了 netdev_tstamp_prequeue,那么在您的 driver 将 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 未启用,时间戳会在一段时间后从每个 cpu 队列中添加。但是,文档说接收顺序没有被修改,所以时间戳也应该保持顺序。
我想在@user14508498 的回答中添加一些内容。
我终于做了一些测量。如果我将中断固定到不同的 CPU(例如 CAN0 到 CPU0 和 CAN1 到 CPU1),candump
确实会按 non-chronical 顺序接收一些 CAN 帧,即上述断言在这种特定情况下并不总是正确的.至少在我的系统上,阶数的大小约为 1-2 微秒。当两个中断都固定到同一个处理器时,我无法观察到相同的结果。
我正在编写一个 CAN 记录器程序。我记录数据的方式类似于 candump
-工具在调用 candump
时的方式,例如 candump any
:
https://github.com/linux-can/can-utils/blob/master/candump.c
candump any
使 candump
绑定到任何设备,即 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 驱动程序中源代码位置的提示也会有所帮助。
简短的回答是肯定的,除非你的 driver 做了一些非常奇怪的事情。 CAN 使用与其他网络设备相同的 netif 子系统。 SKB 获取时间戳的方法有几种。
硬件时间戳:
如果您的 driver 使用硬件时间戳,则时间戳基于硬件提供的任何内容。
软件时间戳:
如果启用了 netdev_tstamp_prequeue,那么在您的 driver 将 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 未启用,时间戳会在一段时间后从每个 cpu 队列中添加。但是,文档说接收顺序没有被修改,所以时间戳也应该保持顺序。
我想在@user14508498 的回答中添加一些内容。
我终于做了一些测量。如果我将中断固定到不同的 CPU(例如 CAN0 到 CPU0 和 CAN1 到 CPU1),candump
确实会按 non-chronical 顺序接收一些 CAN 帧,即上述断言在这种特定情况下并不总是正确的.至少在我的系统上,阶数的大小约为 1-2 微秒。当两个中断都固定到同一个处理器时,我无法观察到相同的结果。