Coop.Objects.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. (* Set the current process' priority. *)
  158. PROCEDURE SetPriority*( priority: LONGINT );
  159. BEGIN
  160. END SetPriority;
  161. (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
  162. PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
  163. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
  164. BEGIN
  165. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  166. ASSERT(hdr IS Heaps.ProtRecBlock);
  167. Machine.Acquire(Machine.Objects);
  168. res := (hdr.lockedBy = ActiveObject());
  169. Machine.Release(Machine.Objects);
  170. RETURN res
  171. END LockedByCurrent;
  172. PROCEDURE Yield*;
  173. BEGIN
  174. Activities.Switch;
  175. END Yield;
  176. (** Return current process. (DEPRECATED, use ActiveObject) *)
  177. PROCEDURE CurrentProcess*( ): Process;
  178. BEGIN
  179. HALT (1234);
  180. RETURN NIL;
  181. END CurrentProcess;
  182. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  183. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  184. BEGIN
  185. RETURN p.stackBottom
  186. END GetStackBottom;
  187. (** Return the active object currently executing. *)
  188. PROCEDURE ActiveObject* (): ANY;
  189. BEGIN
  190. RETURN Activities.GetCurrentActivity ().object;
  191. END ActiveObject;
  192. (** Return the ID of the active currently executing process. *)
  193. PROCEDURE GetProcessID* (): LONGINT;
  194. BEGIN
  195. RETURN SYSTEM.VAL (LONGINT, Activities.GetCurrentActivity ());
  196. END GetProcessID;
  197. (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
  198. PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
  199. END TerminateThis;
  200. PROCEDURE Terminate*;
  201. BEGIN
  202. Activities.TerminateCurrentActivity;
  203. END Terminate;
  204. (** Set (or reset) an event handler object's timeout value. *)
  205. PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
  206. VAR e: Timer; trigger: LONGINT;
  207. BEGIN
  208. ASSERT((t # NIL) & (h # NIL));
  209. IF ms < 1 THEN ms := 1 END;
  210. Machine.Acquire(Machine.Objects);
  211. trigger := Environment.Clock () + ms;
  212. IF t.next # NIL THEN (* cancel previous timeout *)
  213. t.next.prev := t.prev; t.prev.next := t.next
  214. END;
  215. t.trigger := trigger; t.handler := h;
  216. e := event.next; (* performance: linear search! *)
  217. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  218. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  219. Machine.Release(Machine.Objects)
  220. END SetTimeout;
  221. (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
  222. PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
  223. VAR e: Timer; trigger: LONGINT;
  224. BEGIN
  225. ASSERT((t # NIL) & (h # NIL));
  226. Machine.Acquire(Machine.Objects);
  227. trigger := ms; (* ignore overflow *)
  228. IF t.next # NIL THEN (* cancel previous timeout *)
  229. t.next.prev := t.prev; t.prev.next := t.next
  230. END;
  231. t.trigger := trigger; t.handler := h;
  232. e := event.next; (* performance: linear search! *)
  233. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  234. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  235. Machine.Release(Machine.Objects);
  236. END SetTimeoutAt;
  237. (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
  238. PROCEDURE CancelTimeout*( t: Timer );
  239. BEGIN
  240. Machine.Acquire(Machine.Objects);
  241. ASSERT (t # event );
  242. IF t.next # NIL THEN
  243. t.next.prev := t.prev; t.prev.next := t.next; t.next := NIL;
  244. t.prev := NIL
  245. END;
  246. Machine.Release(Machine.Objects);
  247. END CancelTimeout;
  248. PROCEDURE InitEventHandling;
  249. BEGIN
  250. NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
  251. NEW(clock)
  252. END InitEventHandling;
  253. PROCEDURE NumReady*( ): LONGINT;
  254. BEGIN
  255. RETURN 0
  256. END NumReady;
  257. (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
  258. return the number of cycles since the process has been created. If FALSE, return the number of cycles
  259. consumed since the last time asked. *)
  260. PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
  261. VAR i : LONGINT;
  262. BEGIN
  263. ASSERT(process # NIL);
  264. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := process.cpuCycles[i]; END;
  265. IF ~all THEN
  266. FOR i := 0 TO Machine.MaxCPU-1 DO
  267. cpuCycles[i] := cpuCycles[i] - process.lastCpuCycles[i];
  268. process.lastCpuCycles[i] := process.cpuCycles[i]; (* actually could have changed meanwhile *)
  269. END;
  270. END;
  271. END GetCpuCycles;
  272. PROCEDURE CurrentProcessTime*(): HUGEINT;
  273. BEGIN
  274. RETURN Activities.GetProcessTime();
  275. END CurrentProcessTime;
  276. PROCEDURE TimerFrequency*(): HUGEINT;
  277. BEGIN
  278. RETURN TimerModule.GetFrequency();
  279. END TimerFrequency;
  280. (** Install interrupt handler. *)
  281. PROCEDURE InstallHandler*(h: EventHandler; int: LONGINT);
  282. VAR ih: Interrupter;
  283. BEGIN {EXCLUSIVE}
  284. ASSERT((int >= 0) & (int < CPU.Interrupts));
  285. ih := interrupt[int];
  286. IF ih = NIL THEN
  287. NEW (ih, int);
  288. interrupt[int] := ih;
  289. END;
  290. ih.Add(h);
  291. END InstallHandler;
  292. (** Remove interrupt handler. *)
  293. PROCEDURE RemoveHandler*(h: EventHandler; int: LONGINT);
  294. VAR ih: Interrupter;
  295. BEGIN {EXCLUSIVE}
  296. ASSERT((int >= 0) & (int < CPU.Interrupts));
  297. ih := interrupt[int];
  298. IF ih # NIL THEN
  299. ih.Remove(h);
  300. IF ih.Count () = 0 THEN
  301. ih.Cancel;
  302. interrupt[int] := NIL;
  303. END;
  304. END;
  305. END RemoveHandler;
  306. BEGIN
  307. InitEventHandling;
  308. END Objects.
  309. (*
  310. 24.03.1998 pjm Started
  311. 06.05.1998 pjm CreateProcess init process, page fault handler
  312. 06.08.1998 pjm Moved exception interrupt handling here for current process
  313. 17.08.1998 pjm FindRoots method
  314. 02.10.1998 pjm Idle process
  315. 06.11.1998 pjm snapshot
  316. 25.03.1999 pjm Scope removed
  317. 28.05.1999 pjm EventHandler object
  318. 01.06.1999 pjm Fixed InterruptProcess lock error
  319. 16.06.1999 pjm Flat IRQ priority model to avoid GC deadlock
  320. 23.06.1999 pjm Flat IRQ priority experiment failed, rather do STI in FieldIRQ to avoid GC deadlock
  321. 29.06.1999 pjm Timeout in EventHandler object
  322. 13.01.2000 pjm Overed (Interrupt Objects, Event Handlers, Process ID, Process state, Process mode, Process stack, Await)
  323. 17.10.2000 pjm Priorities
  324. 22.10.2003 mib SSE2 extension
  325. 24.10.2003 phk Priority inversion / cycle counters
  326. Stack invariant for GC:
  327. o if process is running, the processor registers contain its state
  328. o if process is not running, at least state.ESP is valid, and between stack.adr and stack.high (for GC)
  329. o when releasing the Ready lock, make sure the process state is up to date
  330. *)