Skip to content

Commit

Permalink
New list implementation.
Browse files Browse the repository at this point in the history
This replaces the five-year-old lilos::list module with a new
implementation derived from my "lilist" sketch. Compared to the
original, the new list has the following advantages:

- Its implementation is shorter.
- Its API is simpler.
- It no longer requires two-phase init, and so things using it _also_
  don't require two-phase init.
- It can be tested under Miri to catch pointer abuses.
- It's exposed as a separate crate, which means I can update it without
  having to rev the OS.
  • Loading branch information
cbiffle committed May 4, 2024
1 parent e130f5a commit b5f2703
Show file tree
Hide file tree
Showing 25 changed files with 1,174 additions and 361 deletions.
17 changes: 14 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
resolver = "2"
members = [
"list",
"os",
"handoff",
"semaphore",
Expand All @@ -23,6 +24,7 @@ rust-version = "1.69"
[workspace.dependencies]
# Internal
lilos = { path = "os", version = "1.1.0", default-features = false }
lilos-list = { path = "list", version = "0.1.0" }
lilos-testsuite = { path = "testsuite" }
lilos-handoff = { path = "handoff" }
lilos-semaphore = { path = "semaphore" }
Expand Down
2 changes: 1 addition & 1 deletion README.mkdn
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

This is a wee operating system written to support the `async` style of
programming in Rust on microcontrollers. It fits in about 2 kiB of Flash and
uses about 20 bytes of RAM (before your tasks are added). In that space, you get
uses about 40 bytes of RAM (before your tasks are added). In that space, you get
a full `async` runtime with multiple tasks, support for complex concurrency via
`join` and `select`, and a lot of convenient but simple APIs. (If you want to
see what a `lilos` program looks like, look in the `examples` directory, or read
Expand Down
46 changes: 41 additions & 5 deletions RELEASE-NOTES.mkdn
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
# Release Notes

## Version 1.1.1 (in progress)
## Version 1.2.0 (in progress)

Internal changes to data structures mean the OS minimum RAM requirement is down
by 1/3 (from 60 bytes to 40), and programs I've tested are at least 100 bytes
smaller in flash.

### Core API changes

- The original `list` module, and the `List` and `Node` types it contained, are
now deprecated. The new `lilos-list` crate provides a dramatically improved
version. In particular, this eliminates the need for the "two-phase init"
dance with pinned OS types that has haunted `lilos` from the early days.
- Uses of the old `List` type should use the new one from `lilos-list`.
- Instead of using macros to create a list, write: `pin!(List::new())`.
- The `Node` type is now private. Instead, the "contents" field that used to
be passed to `create_node!` is now a parameter to the `List::wait` function.

- Two-phase init of `Mutex` is now deprecated. You can now just write
`pin!(Mutex::create(something))`. (It's `create` and not `new` because I'm
preserving `new` in deprecated form for backwards compatibility with 1.1.) The
mutex creation macros still work.

- It is now possible to create a `Mutex` or `List` in a `const fn` context,
including in a static initializer.

### Non-Core API

- The `lilos-list` crate exists now.

- `rwlock` 0.2 uses the new `lilos-list` internally, and no longer requires (or
supports) two-phase init. I've removed the creation macro.

- `semaphore` 0.2 uses the new `lilos-list` internally, and no longer requires (or
supports) two-phase init. I've removed the creation macro here, too.

### Internal improvements

- All code using lists, particularly timer lists, should now be slightly
smaller.
- All internal use of lists has been rewritten to use `waitlist`.

- All code using any kind of lists, particularly timer lists, should now be
slightly smaller.

- Removed an internal unused `Waker` implementation, reducing the base flash
requirement of the OS.
- Removed an internal mostly-unused `Waker` implementation, reducing the base
flash requirement of the OS for applications that use the new `waitlist`
module.

- `spsc` now uses `get_unchecked` in a couple of places to avoid generating
bounds checks. This is the first place in `lilos` where I've used unsafe code
Expand Down
2 changes: 1 addition & 1 deletion build-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ for k in ${!MODES[@]}; do
popd > /dev/null
done

DIRS="handoff semaphore rwlock testsuite/stm32f4 testsuite/stm32g0 testsuite/stm32f3 testsuite/lm3s6965 examples/*/*/"
DIRS="handoff semaphore rwlock list testsuite/stm32f4 testsuite/stm32g0 testsuite/stm32f3 testsuite/lm3s6965 examples/*/*/"

for d in $DIRS; do
if [[ $d == *memory.x ]]; then
Expand Down
2 changes: 1 addition & 1 deletion clippy-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -euo pipefail

DIRS="os handoff semaphore rwlock testsuite/stm32f4 testsuite/stm32g0 testsuite/stm32f3 examples/*/*/"
DIRS="os list handoff semaphore rwlock testsuite/stm32f4 testsuite/stm32g0 testsuite/stm32f3 examples/*/*/"

for d in $DIRS; do
echo "---- clipping in $d"
Expand Down
16 changes: 16 additions & 0 deletions list/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "lilos-list"
version = "0.1.0"
authors = ["Cliff L. Biffle <code@cliffle.com>"]
description = "Allocation-free intrusive doubly-linked wait queues for lilos."
keywords = ["async", "embedded", "os"]
categories = ["embedded", "no-std"]
readme = "README.mkdn"

edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
pin-project.workspace = true
23 changes: 23 additions & 0 deletions list/README.mkdn
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Allocation-free doubly-linked intrusive lists

This is the list type used to implement timer lists and wait queues in
[`lilos`]. It takes an unusual approach to implementing a sound doubly-linked
intrusive list in Rust without allocation, which is otherwise quite difficult:
it presents a different API that's easier to make sound.

This data structure can be built for any platform, and has tests that can run
both hosted and under Miri (to check for pointer abuses).

See the rustdoc for more details.

## Versioning

It's not important for applications or custom synchronization primitives to use
_exactly_ the same version of `lilos-list` as `lilos` does internally. Having
multiple versions linked into a single binary will work fine. (However, it will
take somewhat less space in flash if you can arrange to use the same version.)

`lilos-list` is versioned separately from the OS API and will likely go through
major versions faster than the rest of the OS.

[`lilos`]: https://docs.rs/lilos/latest/lilos/
Loading

0 comments on commit b5f2703

Please sign in to comment.