I’m happy to announce Release 0.3.0 of the little operating system that can, sometimes, but quite often randomly can’t. Yes, there are heisenbugs, but this release is too big not to get out of the door.
The biggest new feature is pre-emptive multithreading. Yes, we can now use the ‘default’ event-oriented model of previous releases, or a threaded model - or indeed combine the both (as we do in the updated example program).
In this release we have a scheduler for multithreading, with
optional thread preemption if you nominate a suitably configured timer
interrupt with a feature flag like pmt_tcb0_int
in your config.toml
-
see the Rustdocs for further details - and a familiar interface for
creating threads with avr_oxide::thread::spawn()
and avr_oxide::thread::Builder
.
To make this useful of course you need some thread synchronisation primitives;
they’re provided in the avr_oxide::sync
module with simple Mutex
,
EventWait
and Arc
implementations.
Oh, and of course all our high-level device drivers (including clocks, serial ports and buttons) now have blocking APIs that make use of our threading, in addition to the existing event-loop based APIs.
Other changes
Other changes include a focus on reducing the amount of memory used, both
text
and data
segments. I’ve restructured the way the HAL exposes
processor devices/pins to reduce memory use, and at the same time we now have
board compatibility modules for boards other than Arduino devices - in
particular, for ATmega XPlained evaluation boards - so you can easily code
for these boards with things like onboard serial ports and hardware buttons
accessed by aliases.
Memory management is also improved; instead of having to specify ‘small’, ‘medium’ or ’large’ memory model to size the heap, the heap will now automatically be sized to use all available memory. Now that we have multithreading, the stack size of every thread - including the main() thread - is of course now configurable as well.
Finally, there are also some tools for helping with debugging - error
conditions in the OS can be indicated by pulse-codes on a nominated debug
pin (which if you’ve enabled one of the board compatibility features will
default to that board’s debug LED,) as well as output to the nominated
panicout
serial port (along with a full thread dump.) See the
debug pin reference and
thread dump format posts for more information.
Full Changelog
- Well behaved blocking reads on serial ports, and options for buffered read-to-EOL and read-to-EOT
- Main thread stack size now configurable using an attribute on the
avr_oxide::main
macro. - Better stack-overflow detection to detect stack busts where the compiler
skips stack elements by modifying the SP directly, and also a new function
in the
avr_oxide::util::debug
module to print out details of all current threads to the configured panicout serial port (including stack usage) to help developers right-size their thread stack sizes. - Reduced size of code segment through refactoring Port implementation,
- And reduced stack use in interrupts/system calls.
- Now includes basic Mutex synchronisation primitive, and the various I/O routines have been updated to use thread yield/waits instead of spinlocking.
- Change the way we do Arduino-compatible pin naming to avoid creating huge objects on the stack.
- Pre-emptive multithreading
- Dynamic sizing of the heap to use all available memory, losing the
alloc_large
style feature flags - Reduced memory use for ports/pins (in particular to accomodate the ‘328p)
- Events scheduled with
after_delay()
now return a handle that can be used to cancel them before they run usingcancel_delay()
- MasterClock can now schedule delay events in the same way as WallClock