# Idling

Dusk's "main" execution loop is to repeatedly fetch word from its input source
and execute it. If the input source is interactive, it means that it spends the
vast majority of its time waiting for this source.

The unit at [lib/idle.fs] realiases "idle", which allows you to use this time to
do other tasks one after the other.

This unit holds a linked list of routines that are called one after the other
whenever "idle" is called.

You could, for example, want to maintain some debug information at specific
coordinates of your Grid subsystem. Or, if you have a mouse subsystem, you'll
want to regularly update its coordinates. You would do that through "idle".

All units in Dusk needing to do some idling do so through this unit.

## "idle" is a core word

Above, we say "realiases" rather than "provide" because the word "idle" is
defined in core words because it is referenced early in the boot process.
However, this word is reserved for the semantics of the lib/idle unit. However,
you don't need to add "lib/idle" to your dependencies in order to call "idle".

## When to idle?

When writing code, sometimes it's appropriate to insert a "idle", but it's not
always clear when. The general guideline is that idling should happen every few
tens of milliseconds.

First of all, there's the run loops. Whenever you're in a loop that implies
interaction with the operator, you need to idle.

Although we could, if we wanted, idle at every mass storage access, or every
"f<<", we don't. It's too deep in granularity. Most of the time, such access is
instant from the perspective of the operator.

But sometimes, we know that some operations take longer than it should for the
operator to stay without feedback.

One such example is the test suite. It take several seconds to run. We can't
leave the operator without a idle loop. Therefore, we idle at "testbegin" and
"testend" in [tests/harness.fs].

Another example is Duskberon [oberon]. On a Raspberry Pi, it takes a few seconds
to load it all. It's a close call, but it's enough to pass the threshold.
Therefore, we add a idle call in the "Loading module" message in
[comp/oberon.fs].

Another obvious example is the booting sequence. For a while, we have no way to
output anything on the screen, but when we do, we appreciate the feedback.
Therefore, it's a good idea, on systems that don't have instant boot, to litter
theit init.fs file with ".." calls (see below).

## Example usage


  needs lib/idle
  variable mycounter
  :> 1 mycounter +! ; idleadd
  ...
  mycounter @ . \ This number should be going up very fast

## Implementation details

The idle loop is a list of routines in which we keep track of the next routine
to call. Calling "idle" simply calls that routine select the next one in the
list for the next "idle" call. In other words, "idle" calls *one* item in the
loop.

"idle" doesn't have to be called only by "key". In can also be called by a word
that is doing a time-intensive task. That those tasks call "idle" is what
enables multi-tasking.

There's an important caveat with idle: if you call it in a "low" enough place, a
driver for example, you are likely to end up in an infinite self-referential
loop.

Therefore, calling "idle" is for high level loops, not drivers. When drivers
need to wait, they should use [drv/timer].

## API

idle ( -- )
  Call the next word of the idle loop.

idleadd ( xt -- )
  Add word "xt" to the idle loop.

.. ( -- )
  Shortcut of "'.' emit idle". It's appropriate to use in long loading sequences
  to indicate progress. Using only "emit" doesn't cut it in some cases, such as
  [io/grid] systems, because those systems only refresh themselves on idling.
  Therefore, you'll want to use this word instead.
