Coop.Objects.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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 = Environment.Running 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-,SP-: 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. InterruptList = POINTER TO RECORD
  79. next: InterruptList;
  80. handler: EventHandler
  81. END;
  82. Interrupter* = OBJECT
  83. VAR root: InterruptList;
  84. VAR cancelled: BOOLEAN;
  85. VAR interrupt: Interrupts.Interrupt;
  86. PROCEDURE &Init (irq: SIZE);
  87. BEGIN
  88. Interrupts.Install (interrupt, irq);
  89. END Init;
  90. PROCEDURE Add (handler: EventHandler);
  91. VAR item: InterruptList;
  92. BEGIN {EXCLUSIVE}
  93. NEW (item);
  94. item.next := root;
  95. item.handler := handler;
  96. root := item;
  97. END Add;
  98. PROCEDURE Remove (handler: EventHandler);
  99. VAR previous, current: InterruptList;
  100. BEGIN {EXCLUSIVE}
  101. previous := NIL; current := root;
  102. WHILE (current # NIL) & (current.handler # handler) DO
  103. previous := current; current := current.next;
  104. END;
  105. IF current # NIL THEN
  106. IF previous = NIL THEN
  107. root := current.next;
  108. ELSE
  109. previous.next := current.next;
  110. END;
  111. END;
  112. END Remove;
  113. PROCEDURE Count(): SIZE;
  114. VAR count := 0: SIZE; item: InterruptList;
  115. BEGIN {EXCLUSIVE}
  116. item := root;
  117. WHILE item # NIL DO INC (count); item := item.next END;
  118. RETURN count;
  119. END Count;
  120. PROCEDURE Cancel;
  121. BEGIN {EXCLUSIVE}
  122. IF ~cancelled THEN
  123. cancelled := TRUE;
  124. Interrupts.Cancel (interrupt);
  125. WAIT (SELF);
  126. END;
  127. END Cancel;
  128. PROCEDURE Handle;
  129. VAR item: InterruptList;
  130. BEGIN {EXCLUSIVE}
  131. item := root;
  132. WHILE item # NIL DO
  133. item.handler;
  134. item := item.next;
  135. END;
  136. END Handle;
  137. BEGIN {ACTIVE, PRIORITY(Realtime)}
  138. LOOP
  139. Interrupts.Await (interrupt);
  140. IF cancelled THEN EXIT END;
  141. Handle;
  142. END;
  143. END Interrupter;
  144. VAR
  145. awc-, awl-: LONGINT;
  146. oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
  147. event: Timer; (* list of events *)
  148. clock: Clock;
  149. interrupt: ARRAY CPU.Interrupts OF Interrupter;
  150. (* for compatibility and later extension *)
  151. TraceProcessHook* := NIL: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  152. (* Set the current process' priority. *)
  153. PROCEDURE SetPriority*( priority: LONGINT );
  154. BEGIN
  155. END SetPriority;
  156. (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
  157. PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
  158. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
  159. BEGIN
  160. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  161. ASSERT(hdr IS Heaps.ProtRecBlock);
  162. Machine.Acquire(Machine.Objects);
  163. res := (hdr.lockedBy = ActiveObject());
  164. Machine.Release(Machine.Objects);
  165. RETURN res
  166. END LockedByCurrent;
  167. PROCEDURE Yield*;
  168. BEGIN
  169. Activities.Switch;
  170. END Yield;
  171. PROCEDURE Sleep* (ms: LONGINT);
  172. BEGIN
  173. Environment.Sleep (ms);
  174. END Sleep;
  175. (** Return current process. (DEPRECATED, use ActiveObject) *)
  176. PROCEDURE CurrentProcess*( ): Process;
  177. BEGIN
  178. HALT (1234);
  179. RETURN NIL;
  180. END CurrentProcess;
  181. PROCEDURE CurrentContext*(): ANY;
  182. BEGIN
  183. RETURN Activities.GetCurrentActivity ().context;
  184. END CurrentContext;
  185. PROCEDURE SetContext*(context: ANY);
  186. BEGIN
  187. Activities.GetCurrentActivity ().context := context;
  188. END SetContext;
  189. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  190. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  191. BEGIN
  192. RETURN p.stackBottom
  193. END GetStackBottom;
  194. (** Return the active object currently executing. *)
  195. PROCEDURE ActiveObject* (): ANY;
  196. VAR activity {UNTRACED}: Activities.Activity;
  197. BEGIN {UNCOOPERATIVE, UNCHECKED}
  198. activity := Activities.GetCurrentActivity ();
  199. IF activity.object # NIL THEN RETURN activity.object ELSE RETURN activity END;
  200. END ActiveObject;
  201. (** Return the ID of the active currently executing process. *)
  202. PROCEDURE GetProcessID* (): LONGINT;
  203. BEGIN
  204. RETURN SYSTEM.VAL (LONGINT, Activities.GetCurrentActivity ());
  205. END GetProcessID;
  206. (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
  207. PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
  208. END TerminateThis;
  209. (* called by WMProcessInfo to obtain the current state of a running process *)
  210. PROCEDURE UpdateProcessState*( p: Process );
  211. BEGIN
  212. (* update p.stat.{PC,BP,SP} *)
  213. END UpdateProcessState;
  214. PROCEDURE Terminate*;
  215. BEGIN
  216. Activities.TerminateCurrentActivity;
  217. END Terminate;
  218. (** Set (or reset) an event handler object's timeout value. *)
  219. PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
  220. VAR e: Timer; trigger: LONGINT;
  221. BEGIN
  222. ASSERT((t # NIL) & (h # NIL));
  223. IF ms < 1 THEN ms := 1 END;
  224. Machine.Acquire(Machine.Objects);
  225. trigger := Environment.Clock () + ms;
  226. IF t.next # NIL THEN (* cancel previous timeout *)
  227. t.next.prev := t.prev; t.prev.next := t.next
  228. END;
  229. t.trigger := trigger; t.handler := h;
  230. e := event.next; (* performance: linear search! *)
  231. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  232. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  233. Machine.Release(Machine.Objects)
  234. END SetTimeout;
  235. (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
  236. PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
  237. VAR e: Timer; trigger: LONGINT;
  238. BEGIN
  239. ASSERT((t # NIL) & (h # NIL));
  240. Machine.Acquire(Machine.Objects);
  241. trigger := ms; (* ignore overflow *)
  242. IF t.next # NIL THEN (* cancel previous timeout *)
  243. t.next.prev := t.prev; t.prev.next := t.next
  244. END;
  245. t.trigger := trigger; t.handler := h;
  246. e := event.next; (* performance: linear search! *)
  247. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  248. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  249. Machine.Release(Machine.Objects);
  250. END SetTimeoutAt;
  251. (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
  252. PROCEDURE CancelTimeout*( t: Timer );
  253. BEGIN
  254. Machine.Acquire(Machine.Objects);
  255. ASSERT (t # event );
  256. IF t.next # NIL THEN
  257. t.next.prev := t.prev; t.prev.next := t.next; t.next := NIL;
  258. t.prev := NIL
  259. END;
  260. Machine.Release(Machine.Objects);
  261. END CancelTimeout;
  262. PROCEDURE LeaveA2-;
  263. END LeaveA2;
  264. PROCEDURE ReenterA2-;
  265. END ReenterA2;
  266. PROCEDURE InitEventHandling;
  267. BEGIN
  268. NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
  269. NEW(clock)
  270. END InitEventHandling;
  271. PROCEDURE NumReady*( ): LONGINT;
  272. BEGIN
  273. RETURN 0
  274. END NumReady;
  275. (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
  276. return the number of cycles since the process has been created. If FALSE, return the number of cycles
  277. consumed since the last time asked. *)
  278. PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
  279. VAR i : LONGINT;
  280. BEGIN
  281. ASSERT(process # NIL);
  282. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := process.cpuCycles[i]; END;
  283. IF ~all THEN
  284. FOR i := 0 TO Machine.MaxCPU-1 DO
  285. cpuCycles[i] := cpuCycles[i] - process.lastCpuCycles[i];
  286. process.lastCpuCycles[i] := process.cpuCycles[i]; (* actually could have changed meanwhile *)
  287. END;
  288. END;
  289. END GetCpuCycles;
  290. PROCEDURE CurrentProcessTime*(): HUGEINT;
  291. BEGIN
  292. RETURN Activities.GetProcessTime();
  293. END CurrentProcessTime;
  294. PROCEDURE TimerFrequency*(): HUGEINT;
  295. BEGIN
  296. RETURN TimerModule.GetFrequency();
  297. END TimerFrequency;
  298. (** Install interrupt handler. *)
  299. PROCEDURE InstallHandler*(h: EventHandler; int: LONGINT);
  300. VAR ih: Interrupter;
  301. BEGIN {EXCLUSIVE}
  302. ASSERT((int >= 0) & (int < CPU.Interrupts));
  303. ih := interrupt[int];
  304. IF ih = NIL THEN
  305. NEW (ih, int);
  306. interrupt[int] := ih;
  307. END;
  308. ih.Add(h);
  309. END InstallHandler;
  310. (** Remove interrupt handler. *)
  311. PROCEDURE RemoveHandler*(h: EventHandler; int: LONGINT);
  312. VAR ih: Interrupter;
  313. BEGIN {EXCLUSIVE}
  314. ASSERT((int >= 0) & (int < CPU.Interrupts));
  315. ih := interrupt[int];
  316. IF ih # NIL THEN
  317. ih.Remove(h);
  318. IF ih.Count () = 0 THEN
  319. ih.Cancel;
  320. interrupt[int] := NIL;
  321. END;
  322. END;
  323. END RemoveHandler;
  324. BEGIN
  325. InitEventHandling;
  326. END Objects.
  327. (*
  328. 24.03.1998 pjm Started
  329. 06.05.1998 pjm CreateProcess init process, page fault handler
  330. 06.08.1998 pjm Moved exception interrupt handling here for current process
  331. 17.08.1998 pjm FindRoots method
  332. 02.10.1998 pjm Idle process
  333. 06.11.1998 pjm snapshot
  334. 25.03.1999 pjm Scope removed
  335. 28.05.1999 pjm EventHandler object
  336. 01.06.1999 pjm Fixed InterruptProcess lock error
  337. 16.06.1999 pjm Flat IRQ priority model to avoid GC deadlock
  338. 23.06.1999 pjm Flat IRQ priority experiment failed, rather do STI in FieldIRQ to avoid GC deadlock
  339. 29.06.1999 pjm Timeout in EventHandler object
  340. 13.01.2000 pjm Overed (Interrupt Objects, Event Handlers, Process ID, Process state, Process mode, Process stack, Await)
  341. 17.10.2000 pjm Priorities
  342. 22.10.2003 mib SSE2 extension
  343. 24.10.2003 phk Priority inversion / cycle counters
  344. Stack invariant for GC:
  345. o if process is running, the processor registers contain its state
  346. o if process is not running, at least state.ESP is valid, and between stack.adr and stack.high (for GC)
  347. o when releasing the Ready lock, make sure the process state is up to date
  348. *)