This document describes several of the factors that constrain the design of libtock_core
.
Tock is designed to run on hardware with limited program storage and limited RAM. On Google's H1 chip, the Tock kernel and apps are limited to a 256 KiB flash region. The HiFive1 Rev B board has only 16 KiB of RAM.
Note that a Tock system may have multiple process binaries, each of which uses libtock_core
, so libtock_core
must minimize its size impact to the extent possible.
A process binary is generally stored in non-volatile memory and contains:
.crt0_header
section).text
section).rodata
section).data
section)A process' memory section is in RAM and contains:
.bss
section).data
section)libtock_core
developers should consider the space usage of their code, and where the space usage is (non-volatile memory or RAM). Important note: the .data
section consumes space in both non-volatile memory and RAM!
Most apps will not use all functionality in libtock_core
. The size impact of using libtock_core
in an app should be commensurate with the libtock_core
functionality that app uses. If done correctly, this will allow libtock_core
's users to build Tock systems with multiple small, single-purpose apps without excessive code duplication.
Programmatic tests are important to verify that new functionality works correctly and to keep existing functionality working through nontrivial refactorings. Different types of tests offer different capabilities:
libtock_core
code, as the code they test must run on both Tock and the host OS. These tests must either test code that does not directly use system calls, or must direct the system calls to a fake Tock kernel. These tests can be fast (compile and run in seconds), and can easily simulate a variety of failure modes (e.g. kernel errors) that may be difficult to generate with a real Tock kernel.libtock_core
's interaction with a real Tock kernel, albeit with limited hardware access.libtock_core
‘s functionality but also the Tock kernel’s interaction with the real hardware. However, automating these tests is difficult, and currently we do not have a way to run hardware tests in CI.If libtock_core
is functional on real hardware with a real kernel, it should be able to support emulation tests and hardware tests. However, host-based unit tests require more work. In its intended use case, libtock_core
is not supposed to be portable, supporting only the Tock kernel. Hoever, host-based unit tests are very valuable, both for rapid development and for testing error handling code. To support host-based tests, libtock_core
must be built out of portable pieces that can be unit tested, even though the library as a whole is not portable.
Testing pieces of libtock_core
against a fake kernel can be done using dependency injection, but most dependency injection techniques have considerable code size and RAM usage costs. libtock_core
needs either a dependency injection technique that has minimal size impact or an alternative mechanism for testing libtock_core
's system call error handling logic.
The general Rust ecosystem has converged on futures as its building block for interoperable asynchronous APIs, but futures have a size cost that makes them impractical for some use cases of libtock_core
. Although libtock_core
is still a work in progress (see issue 217), it will probably use an asynchronous API design based on the Asynchronous Components using Zero Sized Type Pointers exploration.
In order to interoperate with other libraries as well as the async
/await
functionality built in to Rust, we need libtock_core
to interface well with futures. In addition, there are several use cases of libtock_core
that consist primarily of synchronous code, so we need to be able to use libtock_core
's APIs in a synchronous manner.
The libtock-c
developers are already familiar with some of the complications that come up when synchronous code is interfaced to asynchronous code. For example, calling printf
-- an extremely common debugging tool -- causes callbacks to run in the background. This causes surprising and hard-to-debug reentrancy issues.
Some of users of libtock_core
intend to use it in applications that will undergo code audits for security certifications. To make this auditing practical, it is important to allow users to use libtock_core
without pulling in a large dependency tree.
As a general rule, a libtock_core
should avoid having required dependencies unless those dependencies are minimal (that is, avoiding the dependency would require reimplementing nearly all of it). Dependencies included in the Rust toolchain (such as the core
crate and its dependencies) are an exception, as they are a part of the language itself.
alloc
dependencyIt should be possible to use libtock_core
without bringing in the alloc
. Of course, it is fine for libtock_core
to offer a memory allocator as an optional feature.