如何在#[no_std] 环境中使用 Tokio Reactor?

How do I use Tokio Reactor in a #[no_std] environment?

我正在尝试在 Tock OS 嵌入式操作系统上实现期货。我正在尝试在 #[no_std] 环境中使用 Tokio

我的 Cargo.toml 文件如下所示:

[package]
name = "nrf52dk"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"

[profile.dev]
panic = "abort"
lto = true
opt-level = "z"
debug = true

[profile.release]
panic = "abort"
lto = true
opt-level = "z"
debug = true

[dependencies]
cortexm4 = { path = "../../arch/cortex-m4" }
capsules = { path = "../../capsules" }
kernel = { path = "../../kernel" }
nrf52 = { path = "../../chips/nrf52" }
nrf5x = { path = "../../chips/nrf5x" }
futures = {version = "0.2.0", default-features = false }

编译没有错误,但是当我添加 tokio-reactor = "0.1.1" 时,我收到错误:error[E0463]: can't find crate for std。我明白这是因为 Tokio 从 std 库中导入了一些东西。

是否可以解决这个问题?

据我所知,你不会。 Tokio Reactor 0.1.1 imports many things from the standard library,其中 none 有条件。

大部分导入可能会切换到 libcore 替代方案,但 Arc 需要内存分配,内存位于 alloc 板条箱中。

作为支持 no_std 的板条箱示例,请查看 Futures 0.1.20。这有一个功能标志,可以选择加入需要标准库的功能。

如果您希望这样做,您需要为 Tokio 及其所有依赖项做出大量努力,以添加功能标志以选择加入需要标准库的所有功能。值得向维护者提出一个问题来协调这样的工作。

扩展 Shepmaster 已经说过的话:你不想要 tokio;它基于 mio,这不太可能在内核中工作,尤其是在没有堆分配/标准的情况下。

那么如何在这样的环境中驱动任务(生成 Futures)(这是为 futures 0.1.x 系列编写的):

  • 您的 "Executor" ("main loop") 将希望跟踪每个任务的某些状态,例如你是否需要轮询它,也许一些链表来找到那些需要轮询的。
  • 你需要那个州的地方;您还需要存储包裹在 Spawn<...> 中的 Future。应该可以为此使用 "static" 分配的存储空间。
  • 你需要实现UnsafeNotify(和基本特征Notify),可能是为了一些原始指针/&'static对任务(包括状态)的引用; notify 需要能够对任务进行排队,以便以线程安全的方式进行轮询。 {clone,drop}_{raw,id} 函数可以为空,因为无论如何您都将使用静态分配。 notify 如果主循环正在休眠,还需要调度它。队列本身也需要一些全局状态("list head+tail");如果您需要不同的队列,您也可以在 NotifyHandle 中存储对它的引用(例如在 id: usize 参数中)。
  • 你甚至可以在同一个 "poll queue" 上尝试 运行 多个循环,祝它线程安全:) future-0.2 ThreadPool might give some ideas how to do that (or the tokio-threadpool crate).
  • 您可能需要向事件循环添加一些 "timer" 处理;一个定时器应该存储一个 NotifyHandle 到它应该在超时时唤醒的任务,一些状态来跟踪是否超时,并且事件循环需要一个活动(指向)定时器的列表来确定多长时间等待。 (tokio-timer crate 可能会给你一些关于如何实现它的想法)
  • 异步IO的一些类似处理;在用户空间中,您将使用 select 超时(或它的平台特定优化版本),在内核中,您可能必须找到其他方法:)(在 tokio 世界中,这是提供的由 Reactor,它基于 mio)
  • 完成您想要使用的任务poll_future_notify

在 futures-0.2 中 NotifyHandle 变成了 Waker, and UnsafeNotify became UnsafeWake; the id: usize context is gone (just use a struct with all the data you need to implement UnsafeWake for). Instead of storing Spawn<...> for a future you need to manually store a LocalMap for each task, which is then be used to create a Context with Context::without_spawn, which is then passed to Future::poll