Liam wrote:
> I was not merely looking for a lightweight OS. I had a demanding list
of criteria.
> I looked for:
• a clean, simple OS, with SMP support, that supported pre-emption,
memory management etc.
• in a type-safe language, with a native-object-code compiler — not
JITTed, not using a VM or runtime
• and a readable language, not something far outside the Algol family
of imperative HLLs
• that was portable across different architectures
• that was FOSS and could be forked
• that was documented and had a user community who knew it
• that can be built with FOSS tools (which RISC OS fails, for instance)
• which is or was used by non-specialists for general purpose computing
• which can usefully access the Internet
• which runs on commodity hardware
• which does not have a strongly filesystem-centric design that would
not fit a PMEM-only computer (i.e. not an xNix)
I think you have specified a null set.
Alan Kay said: "The best way to predict the future is to invent it."
You have described the world you want to move into.
My only suggestion here is to look at OSs which are easily ported. I
would look at RISC-V because the kind of solution you are looking for
will probably appear there first.
Within "type-strict", you might consider a Rust or Haskell oSs. [I
think Smalltalk is "type-safe", every object knows its class and trying
to access element 41 of a 10 element array gives DNU, but I suspect this
is not your definition].
For small, FreeRTOS and PharOS
(https://sourceforge.net/projects/rtospharos/) look interesting.
From Wikipedia entry on RISC-V:
"Available RISC-V software tools include a GNU Compiler Collection (GCC)
toolchain (with GDB, the debugger), an LLVM toolchain, the OVPsim
simulator (and library of RISC-V Fast Processor Models), the Spike
simulator, and a simulator in QEMU (RV32GC/RV64GC).
Operating system support exists for the Linux kernel, FreeBSD, and
NetBSD, but the supervisor-mode instructions were unstandardized prior
to June 2019,[14] so this support is provisional. The preliminary
FreeBSD port to the RISC-V architecture was upstreamed in February 2016,
and shipped in FreeBSD 11.0.[96][74] Ports of Debian[97] and Fedora[98]
are stabilizing (both only support 64-bit RISC-V, with no plans to
support 32-bit version). A port of Das U-Boot exists.[99] UEFI Spec v2.7
has defined the RISC-V binding and a TianoCore port has been done by HPE
engineers[100] and is expected to be upstreamed. There is a preliminary
port of the seL4 microkernel.[101][102] Hex Five released the first
Secure IoT Stack for RISC-V with FreeRTOS support.[103] Also xv6, a
modern reimplementation of Sixth Edition Unix in ANSI C used for
pedagogical purposes in MIT, was ported. Pharos RTOS has been ported to
64-bit RISC-V[104] (including time and memory protection). Also see
Comparison of real-time operating systems.
"
Note also OSDev.org.
Good on ya,
-KenD
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1728.mcz
==================== Summary ====================
Name: Morphic-mt.1728
Author: mt
Time: 1 March 2021, 12:21:45.616905 pm
UUID: 9034e981-d83b-c344-a079-e9eb55c8115f
Ancestors: Morphic-mt.1727
Increases robustness during layout computation. Similar to WorldState >> #displayWorldSafely:. Here, faulty layout policies will be disabled to keep the environment responsive.
Note that you can try breaking #doLayoutIn: and then take a look at all those #fullBounds sends. (After reverting the last change via the emergency evaluator, of course.)
=============== Diff against Morphic-mt.1727 ===============
Item was changed:
----- Method: Morph>>adjustLayoutBounds (in category 'layout') -----
adjustLayoutBounds
"Adjust the receivers bounds depending on the resizing strategy imposed"
| hFit vFit box sbox myExtent myOrigin myBox |
hFit := self hResizing.
vFit := self vResizing.
(hFit == #shrinkWrap or:[vFit == #shrinkWrap]) ifFalse:[^self]. "not needed"
(self cellSpacing == #none and: [self listSpacing == #none]) ifFalse: [
self flag: #todo. "mt: Find a way to make cell sizes accessible from here."
+ self cellSpacing: #none; listSpacing: #none.
self notify: 'It is not possible to shrink-wrap around submorphs when the layout policy reserves extra cell space. At this point, we have no access to that extra cell space and we do not know whether the submorph did make use of that extra space. So, shrink-wrapping could make the bounds very unstable.\\Please either reset #cellSpacing and #listSpacing - or change the resizing strategy to #rigid or #spaceFill.' withCRs.
^ self].
box := self layoutBounds.
sbox := self submorphBoundsForShrinkWrap outsetBy: self cellInset.
myExtent := box extent.
myOrigin := box origin.
hFit == #shrinkWrap ifTrue:[
myExtent := sbox extent x @ myExtent y.
myOrigin := sbox origin x @ myOrigin y].
vFit == #shrinkWrap ifTrue:[
myExtent := myExtent x @ sbox extent y.
myOrigin := myOrigin x @ sbox origin y].
"Make sure we don't get smaller than minWidth/minHeight"
myExtent x < self minWidth ifTrue:[
myExtent := (myExtent x max:
(self minWidth - self bounds width + self layoutBounds width)) @ myExtent y].
myExtent y < self minHeight ifTrue:[
myExtent := myExtent x @ (myExtent y max:
(self minHeight - self bounds height + self layoutBounds height))].
myBox := myOrigin extent: myExtent.
self setLayoutBoundsFromLayout: myBox.!
Item was changed:
----- Method: Morph>>buildDebugMenu: (in category 'debug and other') -----
buildDebugMenu: aHand
"Answer a debugging menu for the receiver. The hand argument is seemingly historical and plays no role presently"
| aMenu aPlayer |
aMenu := MenuMorph new defaultTarget: self.
aMenu addStayUpItem.
(self hasProperty: #errorOnDraw) ifTrue:
[aMenu add: 'start drawing again' translated action: #resumeAfterDrawError.
aMenu addLine].
(self hasProperty: #errorOnStep) ifTrue:
[aMenu add: 'start stepping again' translated action: #resumeAfterStepError.
aMenu addLine].
+ (self hasProperty: #errorOnLayout) ifTrue:
+ [aMenu add: 'start layouting again' translated action: #resumeAfterLayoutError.
+ aMenu addLine].
aMenu add: 'inspect morph' translated action: #inspectInMorphic:.
aMenu add: 'inspect owner chain' translated action: #inspectOwnerChain.
Smalltalk isMorphic ifFalse:
[aMenu add: 'inspect morph (in MVC)' translated action: #inspect].
self isMorphicModel ifTrue:
[aMenu add: 'inspect model' translated target: self model action: #inspect;
add: 'explore model' translated target: self model action: #explore].
(aPlayer := self player) ifNotNil:
[aMenu add: 'inspect player' translated target: aPlayer action: #inspect].
aMenu add: 'explore morph' translated target: self selector: #exploreInMorphic:.
aMenu addLine.
aPlayer ifNotNil:
[ aMenu add: 'viewer for Player' translated target: self player action: #beViewed.
aMenu balloonTextForLastItem: 'Opens a viewer on my Player -- this is the same thing you get if you click on the cyan "View" halo handle' translated ].
aMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly.
aMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated.
aMenu addLine.
aPlayer ifNotNil:
[aPlayer class isUniClass ifTrue: [
aMenu add: 'browse player class' translated target: aPlayer selector: #haveFullProtocolBrowsedShowingSelector: argumentList: #(nil)]].
aMenu add: 'browse morph class' translated target: self selector: #browseHierarchy.
(self isMorphicModel)
ifTrue: [aMenu
add: 'browse model class'
target: self model
selector: #browseHierarchy].
aMenu addLine.
self addViewingItemsTo: aMenu.
aMenu
add: 'make own subclass' translated action: #subclassMorph;
add: 'save morph in file' translated action: #saveOnFile;
addLine;
add: 'call #tempCommand' translated action: #tempCommand;
add: 'define #tempCommand' translated action: #defineTempCommand;
addLine;
add: 'control-menu...' translated target: self selector: #invokeMetaMenu:;
add: 'edit balloon help' translated action: #editBalloonHelpText.
^ aMenu!
Item was added:
+ ----- Method: Morph>>doLayout (in category 'layout') -----
+ doLayout
+
+ self doLayoutIn: self layoutBounds.!
Item was added:
+ ----- Method: Morph>>doLayoutSafely (in category 'layout') -----
+ doLayoutSafely
+ "Also see #resumeAfterLayoutError."
+
+ [fullBounds] whileNil: [
+ [self doLayout] on: Error, Halt, Warning do: [:error |
+
+ | errorMorph |
+ (error signalerContext
+ findContextSuchThat: [:context |
+ context receiver isMorph and: [context receiver layoutPolicy notNil]])
+ ifNil: [^ Project current primitiveError: error description]
+ ifNotNil: [:errorContext | errorMorph := errorContext receiver].
+ errorMorph
+ instVarNamed: #fullBounds
+ put: (errorMorph instVarNamed: #bounds).
+ (Warning handles: error) ifFalse: [
+ "Disable the policy unless it is a warning, which should be secured where signaled to ease debugging."
+ errorMorph
+ setProperty: #errorOnLayout toValue: errorMorph layoutPolicy;
+ setProperty: #layoutPolicy toValue: nil. "Avoid #layoutChanged!!"].
+
+ ToolSet debugException: error]].!
Item was changed:
----- Method: Morph>>fullBounds (in category 'layout') -----
fullBounds
+ "Return the bounding box of the receiver and all its children. Recompute the layout if necessary. See #layoutChanged."
+
+ ^ fullBounds ifNil: [self doLayoutSafely. fullBounds]!
- "Return the bounding box of the receiver and all its children. Recompute the layout if necessary."
- fullBounds ifNotNil:[^fullBounds].
- "Errors at this point can be critical so make sure we catch 'em all right"
- [self doLayoutIn: self layoutBounds] on: Error, Warning, Halt do:[:ex|
- "This should do it unless you don't screw up the bounds"
- fullBounds := bounds.
- ex pass].
- ^fullBounds!
Item was added:
+ ----- Method: Morph>>resumeAfterLayoutError (in category 'debug and other') -----
+ resumeAfterLayoutError
+ "Resume layouting after an error has occured."
+
+ self layoutPolicy: (self valueOfProperty: #errorOnLayout ifAbsent: [^ self]).
+ self removeProperty:#errorOnLayout.!
Item was changed:
----- Method: MorphicDebugger class>>openOn:context:label:contents:fullView: (in category 'opening') -----
openOn: processToDebug context: context label: title contents: contentsStringOrNil fullView: full
| debugger uiBlock |
debugger := self new
process: processToDebug context: context;
errorWasInUIProcess: (Project current spawnNewProcessIfThisIsUI: processToDebug).
uiBlock := [
full
ifTrue: [debugger openFullNoSuspendLabel: title]
ifFalse: [debugger openNotifierNoSuspendContents: contentsStringOrNil label: title].
+ "Try layouting the debugger tool at least once to avoid freeze."
+ debugger topView ifNotNil: [:window |
+ "There are way too many #fullBounds sends. Layout errors might already have happened."
+ window allMorphsDo: [:m | (m hasProperty: #errorOnLayout) ifTrue: [self error: 'Layout error']].
+ window world doLayout. "Not safely!!"].
"Try drawing the debugger tool at least once to avoid freeze."
debugger topView ifNotNil: [:window | window world displayWorld. "Not safely!!"].
].
"Schedule debugging in a deferred UI message if necessary. Note that only the ui process should execute ui code."
(Project current uiProcess isActiveProcess not or: [processToDebug isActiveProcess])
ifTrue: [Project current addDeferredUIMessage: uiBlock]
ifFalse: uiBlock.
processToDebug suspend.
"Get here only if active process is not the process-to-debug. So in tests, use a helper process if you want to access this return value."
^ debugger!
Marcel Taeumel uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-mt.1027.mcz
==================== Summary ====================
Name: Tools-mt.1027
Author: mt
Time: 1 March 2021, 11:19:25.66938 am
UUID: 4a78193f-b0aa-1b42-9f4a-d588b979d0b6
Ancestors: Tools-mt.1026
Let warnings appear as "normal" as possible via #debugException:.
Note that the "normal" contents are prepared only in ToolSet >> #handleWarning: for unhandled warnings, which is transparent to the signaler. This interface, however, is for exception handlers that want to allow for post-exception debugging, which can also catch warnings.
=============== Diff against Tools-mt.1026 ===============
Item was changed:
----- Method: StandardToolSet class>>debugException: (in category 'debugging') -----
debugException: anException
"For convenience. Construct a helper process to debug an exception that occurred in the active process later on so that the active process can (try to) resume. Uses a temporary variable to access and copy the signaler context now before it gets GC'ed."
| helperProcess |
helperProcess := (Process
forContext: anException signalerContext copyStack
priority: Processor activeProcess priority)
shouldResumeFromDebugger: false;
yourself.
Project current addDeferredUIMessage: [
helperProcess
debugWithTitle: anException description
+ full: false
+ contents: ((anException isKindOf: Warning)
+ ifTrue: [anException messageText])].!
- full: false].!
Liam wrote:
> I do not know much about the whole L4 family but what little I know
some of the existing OSes based upon them were very vaguely Unix-ish.
That's precisely what I'm trying to move away from.
• I do not know if SEL4 has working multiprocessor support. I know
that QNX does, which demonstrates that a Unix-like true microkernel
can do this; but I also believe that Minix 3 so far lacks one, and
lacks some APIs needed for POSIX and xNix compatibility. This is not
an easy thing to do.
..
Right. I am thinking of expanding outward from Genode (
https://genode.org/about/index ), start with a small (non-Unix) OS which
runs on (some of) x86/ARM64/RISC-V which can be used as a bootstrap for
Smalltalk->Native runtime, then replace services written in C to
services written in Smalltalk initially with the same API, but later
re-imagined. An ultra-secure OS which has the right basics for
hotplug/live updates. Add eMail & Web browsing after getting core St
GUI up.
This is pretty much a scratch effort. Some C at first, particularly in
the microkernel (e.g. seL4) but this is minimal and kinda like changing
FPGA gates.
We are probably "agreeing loudly" on most of this, particularly given my
ignorance of Oberon.
Later,
-KenD