SimProcess.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) September 11, 1986 1:40:57 pm PDT
Carl Hauser, March 31, 1987 4:08:44 pm PST
Demers, April 30, 1987 6:31:55 pm PDT
About the Dorado Simulation Environment:
1. This is a temporary hack to let us exercise at least some of the Dragon process code on D-machines.
2. Names that start out "Sim..." or "sim..." are part of the simulation environment (SIM), and will be deleted for the Real Dragon Implementation (RDI).
3. There are (intended to be) lots of comments about how things will change for the RDI. Search for SIM and RDI in the comments.
General comments:
1. We should consider splitting this into Process and ProcessPrivate - ajd.
2. This needs much more work on making the simulated processor state look like a real processor.
3. On interrupt enable/disable: note when you return, the enable/disable state reverts to that of the caller (except for EnableInterrupts[] and DisableInterrupts[]); but this is NOT TRUE for INLINES. Thus, there's a very subtle side-effect to commenting out the INLINE on a procedure. Arrgh.
4. We need to do something to relate PROCESS and SecureProcess!
DIRECTORY
DragOps USING [Word, ZerosWord];
SimProcess: CEDAR DEFINITIONS ~ BEGIN
Word: TYPE ~ DragOps.Word;
wordZero: Word ~ DragOps.ZerosWord;
Data Types for Process machinery (wizards only)
Sim Locks
SIM only.
SimLock: TYPE ~ REF SimLockRep;
SimLockRep: TYPE ~ MONITORED RECORD [];
Queues
Queue: TYPE ~ LONG POINTER TO QueueRep;
QueueRep: TYPE ~ RECORD [
busy: Process, -- a GSL that protects the chain
chain: Process -- points to the tail of a circular process queue
];
MetaQueue: TYPE = LONG POINTER TO MetaQueueRep;
MetaQueueRep: TYPE ~ Process;
emptyMetaQueueRep: MetaQueueRep ~ NIL;
Locks
MonitorLock: TYPE ~ LONG POINTER TO MonitorLockRep;
MonitorLockRep: TYPE ~ RECORD [
queue: QueueRep, -- the GQ of waiting processes
owner: Process -- the process owning the lock
];
InitializeMonitorLock: PROC [monitorLock: MonitorLock]
~ TRUSTED INLINE {monitorLock^ ← [queue: [NIL, NIL], owner: NIL]};
Condition: TYPE ~ LONG POINTER TO ConditionRep;
ConditionRep: TYPE ~ RECORD [
queue: QueueRep, -- the GQ of waiting processes
timeout: Ticks, -- the timeout initialization
flags: CondFlags -- option flags
];
Ticks: TYPE ~ CARD;
noTimeout: Ticks ~ 0;
Milliseconds: TYPE ~ CARD;
Seconds: TYPE ~ CARD;
CondFlags: TYPE ~ MACHINE DEPENDENT RECORD [
padBitsA: PACKED ARRAY [0..16) OF BOOL,
padBitsB: PACKED ARRAY [0..14) OF BOOL,
The two pad fields should be combined in RDI.
abortEnable: BOOL,
condRequest: BOOL
];
defaultCondFlags: CondFlags ~ [padBitsA~ALL[FALSE], padBitsB~ALL[FALSE], abortEnable~FALSE, condRequest~FALSE];
InitializeCondition: PROC [condition: Condition, ticks: Ticks]
~ TRUSTED INLINE {
condition^ ← [queue: [NIL, NIL], timeout: ticks, flags: defaultCondFlags]
};
MsecToTicks: SAFE PROC [Milliseconds] RETURNS [Ticks];
SecondsToTicks: SAFE PROC [Seconds] RETURNS [Ticks];
TicksToMsec: SAFE PROC [Ticks] RETURNS [Milliseconds];
Timeouts
SetTimeout: PROC [condition: Condition, ticks: Ticks]
~ TRUSTED INLINE {condition.timeout ←
IF ticks = noTimeout THEN noTimeout+1 ELSE ticks};
DisableTimeout: PROC [condition: Condition]
~ TRUSTED INLINE {condition.timeout ← noTimeout};
InterruptCondition: TYPE ~ LONG POINTER TO InterruptConditionRep;
InterruptConditionRep: TYPE ~ RECORD [queue: QueueRep, timeout: Word, requests: Word];
Processes
SecureProcess: TYPE ~ RECORD [
key: ProcessKey, -- matches key in ProcessRep
index: CARD  -- index in process table
];
ProcessKey: TYPE ~ CARD; -- RDI: change this to CARD64 ????
ProcessPtr: TYPE ~ LONG POINTER TO Process;
Process: TYPE ~ LONG POINTER TO ProcessRep;
ProcessRep: TYPE ~ RECORD [
secure: SecureProcess, -- denotes this ProcessRep
queue: Queue, -- pointer to queue that this process is waiting for
next: Process, -- next process in above circular queue
meta: Process, -- next process in ready queue, timeout queue or page fault queue
when: Ticks, -- when timeout will occur
page: Word, -- page number for fault
priority: Priority, -- priority of this process
state: ProcessState, -- process state
lock: MonitorLockRep, -- ML for following fields
abortState: AbortState, -- aborting state
joinState: JoinState, -- JOIN / Detach state
joinCondition: ConditionRep, -- to wait for JOIN rendezvous
euState: EUstate, -- useful registers in EU
sim: RefSimProcess -- SIM only
];
RefSimProcess: TYPE ~ REF SimProcessRep;
SimProcessRep: TYPE ~ RECORD [ -- SIM only
lock: SimLock,
awakenEvent: CONDITION,
awakened: BOOL,
processor: Processor
];
Priority: TYPE ~ MACHINE DEPENDENT {
slothful (0), -- user-level deep background processing (idle)
sluggish (1), -- user-level background processing
normal (2), -- user-level normal processing
perky (3), -- user-level foreground processing
nervous (4), -- system-level ?? processing
jumpy (5), -- system-level ?? processing
excited (6), -- system-level real-time processing
hyper (7) -- system-level emergency processing
};
ProcessState: TYPE ~ MACHINE DEPENDENT {
free (0), -- process is on free list
running (1), -- process is running (assigned to a processor)
ready (2), -- process is ready to run (on ready queue)
waitingPage (3), -- process is waiting for page fault (on page fault queue)
waitingCV (4), -- process is waiting for CV
waitingML (5), -- process is waiting for ML
waitingICV (6), -- process is waiting for ICV
done (7)  -- process is done (waiting for Join) (This may be subsumed by JoinState, below ???? ) - ajd
};
AbortState: TYPE ~ MACHINE DEPENDENT {
none (0), -- process not requested to abort
requested (1), -- process abort requested
inhibited (2), -- process abort not allowed & not requested
delayed (3)  -- process abort requested but not allowed
};
JoinState: TYPE ~ MACHINE DEPENDENT {
none (0), -- nothing has happened yet
exiting (1), -- process has finished, is waiting on its own joinCondition
joining (2), -- parent has JOINed and is waiting process's joinCondition
joined (3), -- parent has JOINed and retrieved results of process
detached (4) -- parent has detached process
};
THE FOLLOWING NEEDS A LOT OF WORK - ajd
EUstateIndex: TYPE ~ MACHINE DEPENDENT {
The "volatile" state - potentially smashed by interrupt handlers
carry (0), -- the carry bit (not really a register)
field (1), -- shifter control
temp0 (2), -- user aux reg 0 ???? - ajd
temp1 (3), -- user aux reg 1 ???? - ajd
temp2 (4), -- user aux reg 2 ???? - ajd
temp3 (5), -- user aux reg 3 ???? - ajd
The "non-volatile" state - preserved unless explicitly altered
hook (6), -- pointer to the youngest frame saved to memory (a nacho)
framesLeft (7) -- frames left before fault occurs
};
EUstate: TYPE ~ ARRAY EUstateIndex OF Word;
Nachos
Nachos are used to save EU & IFU registers associated with local frames. A chain of nachos is used to represent the process call stack. Nachos are fixed size to simplify and speed up allocation. Nachos are pinned to allow us to put a process to sleep without taking page faults.
Nacho: TYPE ~ LONG POINTER TO NachoRep;
NachoRep: TYPE ~ RECORD [
link: Nacho, -- link to the next elder frame in the process stack
nextPC: Word, -- the continuation PC for the frame
nextStatus: Word, -- the continuation Status for the frame
nRegs: Word, -- the # of registers saved in this Nacho
others: Nacho, -- the link to the area for more saved registers
regs: RegArray -- the saved registers (local variables)
];
RegArray: TYPE ~ ARRAY Reg OF Word;
Reg: TYPE ~ [0..15]; -- Should this be something out of DragOps???? ajd
Detaching processes
Detach: PROC [SecureProcess];
Identity of the currently executing process
GetCurrent: SAFE PROC RETURNS [SecureProcess]
~ TRUSTED INLINE {
};
Priorities of processes
SetPriority: SAFE PROC [p: Priority];
GetPriority: SAFE PROC RETURNS [Priority]
~ TRUSTED INLINE {
};
Aborting a process
Abort: PROC [SecureProcess];
Requests that the indicated process be aborted.
CheckForAbort: SAFE PROC;
Checks for the current process being asked to abort by Abort. Raises ABORTED if such a request has been made. Otherwise CheckForAbort is a null operation.
DisableAborts: PROC [condition: Condition]
~ TRUSTED INLINE {condition^.flags.abortEnable ← FALSE};
EnableAborts: PROC [condition: Condition]
~ TRUSTED INLINE {condition^.flags.abortEnable ← TRUE};
Control of Scheduling
Pause: SAFE PROC [ticks: Ticks];
Yield: SAFE PROC ~ TRUSTED INLINE{ DirectedYield[] };
DirectedYield: UNSAFE PROC [nextState: ProcessState ← ready, nextProcess: Process ← NIL, when: Ticks ← 0];
SetTimeSlice: SAFE PROC [ticks: Ticks];
Process validation
ValidateProcess: PROC [SecureProcess];
InvalidProcess: ERROR [secureProcess: SecureProcess];
Processor data
Processors are chained together in a circular queue that is not modified after initialization. Processor data is pinned.
ProcessorPtr: TYPE ~ LONG POINTER TO Processor;
Processor: TYPE ~ LONG POINTER TO ProcessorRep;
ProcessorRep: TYPE ~ RECORD [
next: Processor, -- next processor in ring.
orders: ProcessorOrders, -- orders for what to do after reschedule (hint only).
switchTo: Process, -- if orders = switchToGiven, then switch to this one (hint only).
running: Process, -- the process currently being run.
sim: RefSimProcessor -- SIM only.
];
RefSimProcessor: TYPE ~ REF SimProcessorRep;
SimProcessorRep: TYPE ~ RECORD [ -- SIM only
lock: SimLock,
interruptsEnabled: BOOL,
rescheduleRequested: BOOL,
process: Process, -- an aux register
processor: Processor -- an aux register
];
ProcessorOrders: TYPE ~ MACHINE DEPENDENT {
reset (0), -- useful during system init (?)
noChange (1), -- ignore the reschedule
switchToGiven (2), -- switch to process given by processor.switchTo (NIL => to best)
panicStop (3), -- save current process, then spin on these orders
stopped (4) -- stopped in response to panicStop
};
Interrupt Handling
RequestKind: TYPE ~ [0..31];
RequestWordPtr: TYPE ~ LONG POINTER TO RequestWord;
RequestWord: TYPE ~ PACKED ARRAY RequestKind OF BOOL;
nullRequestWord: RequestWord ~ ALL[FALSE];
IntHandler: TYPE ~ PROC [requestKind: RequestKind];
RegisterIntHandler: SAFE PROC [requestKind: RequestKind, intHandler: IntHandler]
RETURNS
[old: IntHandler];
The interrupt handler will be called for each request of the given kind. On entry to the handler, interrupts will be disabled and the metaLock will be held. The handler can't touch any code or data that isn't pinned, and can't use a lot of time. In most cases it should just do DelicateNotify[someInterruptConditionVariable] and return.
END.