Nut Operating System (Nos)
How NOS work?
Nos works under NOSS (Nos simulator). Nos are user-space
functions (running in user-space). Noss is responsible to
time-multiplex the nos function (switchp, the task-switcher) execution
and user functions execution. Both are running is
user-space. The main function of NOSS is to issue a control to
processor simulator (S-machine) to run a number of instructions before
returning to NOSS. Noss does this by commanding the s-machine
simulator (the eval() in C) to run the s-code for a number of
instructions and save its C-state. The first thing Nos does is to
run task-switching (switchp) followed by running the task (at
restoreCstate). This behaviour regards Noss as "interruptor" to
s-machine simulator, i.e., s-machine is running some computing process
and Noss "interrupts" it at a fixed interval to run "task-switching".
Nos starts by executing "main" function which initialise global
variables and creates processes to run user functions by (run (user-fun
...)). After this start-up, noss enters the main loop:
while
there is a task
run switchp and at restore
C-state, run user ;; by call eval once
save C-state
This is the code in nos for switchp:
;;
status indicates how the process has been interrupted:
;;
time-out, block, end
switchp
if status is time-out or
block
if one-process
runnable that process
else
set current process to ready
runnable next process
if status is end
delete current
process
runnable next
process
runnable
set process to running
restore C-state
Most functions in nos (switchp, wait, signal) must be atomic, that is,
they must run to completion before allowing interruption to switch
process. This is achieved by adding two system calls to
s-machine: disable interrupt, enable interrupt. In the s-machine
simulator, the eval() executes a fixed number of instruction by
checking the instruction count. This is the main fetch-execute
cycle of s-machine (in fact most processor simulator are like this):
eval
count = 0
loop
if count >
limit break
fetch an
instruction
execute the
instruction
count = count
+ 1
To implement "interrupt", a flag (intflag) is used to disable the
break. This flag can be turned on/off by the system calls.
eval2
count = 0
loop
if intflag == 1
if
count > limit break
fetch an
instruction
execute the
instruction
count = count
+ 1
The process descriptor contains C-state. C-state consists of fp, sp and
ip. Saving and restoring C-state are the act of transferring
C-state between the s-machine simulator state and C-state of the
process. Noss does the restoring of C-state by running the code in
user-space. This restoring will affect the flow of execution, as the
instruction pointer is changed, it does a jump in the program.
Therefore, the precise point of time when this jump occurs is
important. There must not be any code following this jump.
This instruction must be the last instruction execute in the function
(and it never returns to the caller). As Noss is responsible to
run the task-switcher, it must save C-state. Saving C-state can
not be done in user-space as the precise state has been changed when
trying to run the "saving state" function. So, save-Cstate is
done in the main loop of Noss (in C). This gives the save-Cstate
a special previlege (so called "kernel" in OS vocabulary). It is
implemented as a system call instruction in s-machine.
The system calls that support Nos are:
20 disable interrupt
21 enable interrupt
22 block current process
23 save C-state // never run in user-space
24 restore C-state
Example session
A user program is written as (count) and integrated with nos in "main":
;
---- application --------
(def count (n) (i)
(do
(set i 0)
(while (< i n)
(do
(set i (+ i 1))
(print i)
(space)))))
(def main () (p)
(do
(sys 5)
(set activep 0)
(set sseg 1000)
(run (count 500))
(bootnos)))
The (run (count 500)) creates a process to run (count 500).
(bootnos) starts the process running.
To run NOSS, first compile user functions with NOS in nos.txt:
e:\test>nut21
< nos.txt
print
(fun.1.1 (sys.1 get.1 ))
printc
(fun.1.1 (sys.2 get.1 ))
nl
(fun.0.0 (sys.2 lit.10 ))
space
(fun.0.0 (sys.2 lit.32 ))
not
(fun.1.1 (if get.1 lit.0 lit.1 ))
. . .
Then run NOSS with the a.obj executable:
e:\test>noss < a.obj
print
printc
. . .
setslist
showp
wakeup
signal
wait
run
runnable
switchp
bootnos
count
main
1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
*
50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
. . .
146 147 148 149 150 151 152 153
154 155 156 157 158 159
*
160 161 162 163 164 165 166
167 168 169 170 171 172 173 174 175 176 177 178 179
. . .
240 241 242 243 244 245 246
247 248 249 250 251 252 253 254 255 256 257 258 259
260 261 262 263 264 265 266
267 268
*
269 270 271 272 273 274 275
276 277 278 279 280 281 282 283 284 285 286 287 288
. . .
*
487 488 489 490 491 492 493 494
495 496 497 498 499 500
*
9345 clocks
e:\test>
The "*" indicates the task-switching (every 1000 instructions).
24 Jan 2005
Prabhas Chongstitvatana