123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich; this module ported for the windows version, fof. *)
- MODULE Objects; (** AUTHOR "pjm, ejz, fof"; PURPOSE "Active object runtime support"; *)
- IMPORT SYSTEM, Environment, Machine, Modules, Heaps, Activities, Interrupts, CPU, TimerModule := Timer;
- CONST
- (* Process flags *)
- Restart* = 0; (* Restart/Destroy process on exception *)
- PleaseHalt* = 10; (* Process requested to Halt itself soon *)
- Unbreakable* = 11;
- SelfTermination* = 12;
- Preempted* = 27; (* Has been preempted. *)
- Resistant* = 28; (* Can only be destroyed by itself *)
- PleaseStop* = 31; (* Process requested to Terminate or Halt itself soon *)
- InActive* = 26; (* needed to prevent processes to call finalizers while in await or lock or unlock, see Kernel.GC *)
- (** Process modes *)
- Unknown* = 0; Ready* = 1; (* for compatibility with native A2 *)
- Running* = 2; AwaitingLock* = 3; AwaitingCond* = 4; AwaitingEvent* = 5; Suspended* = 6; Terminated* = 7;
- (** Process priorities *)
- Low* = Activities.DefaultPriority; (* "user" priorities *)
- Normal* = Activities.DefaultPriority;
- High* = Activities.HighPriority;
- Realtime* = Activities.RealtimePriority; (* reserved for interrupt handling and realtime apps *)
- (* Process termination halt codes *)
- halt* = 2222;
- haltUnbreakable* = 2223;
- TYPE
- CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
- ProtectedObject = POINTER TO RECORD END; (* protected object (10000) *)
- Body = PROCEDURE (self: ProtectedObject);
- Condition = PROCEDURE (slink: ADDRESS): BOOLEAN;
- EventHandler* = PROCEDURE {DELEGATE};
- RealtimeEventHandler* = PROCEDURE {DELEGATE, REALTIME};
- Timer* = POINTER TO RECORD
- next, prev : Timer;
- trigger: LONGINT;
- handler: EventHandler
- END;
- RealtimeTimer* = POINTER TO RECORD
- next, prev: RealtimeTimer;
- trigger: LONGINT;
- handler: RealtimeEventHandler
- END;
- Clock = OBJECT
- VAR h: Timer;
- BEGIN {ACTIVE, SAFE, PRIORITY(High)}
- WHILE Environment.status = Environment.Running DO
- Machine.Acquire(Machine.Objects);
- LOOP
- h := event.next;
- IF (h = event) OR (h.trigger - Environment.Clock () > 0) THEN EXIT END;
- event.next := h.next; event.next.prev := event; (* unlink *)
- h.next := NIL; h.prev := NIL;
- Machine.Release(Machine.Objects);
- h.handler; (* assume handler will return promptly *)
- Machine.Acquire(Machine.Objects);
- END;
- Machine.Release(Machine.Objects);
- Environment.Sleep (1);
- END
- END Clock;
- TYPE
- Process* = OBJECT(Heaps.ProcessLink)
- VAR
- obj-: ProtectedObject; (* associated active object *)
- state-: RECORD PC-,BP-,SP-: ADDRESS END;
- condition-: Condition; (* awaited process' condition *)
- condFP-: LONGINT; (* awaited process' condition's context *)
- mode-: LONGINT; (* process state *) (* only changed inside Objects lock ??? *)
- procID-: LONGINT; (* processor ID where running, exported for compatibilty , useless in WinAos *)
- waitingOn-: ProtectedObject; (* obj this process is waiting on (for lock or condition) *)
- id-: LONGINT; (* unique process ID for tracing *)
- flags*: SET; (* process flags *)
- priority-: LONGINT; (* process priority *)
- stackBottom: LONGINT;
- restartPC-: LONGINT; (** entry point of body, for SAFE exception recovery *)
- restartSP-: LONGINT; (** stack level at start of body, for SAFE exception recovery *)
- cpuCycles, lastCpuCycles : CpuCyclesArray;
- END Process;
- FinalizedCollection* = OBJECT
- PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
- BEGIN HALT(301) END RemoveAll;
- END FinalizedCollection;
- FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
- c*: FinalizedCollection (* base type for collection containing object *)
- END;
-
- InterruptList = POINTER TO RECORD
- next: InterruptList;
- handler: EventHandler
- END;
- Interrupter* = OBJECT
- VAR root: InterruptList;
- VAR cancelled: BOOLEAN;
- VAR interrupt: Interrupts.Interrupt;
-
- PROCEDURE &Init (irq: SIZE);
- BEGIN
- Interrupts.Install (interrupt, irq);
- END Init;
- PROCEDURE Add (handler: EventHandler);
- VAR item: InterruptList;
- BEGIN {EXCLUSIVE}
- NEW (item);
- item.next := root;
- item.handler := handler;
- root := item;
- END Add;
-
- PROCEDURE Remove (handler: EventHandler);
- VAR previous, current: InterruptList;
- BEGIN {EXCLUSIVE}
- previous := NIL; current := root;
- WHILE (current # NIL) & (current.handler # handler) DO
- previous := current; current := current.next;
- END;
- IF current # NIL THEN
- IF previous = NIL THEN
- root := current.next;
- ELSE
- previous.next := current.next;
- END;
- END;
- END Remove;
-
- PROCEDURE Count(): SIZE;
- VAR count := 0: SIZE; item: InterruptList;
- BEGIN {EXCLUSIVE}
- item := root;
- WHILE item # NIL DO INC (count); item := item.next END;
- RETURN count;
- END Count;
-
- PROCEDURE Cancel;
- BEGIN {EXCLUSIVE}
- IF ~cancelled THEN
- cancelled := TRUE;
- Interrupts.Cancel (interrupt);
- WAIT (SELF);
- END;
- END Cancel;
- PROCEDURE Handle;
- VAR item: InterruptList;
- BEGIN {EXCLUSIVE}
- item := root;
- WHILE item # NIL DO
- item.handler;
- item := item.next;
- END;
- END Handle;
- BEGIN {ACTIVE, PRIORITY(Realtime)}
- LOOP
- Interrupts.Await (interrupt);
- IF cancelled THEN EXIT END;
- Handle;
- END;
- END Interrupter;
- VAR
- awc-, awl-: LONGINT;
- oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
- event: Timer; (* list of events *)
- clock: Clock;
- interrupt: ARRAY CPU.Interrupts OF Interrupter;
- (* for compatibility and later extension *)
- TraceProcessHook* := NIL: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
-
- (* Set the current process' priority. *)
- PROCEDURE SetPriority*( priority: LONGINT );
- BEGIN
- END SetPriority;
- (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
- PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
- BEGIN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
- ASSERT(hdr IS Heaps.ProtRecBlock);
- Machine.Acquire(Machine.Objects);
- res := (hdr.lockedBy = ActiveObject());
- Machine.Release(Machine.Objects);
- RETURN res
- END LockedByCurrent;
- PROCEDURE Yield*;
- BEGIN
- Activities.Switch;
- END Yield;
- PROCEDURE Sleep* (ms: LONGINT);
- BEGIN
- Environment.Sleep (ms);
- END Sleep;
- (** Return current process. (DEPRECATED, use ActiveObject) *)
- PROCEDURE CurrentProcess*( ): Process;
- BEGIN
- HALT (1234);
- RETURN NIL;
- END CurrentProcess;
- PROCEDURE CurrentContext*(): ANY;
- BEGIN
- RETURN NIL; (* stub *)
- END CurrentContext;
- PROCEDURE SetContext*(context: ANY);
- BEGIN
- (* stub *)
- END SetContext;
- (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
- PROCEDURE GetStackBottom*(p: Process): ADDRESS;
- BEGIN
- RETURN p.stackBottom
- END GetStackBottom;
- (** Return the active object currently executing. *)
- PROCEDURE ActiveObject* (): ANY;
- VAR activity {UNTRACED}: Activities.Activity;
- BEGIN {UNCOOPERATIVE, UNCHECKED}
- activity := Activities.GetCurrentActivity ();
- IF activity.object # NIL THEN RETURN activity.object ELSE RETURN activity END;
- END ActiveObject;
- (** Return the ID of the active currently executing process. *)
- PROCEDURE GetProcessID* (): LONGINT;
- BEGIN
- RETURN SYSTEM.VAL (LONGINT, Activities.GetCurrentActivity ());
- END GetProcessID;
- (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
- PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
- END TerminateThis;
- (* called by WMProcessInfo to obtain the current state of a running process *)
- PROCEDURE UpdateProcessState*( p: Process );
- BEGIN
- (* update p.stat.{PC,BP,SP} *)
- END UpdateProcessState;
- PROCEDURE Terminate*;
- BEGIN
- Activities.TerminateCurrentActivity;
- END Terminate;
- (** Set (or reset) an event handler object's timeout value. *)
- PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
- VAR e: Timer; trigger: LONGINT;
- BEGIN
- ASSERT((t # NIL) & (h # NIL));
- IF ms < 1 THEN ms := 1 END;
- Machine.Acquire(Machine.Objects);
- trigger := Environment.Clock () + ms;
- IF t.next # NIL THEN (* cancel previous timeout *)
- t.next.prev := t.prev; t.prev.next := t.next
- END;
- t.trigger := trigger; t.handler := h;
- e := event.next; (* performance: linear search! *)
- WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
- t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
- Machine.Release(Machine.Objects)
- END SetTimeout;
- (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
- PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
- VAR e: Timer; trigger: LONGINT;
- BEGIN
- ASSERT((t # NIL) & (h # NIL));
- Machine.Acquire(Machine.Objects);
- trigger := ms; (* ignore overflow *)
- IF t.next # NIL THEN (* cancel previous timeout *)
- t.next.prev := t.prev; t.prev.next := t.next
- END;
- t.trigger := trigger; t.handler := h;
- e := event.next; (* performance: linear search! *)
- WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
- t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
- Machine.Release(Machine.Objects);
- END SetTimeoutAt;
- (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
- PROCEDURE CancelTimeout*( t: Timer );
- BEGIN
- Machine.Acquire(Machine.Objects);
- ASSERT (t # event );
- IF t.next # NIL THEN
- t.next.prev := t.prev; t.prev.next := t.next; t.next := NIL;
- t.prev := NIL
- END;
- Machine.Release(Machine.Objects);
- END CancelTimeout;
- PROCEDURE LeaveA2-;
- END LeaveA2;
- PROCEDURE ReenterA2-;
- END ReenterA2;
- PROCEDURE InitEventHandling;
- BEGIN
- NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
- NEW(clock)
- END InitEventHandling;
- PROCEDURE NumReady*( ): LONGINT;
- BEGIN
- RETURN 0
- END NumReady;
- (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
- return the number of cycles since the process has been created. If FALSE, return the number of cycles
- consumed since the last time asked. *)
- PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
- VAR i : LONGINT;
- BEGIN
- ASSERT(process # NIL);
- FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := process.cpuCycles[i]; END;
- IF ~all THEN
- FOR i := 0 TO Machine.MaxCPU-1 DO
- cpuCycles[i] := cpuCycles[i] - process.lastCpuCycles[i];
- process.lastCpuCycles[i] := process.cpuCycles[i]; (* actually could have changed meanwhile *)
- END;
- END;
- END GetCpuCycles;
- PROCEDURE CurrentProcessTime*(): HUGEINT;
- BEGIN
- RETURN Activities.GetProcessTime();
- END CurrentProcessTime;
- PROCEDURE TimerFrequency*(): HUGEINT;
- BEGIN
- RETURN TimerModule.GetFrequency();
- END TimerFrequency;
- (** Install interrupt handler. *)
- PROCEDURE InstallHandler*(h: EventHandler; int: LONGINT);
- VAR ih: Interrupter;
- BEGIN {EXCLUSIVE}
- ASSERT((int >= 0) & (int < CPU.Interrupts));
- ih := interrupt[int];
- IF ih = NIL THEN
- NEW (ih, int);
- interrupt[int] := ih;
- END;
- ih.Add(h);
- END InstallHandler;
- (** Remove interrupt handler. *)
- PROCEDURE RemoveHandler*(h: EventHandler; int: LONGINT);
- VAR ih: Interrupter;
- BEGIN {EXCLUSIVE}
- ASSERT((int >= 0) & (int < CPU.Interrupts));
- ih := interrupt[int];
- IF ih # NIL THEN
- ih.Remove(h);
- IF ih.Count () = 0 THEN
- ih.Cancel;
- interrupt[int] := NIL;
- END;
- END;
- END RemoveHandler;
- BEGIN
- InitEventHandling;
- END Objects.
- (*
- 24.03.1998 pjm Started
- 06.05.1998 pjm CreateProcess init process, page fault handler
- 06.08.1998 pjm Moved exception interrupt handling here for current process
- 17.08.1998 pjm FindRoots method
- 02.10.1998 pjm Idle process
- 06.11.1998 pjm snapshot
- 25.03.1999 pjm Scope removed
- 28.05.1999 pjm EventHandler object
- 01.06.1999 pjm Fixed InterruptProcess lock error
- 16.06.1999 pjm Flat IRQ priority model to avoid GC deadlock
- 23.06.1999 pjm Flat IRQ priority experiment failed, rather do STI in FieldIRQ to avoid GC deadlock
- 29.06.1999 pjm Timeout in EventHandler object
- 13.01.2000 pjm Overed (Interrupt Objects, Event Handlers, Process ID, Process state, Process mode, Process stack, Await)
- 17.10.2000 pjm Priorities
- 22.10.2003 mib SSE2 extension
- 24.10.2003 phk Priority inversion / cycle counters
- Stack invariant for GC:
- o if process is running, the processor registers contain its state
- o if process is not running, at least state.ESP is valid, and between stack.adr and stack.high (for GC)
- o when releasing the Ready lock, make sure the process state is up to date
- *)
|