Musings

Goodbye threads, hello workers

The big picture in JeeH is still not right: I don’t like the way device drivers run in an exception-centric “handler” mode, whereas the rest of the application uses “thread” mode. This distinction was needed to provide atomic guards around certain parts of JeeH’s core data structures. This also affects the app-supplied lowestPower and resumePower functions, used to enter sleep modes “when there is no work”. It’s a bit odd that we need to be in a special mode when … idling!

...

Four ways to SPI

One of the problems I want to address in JeeH, is how to best interface with peripherals: built-in as well as connected via a common bus, e.g. I2C or SPI. There are two sides to this: talking to built-in hardware via device registers, and talking through built-in hardware to a connected module / chip.

Hardware register access #

Talking to the built-in hardware is a matter of reading and writing the hardware registers at specific addresses. This is already solved in JeeH with the use of IoReg<...> definitions. To configure the “B” port of the GPIO hardware in an STM32 for example, JeeH defines a GPIOB object (a constant type really) which can be referenced as an array. Here’s how to set its pin 8 high:

...

To buffer or not to buffer

The DMA-based UART driver in JeeH is an interesting example of the interaction between hardware, memory use, and blocking behaviour.

Reading data #

In JeeH, the way to read bytes from the UART is to send a message to its device driver, and wait for its reply. The mTag field is 'R', with the mLen and mPtr field starting off as zero. The driver uses a small ring buffer internally, which is filled in via DMA as bytes arrive. The CPU is not involved.

...

The next task is Tasks

As mentioned in my previous Threads vs Async I/O musings, threads are no longer the main concurrency mechanism I’m after, tasks are. Threads are still present in JeeH (and they actually work), but I’m not so keen on having to allocate stacks for each thread, nor on deciding up front how large they need to be.

So what is a task? #

Tasks are a bit different. I’m using the same sys::send and sys::recv mechanism for them as threads and device drivers, but they run as part of the thread which created them. Sending a message to a task behaves as if the message is sent to its owning thread and then forwarded to that specific task.

...

Spring cleaning

Looks like it’s that time of year again: I’m ripping apart what I have in JeeH 5.3 and reconstructing it in a different way. Perhaps it’s just madness, but I have two reasons to do this: 1) the task/thread design is too messy and 2) the way I can add and run tests is too tedious.

Tasks vs threads #

The first issue was unavoidable, once I figured out that tasks should not be an add-on to a threaded system, but exactly the other way around: threads are a special kind of task. Threads are tasks with their own stack, which can therefore be suspended and resumed. Tasks can’t: they either run to completion or they act on their “owning thread’s” behalf, i.e. they suspend their thread with them, if needed. This change puts tasks first, and optionally adds threads and context switching when needed. Then again, the reality is a bit more complex: there is in fact always one thread, the main() app code. It’s just that there’s no context switching involved until at least a second thread is created (with sys::fork(), as before). To support this, JeeH must be given an extra stack for interrupts, exceptions, and system calls, so that it can use ARM’s PSP + MSP dual stack approach (as before) and use PendSV for context switching.

...

Threads vs Async I/O

It was a mistake in JeeH to call something a Task when it really is a Thread, so I’ve decided to rename them everywhere in the code and in the documentation. Threads are separate execution contexts, each with their own stack. And that’s what’s in JeeH right now.

Threads #

Threads are a bit of a double-edged sword: yes, you can nicely modularise different parts of an application this way, especially in the context of a µC where lots of external events and interrupts are going on. But on a single-CPU system (i.e. all but the most extensive ARM Cortex µCs) they still need to run one at a time. There is no real parallelism going on. The inconvenience of threads is that each one needs to have its own stack area, each sized to handle peak memory needs, even though most of it will not be used at the same time. It can be quite wasteful, especially on a RAM-constrained µC.

...

Greetings

Musings ≠ weblog. The jeelabs.org site used to be my old weblog. For a fairly long time I posted there on a daily basis. Lots of topics I wanted to write about, as I discovered Arduino’s, the whole field of “physical computing”, and then went on to produce and sell JeeNodes, JeeLinks, JeePlugs, etc. It was great fun while it lasted, but at some point I ran out of fuel.

...