Rust in Everything
基于 embassy-executor 0.10.0

常见坑

每一章对着一个报错或一个现象:先用最小的程序复现,再到源码里找它从哪一行来,最后给出修法和检查办法。机制在前面几部分讲过的,这里只链过去。复现分三种环境,每章都写明是哪一种:

  • std:M2 Max、macOS 27、rustc 1.99.0;
  • QEMU:QEMU 11.1.2 b-l475e-iot01a,embassy-stm32 打了一行补丁;
  • 只交叉编译:thumbv7em-none-eabihf。

有几个坑是上游的问题,章里写明在哪个版本上复现、main 上修了没有。

  1. Undefined symbols: _embassy_time_now:用了 Timer 却没有时间驱动,加第一个 Timer 时才报。
  2. symbol _embassy_time_now is already defined:两个驱动;跨 crate 时 macOS 的链接器不报错,悄悄选一个。
  3. the name TICK_HZ is defined multiple times:两个 tick-hz-*;只有库选了一个时不报错,频率却变了。
  4. No architecture selected for embassy-executor:没开 platform-*,报错还在说已经改名的 arch-*。
  5. 开了 trace:Undefined symbols _embassy_trace*:trace 要求自己定义全部钩子,debug 和 release 缺的符号数不同。
  6. Busy - Too many instances of this task are already running:任务池满了,0.10.0 起在调用任务函数时就返回错误。
  7. SpawnToken instances may not be dropped:token 没交给 spawn;rustc 建议的 let _ = 照样 panic。
  8. #[task] 的报错:非 'static、泛型、impl Trait、17 个参数、省略的生命周期。
  9. 任务池比想的大:future 当参数传给 async fn 后翻倍。
  10. 一个任务忙等,其他任务全停:阻塞的 DelayNs、长计算,单执行器没有抢占。
  11. 几个任务等同一个 Channel / Signal 时 CPU 不睡:一个 waker 槽,互相挤掉、互相唤醒。
  12. *mut () cannot be shared between threads safely:NoopRawMutex 放进 static。
  13. 中断里用 Noop / ThreadMode:BorrowMutError、ThreadModeMutex can only be locked from thread mode。
  14. Found waker not created by the Embassy executor:Timer 在别的执行器或组合子里被 poll。
  15. 两个任务等一个 Signal,一个永远拿不到:Signal 只给一个人,要广播用 Watch。
  16. PubSub 收到 Lagged:publish_immediate 挤掉慢订阅者的消息。
  17. select / with_timeout 输了,读了一半的帧丢了:输家被 drop,读了一半的状态跟着丢。
  18. Ticker 阻塞之后连着 tick 好几次:每次只加一个周期;从 tokio interval 搬过来,第一次 tick 晚一个周期。
  19. 通用定时器队列满了:不报错,忙转:generic-queue-N 容量不够时提前唤醒,变成忙等。
  20. 忘了 / 绑错 bind_interrupts!:E0277;重复绑定是 symbol EXTI15_10 is already defined。
  21. 外设被吃掉之后:E0382 / E0499 / E0597;init called more than once!。
  22. the trait bound PA0: RxPin USART1 is not satisfied:引脚不能接这个外设,报错里列出可用的引脚。
  23. BufferedUart 第二次 write 卡住:0.6.0 丢唤醒,main 已修、未发版。
  24. adding a socket to a full SocketSet:StackResources<N> 要算上 DHCP、DNS。
  25. connect 一直不返回:对端不存在时只发 ARP;超时返回 ConnectionReset;drop 不发 FIN。
  26. Descriptor buffer full / control buffer too small:Builder 的几块缓冲区要算够,字符串描述符的检查差一个字节。
  27. packet-trace 加 log:[u8]: LowerHex is not satisfied:只有 defmt 能编,上游问题。
  28. there is no reactor running:在 embassy 任务里用 tokio 的类型。

按出在哪里分:

出在哪里坑
时间驱动与 feature1 没有驱动、2 两个驱动、3 tick-hz、4 平台、5 trace
任务与宏6 池满、7 token、8 宏报错、9 任务大小
调度与阻塞10 忙等、11 多个等待者、14 外来 waker、28 tokio
同步原语12 Noop 静态、13 中断里的锁、15 Signal、16 PubSub、17 select
定时器18 Ticker、19 通用队列
HAL20 中断绑定、21 外设所有权、22 引脚、23 BufferedUart
网络与 USB24 SocketSet、25 connect、26 USB 缓冲区、27 packet-trace
flowchart TB
  q{"碰到了什么"}
  q -->|链接失败| lk{"哪个符号"}
  lk -->|"_embassy_time_now"| p12["1 或 2"]
  lk -->|"__embassy_trace_*"| p5["5 trace"]
  lk -->|"EXTI15_10"| p20["20 中断绑定"]
  q -->|编译失败| cf{"哪一句"}
  cf -->|"TICK_HZ"| p3["3 tick-hz"]
  cf -->|"No architecture"| p4["4 平台"]
  cf -->|"task 宏"| p8["8 宏报错"]
  cf -->|"cannot be shared"| p12b["12 Noop"]
  cf -->|"E0277 Binding 或 Pin"| p2022["20 或 22"]
  cf -->|"E0382 E0499 E0597"| p21["21 外设"]
  cf -->|"LowerHex"| p27["27 packet-trace"]
  q -->|运行期 panic| pn{"原文"}
  pn -->|"Busy"| p6["6 池满"]
  pn -->|"SpawnToken"| p7["7 token"]
  pn -->|"BorrowMutError"| p13["13 中断里的锁"]
  pn -->|"Found waker"| p14["14 外来 waker"]
  pn -->|"full SocketSet"| p24["24 SocketSet"]
  pn -->|"buffer full"| p26["26 USB"]
  pn -->|"no reactor"| p28["28 tokio"]
  q -->|卡住或丢数据| st{"哪种"}
  st -->|"别的任务都停了"| p10["10 忙等"]
  st -->|"CPU 不睡"| p1119["11 或 19"]
  st -->|"有人收不到"| p1516["15 或 16"]
  st -->|"帧丢一半"| p17["17 select"]
  st -->|"连着 tick"| p18["18 Ticker"]
  st -->|"write 不返回"| p23["23 BufferedUart"]
  st -->|"connect 不返回"| p25["25 connect"]

💬 关联讨论

发起讨论
加载中...