Coop.Objects.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich; this module ported for the windows version, fof. *)
  2. MODULE Objects; (** AUTHOR "pjm, ejz, fof"; PURPOSE "Active object runtime support"; *)
  3. IMPORT SYSTEM, Environment, Machine, Modules, Heaps, Activities, Interrupts, CPU, TimerModule := Timer;
  4. CONST
  5. (* Process flags *)
  6. Restart* = 0; (* Restart/Destroy process on exception *)
  7. PleaseHalt* = 10; (* Process requested to Halt itself soon *)
  8. Unbreakable* = 11;
  9. SelfTermination* = 12;
  10. Preempted* = 27; (* Has been preempted. *)
  11. Resistant* = 28; (* Can only be destroyed by itself *)
  12. PleaseStop* = 31; (* Process requested to Terminate or Halt itself soon *)
  13. InActive* = 26; (* needed to prevent processes to call finalizers while in await or lock or unlock, see Kernel.GC *)
  14. (** Process modes *)
  15. Unknown* = 0; Ready* = 1; (* for compatibility with native A2 *)
  16. Running* = 2; AwaitingLock* = 3; AwaitingCond* = 4; AwaitingEvent* = 5; Suspended* = 6; Terminated* = 7;
  17. (** Process priorities *)
  18. Low* = Activities.DefaultPriority; (* "user" priorities *)
  19. Normal* = Activities.DefaultPriority;
  20. High* = Activities.HighPriority;
  21. Realtime* = Activities.RealtimePriority; (* reserved for interrupt handling and realtime apps *)
  22. (* Process termination halt codes *)
  23. halt* = 2222;
  24. haltUnbreakable* = 2223;
  25. TYPE
  26. CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
  27. ProtectedObject = POINTER TO RECORD END; (* protected object (10000) *)
  28. Body = PROCEDURE (self: ProtectedObject);
  29. Condition = PROCEDURE (slink: ADDRESS): BOOLEAN;
  30. EventHandler* = PROCEDURE {DELEGATE};
  31. RealtimeEventHandler* = PROCEDURE {DELEGATE, REALTIME};
  32. Timer* = POINTER TO RECORD
  33. next, prev : Timer;
  34. trigger: LONGINT;
  35. handler: EventHandler
  36. END;
  37. RealtimeTimer* = POINTER TO RECORD
  38. next, prev: RealtimeTimer;
  39. trigger: LONGINT;
  40. handler: RealtimeEventHandler
  41. END;
  42. Clock = OBJECT
  43. VAR h: Timer;
  44. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  45. WHILE Environment.status = 0 DO
  46. Machine.Acquire(Machine.Objects);
  47. LOOP
  48. h := event.next;
  49. IF (h = event) OR (h.trigger - Environment.Clock () > 0) THEN EXIT END;
  50. event.next := h.next; event.next.prev := event; (* unlink *)
  51. h.next := NIL; h.prev := NIL;
  52. Machine.Release(Machine.Objects);
  53. h.handler; (* assume handler will return promptly *)
  54. Machine.Acquire(Machine.Objects);
  55. END;
  56. Machine.Release(Machine.Objects);
  57. Environment.Sleep (1);
  58. END
  59. END Clock;
  60. TYPE
  61. Process* = OBJECT(Heaps.ProcessLink)
  62. VAR
  63. obj-: ProtectedObject; (* associated active object *)
  64. state-: RECORD PC-,BP-: ADDRESS END;
  65. condition-: Condition; (* awaited process' condition *)
  66. condFP-: LONGINT; (* awaited process' condition's context *)
  67. mode-: LONGINT; (* process state *) (* only changed inside Objects lock ??? *)
  68. procID-: LONGINT; (* processor ID where running, exported for compatibilty , useless in WinAos *)
  69. waitingOn-: ProtectedObject; (* obj this process is waiting on (for lock or condition) *)
  70. id-: LONGINT; (* unique process ID for tracing *)
  71. flags*: SET; (* process flags *)
  72. priority-: LONGINT; (* process priority *)
  73. stackBottom: LONGINT;
  74. restartPC-: LONGINT; (** entry point of body, for SAFE exception recovery *)
  75. restartSP-: LONGINT; (** stack level at start of body, for SAFE exception recovery *)
  76. cpuCycles, lastCpuCycles : CpuCyclesArray;
  77. END Process;
  78. FinalizedCollection* = OBJECT
  79. PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
  80. BEGIN HALT(301) END RemoveAll;
  81. END FinalizedCollection;
  82. FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
  83. c*: FinalizedCollection (* base type for collection containing object *)
  84. END;
  85. InterruptList = POINTER TO RECORD
  86. next: InterruptList;
  87. handler: EventHandler
  88. END;
  89. Interrupter* = OBJECT
  90. VAR root: InterruptList;
  91. VAR cancelled: BOOLEAN;
  92. VAR interrupt: Interrupts.Interrupt;
  93. PROCEDURE &Init (irq: SIZE);
  94. BEGIN
  95. Interrupts.Install (interrupt, irq);
  96. END Init;
  97. PROCEDURE Add (handler: EventHandler);
  98. VAR item: InterruptList;
  99. BEGIN {EXCLUSIVE}
  100. NEW (item);
  101. item.next := root;
  102. item.handler := handler;
  103. root := item;
  104. END Add;
  105. PROCEDURE Remove (handler: EventHandler);
  106. VAR previous, current: InterruptList;
  107. BEGIN {EXCLUSIVE}
  108. previous := NIL; current := root;
  109. WHILE (current # NIL) & (current.handler # handler) DO
  110. previous := current; current := current.next;
  111. END;
  112. IF current # NIL THEN
  113. IF previous = NIL THEN
  114. root := current.next;
  115. ELSE
  116. previous.next := current.next;
  117. END;
  118. END;
  119. END Remove;
  120. PROCEDURE Count(): SIZE;
  121. VAR count := 0: SIZE; item: InterruptList;
  122. BEGIN {EXCLUSIVE}
  123. item := root;
  124. WHILE item # NIL DO INC (count); item := item.next END;
  125. RETURN count;
  126. END Count;
  127. PROCEDURE Cancel;
  128. BEGIN {EXCLUSIVE}
  129. IF ~cancelled THEN
  130. cancelled := TRUE;
  131. Interrupts.Cancel (interrupt);
  132. WAIT (SELF);
  133. END;
  134. END Cancel;
  135. PROCEDURE Handle;
  136. VAR item: InterruptList;
  137. BEGIN {EXCLUSIVE}
  138. item := root;
  139. WHILE item # NIL DO
  140. item.handler;
  141. item := item.next;
  142. END;
  143. END Handle;
  144. BEGIN {ACTIVE, PRIORITY(Realtime)}
  145. LOOP
  146. Interrupts.Await (interrupt);
  147. IF cancelled THEN EXIT END;
  148. Handle;
  149. END;
  150. END Interrupter;
  151. VAR
  152. awc-, awl-: LONGINT;
  153. oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
  154. event: Timer; (* list of events *)
  155. clock: Clock;
  156. interrupt: ARRAY CPU.Interrupts OF Interrupter;
  157. (* for compatibility and later extension *)
  158. TraceProcessHook* := NIL: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  159. (* Set the current process' priority. *)
  160. PROCEDURE SetPriority*( priority: LONGINT );
  161. BEGIN
  162. END SetPriority;
  163. (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
  164. PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
  165. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
  166. BEGIN
  167. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  168. ASSERT(hdr IS Heaps.ProtRecBlock);
  169. Machine.Acquire(Machine.Objects);
  170. res := (hdr.lockedBy = ActiveObject());
  171. Machine.Release(Machine.Objects);
  172. RETURN res
  173. END LockedByCurrent;
  174. PROCEDURE Yield*;
  175. BEGIN
  176. Activities.Switch;
  177. END Yield;
  178. (** Return current process. (DEPRECATED, use ActiveObject) *)
  179. PROCEDURE CurrentProcess*( ): Process;
  180. BEGIN
  181. HALT (1234);
  182. RETURN NIL;
  183. END CurrentProcess;
  184. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  185. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  186. BEGIN
  187. RETURN p.stackBottom
  188. END GetStackBottom;
  189. (** Return the active object currently executing. *)
  190. PROCEDURE ActiveObject* (): ANY;
  191. BEGIN
  192. RETURN Activities.GetCurrentActivity ().object;
  193. END ActiveObject;
  194. (** Return the ID of the active currently executing process. *)
  195. PROCEDURE GetProcessID* (): LONGINT;
  196. BEGIN
  197. RETURN SYSTEM.VAL (LONGINT, Activities.GetCurrentActivity ());
  198. END GetProcessID;
  199. (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
  200. PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
  201. END TerminateThis;
  202. PROCEDURE Terminate*;
  203. BEGIN
  204. Activities.TerminateCurrentActivity;
  205. END Terminate;
  206. (** Set (or reset) an event handler object's timeout value. *)
  207. PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
  208. VAR e: Timer; trigger: LONGINT;
  209. BEGIN
  210. ASSERT((t # NIL) & (h # NIL));
  211. IF ms < 1 THEN ms := 1 END;
  212. Machine.Acquire(Machine.Objects);
  213. trigger := Environment.Clock () + ms;
  214. IF t.next # NIL THEN (* cancel previous timeout *)
  215. t.next.prev := t.prev; t.prev.next := t.next
  216. END;
  217. t.trigger := trigger; t.handler := h;
  218. e := event.next; (* performance: linear search! *)
  219. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  220. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  221. Machine.Release(Machine.Objects)
  222. END SetTimeout;
  223. (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
  224. PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
  225. VAR e: Timer; trigger: LONGINT;
  226. BEGIN
  227. ASSERT((t # NIL) & (h # NIL));
  228. Machine.Acquire(Machine.Objects);
  229. trigger := ms; (* ignore overflow *)
  230. IF t.next # NIL THEN (* cancel previous timeout *)
  231. t.next.prev := t.prev; t.prev.next := t.next
  232. END;
  233. t.trigger := trigger; t.handler := h;
  234. e := event.next; (* performance: linear search! *)
  235. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  236. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  237. Machine.Release(Machine.Objects);
  238. END SetTimeoutAt;
  239. (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
  240. PROCEDURE CancelTimeout*( t: Timer );
  241. BEGIN
  242. Machine.Acquire(Machine.Objects);
  243. ASSERT (t # event );
  244. IF t.next # NIL THEN
  245. t.next.prev := t.prev; t.prev.next := t.next; t.next := NIL;
  246. t.prev := NIL
  247. END;
  248. Machine.Release(Machine.Objects);
  249. END CancelTimeout;
  250. PROCEDURE InitEventHandling;
  251. BEGIN
  252. NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
  253. NEW(clock)
  254. END InitEventHandling;
  255. PROCEDURE NumReady*( ): LONGINT;
  256. BEGIN
  257. RETURN 0
  258. END NumReady;
  259. (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
  260. return the number of cycles since the process has been created. If FALSE, return the number of cycles
  261. consumed since the last time asked. *)
  262. PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
  263. VAR i : LONGINT;
  264. BEGIN
  265. ASSERT(process # NIL);
  266. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := process.cpuCycles[i]; END;
  267. IF ~all THEN
  268. FOR i := 0 TO Machine.MaxCPU-1 DO
  269. cpuCycles[i] := cpuCycles[i] - process.lastCpuCycles[i];
  270. process.lastCpuCycles[i] := process.cpuCycles[i]; (* actually could have changed meanwhile *)
  271. END;
  272. END;
  273. END GetCpuCycles;
  274. PROCEDURE CurrentProcessTime*(): HUGEINT;
  275. BEGIN
  276. RETURN Activities.GetProcessTime();
  277. END CurrentProcessTime;
  278. PROCEDURE TimerFrequency*(): HUGEINT;
  279. BEGIN
  280. RETURN TimerModule.GetFrequency();
  281. END TimerFrequency;
  282. (** Install interrupt handler. *)
  283. PROCEDURE InstallHandler*(h: EventHandler; int: LONGINT);
  284. VAR ih: Interrupter;
  285. BEGIN {EXCLUSIVE}
  286. ASSERT((int >= 0) & (int < CPU.Interrupts));
  287. ih := interrupt[int];
  288. IF ih = NIL THEN
  289. NEW (ih, int);
  290. interrupt[int] := ih;
  291. END;
  292. ih.Add(h);
  293. END InstallHandler;
  294. (** Remove interrupt handler. *)
  295. PROCEDURE RemoveHandler*(h: EventHandler; int: LONGINT);
  296. VAR ih: Interrupter;
  297. BEGIN {EXCLUSIVE}
  298. ASSERT((int >= 0) & (int < CPU.Interrupts));
  299. ih := interrupt[int];
  300. IF ih # NIL THEN
  301. ih.Remove(h);
  302. IF ih.Count () = 0 THEN
  303. ih.Cancel;
  304. interrupt[int] := NIL;
  305. END;
  306. END;
  307. END RemoveHandler;
  308. BEGIN
  309. InitEventHandling;
  310. END Objects.
  311. (*
  312. 24.03.1998 pjm Started
  313. 06.05.1998 pjm CreateProcess init process, page fault handler
  314. 06.08.1998 pjm Moved exception interrupt handling here for current process
  315. 17.08.1998 pjm FindRoots method
  316. 02.10.1998 pjm Idle process
  317. 06.11.1998 pjm snapshot
  318. 25.03.1999 pjm Scope removed
  319. 28.05.1999 pjm EventHandler object
  320. 01.06.1999 pjm Fixed InterruptProcess lock error
  321. 16.06.1999 pjm Flat IRQ priority model to avoid GC deadlock
  322. 23.06.1999 pjm Flat IRQ priority experiment failed, rather do STI in FieldIRQ to avoid GC deadlock
  323. 29.06.1999 pjm Timeout in EventHandler object
  324. 13.01.2000 pjm Overed (Interrupt Objects, Event Handlers, Process ID, Process state, Process mode, Process stack, Await)
  325. 17.10.2000 pjm Priorities
  326. 22.10.2003 mib SSE2 extension
  327. 24.10.2003 phk Priority inversion / cycle counters
  328. Stack invariant for GC:
  329. o if process is running, the processor registers contain its state
  330. o if process is not running, at least state.ESP is valid, and between stack.adr and stack.high (for GC)
  331. o when releasing the Ready lock, make sure the process state is up to date
  332. *)