Skip to content

os8088 v1.0.20260802

Choose a tag to compare

@jggonz jggonz released this 02 Aug 17:42
· 21 commits to main since this release
7afa4de

A package can run in the background, and a covered window can keep drawing.
Two API calls let a loaded package claim one worker task of its own, so two
packages can be pre-empted against each other for the first time; a clip region
replaces the boolean "am I covered?" veto that made every background painter
freeze under a single overlapping pixel; and FRACTAL.O88 -- five escape-time
fractals computed scanline by scanline while the desktop stays live -- is the
package that needed both.

A package can claim a background task (#36)

Until now a loaded package only ever ran inside its own window callbacks, on
the UI task: it could be scheduled against nothing. Two slots in the kernel's
jump table change that. OSAPI_TASK_SPAWN gives an instance exactly one worker
task, and OSAPI_TASK_ALIVE is where that worker finds out it is being closed
and dies. The teardown machinery already existed -- Clock and Bounce have been
task-owned instances since they were built -- so a package simply becomes
eligible for a path it had been excluded from. Two kernel-side rules hold it
up. inst_pkg_spawn fences the caller's window pointer with an ownership test,
because attaching a worker to a stranger's record puts both instances on the
wrong teardown path: the stranger hides forever waiting on a worker it does not
own, while the caller's own close frees the region its worker is still
executing in. And task_spawn now runs its slot scan and its state publish
under one cli, because this is the first time two different tasks can spawn
at once.

A covered window can draw again (#37)

wm_obscured answers a boolean, and every background painter used it as a veto
-- one covered pixel and the whole frame was skipped. It had to be that blunt,
because the drawing primitives take absolute screen coordinates and clip only
to the edge of the screen, so a covered window that drew would paint straight
over the window on top of it. The visible cost was a Bounce that froze under a
corner, a Clock that stopped, and a fractal that gave up two minutes of work.
wm_clip_set replaces the veto with a region: the window's content rect less
every visible window above it, drop shadows included, as a list of up to sixteen
disjoint rectangles, and while it is armed the six clipped primitives draw only
inside it. Overflow past sixteen degrades to "skip this frame" -- exactly what
the old boolean said -- so it cannot regress anything.

Fills clip per pixel; glyphs clip per whole cell (#37)

That asymmetry is deliberate -- a character cell cannot be drawn half-wide, so
a glyph that would straddle the region is dropped whole, the same way it is
already dropped at a screen edge -- and it is the sharp edge of the whole
feature. Anything that erases a rectangle and then writes text into it has to
reconcile the two or it goes blank rather than stale: a Clock cut
horizontally by another window's edge would get its visible rows white-filled
and then no digits back in them, twice a second. There is a third call,
wm_clip_test, so a caller can ask the glyphs' question before it erases
anything -- the Clock now erases per 8x8 cell behind it, the fractal's status
strip gates the erase and the text together. Solid drawing is unaffected, which
is why Bounce needed no change at either end.

A repaint no longer destroys the picture (#37)

A window's content has never been stored anywhere -- exposing one meant asking
the application to compute it from scratch, which for a fractal is minutes.
There is still no frame buffer, and there cannot be: the canvas is 27,200 bytes
against a 19,968-byte pool shared by every resident package. What fits is the
progressive first pass alone, one word per run of equal color -- color in the
top four bits, last column in the low twelve, which cannot collide -- so 4,000
bytes covers the whole canvas at quarter vertical resolution. A repaint replays
the cache and tells the worker to resume rather than restart, so an uncovered
window comes back with its picture already on it and the render carries on from
where it was.

FRACTAL.O88, the package that needed both (#36)

Five escape-time fractals -- Mandelbrot, two Julia sets, Burning Ship and
Tricorn -- through one fixed-point iteration core, four palettes, click to
recentre and zoom, all chosen from the menu bar. It is the reference client for
worker tasks: the worker computes each scanline with the drawing lock free and
takes it only for a short blit, so the desktop stays fully live through a
render, and two Fractals will render side by side while a Clock ticks and a
window is dragged over both. It also ships on the software disk, which is now
six packages -- and two Fractals plus Minesweeper plus Note Pad still fit the
pool, at 19,456 bytes of 19,968.

Notes

  • A worker task must never return or exit on its own. If it does, its instance
    record and its slice of the package pool leak for the rest of the session,
    because the close path then sets a die flag that nobody is left to read. The
    loop calls OSAPI_TASK_ALIVE every pass and that call is where it dies.
  • Bounce now always steps, and only its erase and redraw are conditional, so a
    covered or minimized one turns up where it now is rather than where it was
    buried. The old rule that a hidden Bounce skips without stepping is retired.
  • Not landed, and recorded as such: the fractal's symmetry mirror, and
    non-destructive window moves in the window manager. A drag still repaints
    what it uncovers rather than blitting it.

The build

Kernel image 41,739 bytes, up 1,103 from v1.0.20260801.1. Image plus .bss is
39,922 of the 45,056 available below the package pool, leaving 5,134 bytes.
37,184 lines of assembly across 28 kernel modules. The API jump table grew from
41 slots to 47 and its pinned start offset is unchanged.

Four raw floppy images are attached: os8088.img and apps.img for a 1.44MB
drive (QEMU), os8088-360.img and apps360.img for 360KB (86Box, real XT
hardware). Boot the first of each pair; the apps disk goes in the second drive
and is not bootable.

Checksums and the exact QEMU command line are on https://os8088.com/download/