Windows.Kernel.Mod 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. (* red marked parts are specific for WinAos, fof *)
  3. MODULE Kernel; (** AUTHOR "pjm, ejz, fof, ug"; PURPOSE "Implementation-independent kernel interface"; *)
  4. IMPORT SYSTEM, Kernel32, Machine, Heaps, (* Modules, *) Objects;
  5. CONST
  6. TimerFree = 0; TimerSleeping = 1; TimerWoken = 2; TimerExpired = 3; (* Timer state *)
  7. Second* = Machine.Second;
  8. TYPE
  9. (** Finalizer for FinalizedCollection.Add. *)
  10. Finalizer* = Heaps.Finalizer; (** PROCEDURE (obj: ANY) *)
  11. (** Enumerator for FinalizedCollection.Enumerate. *)
  12. Enumerator* = PROCEDURE {DELEGATE} ( obj: ANY; VAR cont: BOOLEAN );
  13. FinalizerNode = POINTER TO RECORD (Objects.FinalizerNode)
  14. nextObj {UNTRACED} : FinalizerNode; (* in Collection c *)
  15. END;
  16. (** Polling timer. *)
  17. MilliTimer* = RECORD
  18. start, target: LONGINT
  19. END;
  20. TYPE
  21. (** Delay timer *)
  22. Timer* = OBJECT
  23. VAR
  24. timer: Objects.Timer;
  25. state-: SHORTINT;
  26. nofHandleTimeout-, nofHandleTimeout2- : LONGINT;
  27. nofSleeps-, nofSleepsLeft- : LONGINT;
  28. nofAwaits-, nofAwaitsLeft- : LONGINT;
  29. PROCEDURE HandleTimeout;
  30. BEGIN {EXCLUSIVE}
  31. INC(nofHandleTimeout);
  32. IF state # TimerFree THEN INC(nofHandleTimeout2); state := TimerExpired END
  33. END HandleTimeout;
  34. (** Delay the calling process the specified number of milliseconds or until Wakeup is called. Only one process may sleep on a specific timer at a time. *)
  35. PROCEDURE Sleep*(ms: LONGINT);
  36. BEGIN {EXCLUSIVE}
  37. INC(nofSleeps);
  38. ASSERT(state = TimerFree); (* only one process may sleep on a timer *)
  39. state := TimerSleeping;
  40. Objects.SetTimeout(timer, HandleTimeout, ms);
  41. INC(nofAwaits);
  42. AWAIT(state # TimerSleeping);
  43. INC(nofAwaitsLeft);
  44. IF state # TimerExpired THEN Objects.CancelTimeout(timer) END;
  45. state := TimerFree;
  46. INC(nofSleepsLeft);
  47. END Sleep;
  48. (** Wake up the process sleeping on the timer, if any. *)
  49. PROCEDURE Wakeup*;
  50. BEGIN {EXCLUSIVE}
  51. IF state = TimerSleeping THEN state := TimerWoken END
  52. END Wakeup;
  53. (** Initializer. *)
  54. PROCEDURE &Init*;
  55. BEGIN
  56. state := TimerFree; NEW(timer);
  57. nofHandleTimeout := 0; nofHandleTimeout2 := 0;
  58. nofSleeps := 0; nofSleepsLeft := 0;
  59. nofAwaits := 0; nofAwaitsLeft := 0;
  60. END Init;
  61. END Timer;
  62. TYPE
  63. (** A collection of objects that are finalized automatically by the garbage collector. *)
  64. FinalizedCollection* = OBJECT (Objects.FinalizedCollection)
  65. VAR root: FinalizerNode; (* weak list of contents linked by nextObj *)
  66. (** Add obj to collection. Parameter fin specifies finalizer, or NIL if not required. *) (* may be called multiple times *)
  67. PROCEDURE Add*(obj: ANY; fin: Finalizer);
  68. VAR n: FinalizerNode;
  69. BEGIN
  70. NEW(n); n.c := SELF; n.finalizer := fin;
  71. Heaps.AddFinalizer(obj, n);
  72. BEGIN {EXCLUSIVE}
  73. n.nextObj := root.nextObj; root.nextObj := n (* add to collection *)
  74. END
  75. END Add;
  76. (** Remove one occurrence of obj from collection. *)
  77. PROCEDURE Remove*(obj: ANY);
  78. VAR p, n: FinalizerNode;
  79. BEGIN {EXCLUSIVE}
  80. p := root; n := p.nextObj;
  81. WHILE (n # NIL) & (n.objWeak # obj) DO
  82. p := n; n := n.nextObj
  83. END;
  84. IF n # NIL THEN p.nextObj := n.nextObj END;
  85. (* leave in global finalizer list *)
  86. END Remove;
  87. (** Overriden method: Remove all occurrences of obj from collection. *)
  88. PROCEDURE RemoveAll*(obj: ANY);
  89. VAR p, n: FinalizerNode;
  90. BEGIN {EXCLUSIVE}
  91. p := root; n := p.nextObj;
  92. WHILE n # NIL DO
  93. IF n.objWeak = obj THEN
  94. p.nextObj := n.nextObj;
  95. ELSE
  96. p := n;
  97. END;
  98. n := n.nextObj
  99. END
  100. END RemoveAll;
  101. (** Enumerate all objects in the collection (Enumerator may not call Remove, Add, Enumerate or Clear). *)
  102. PROCEDURE Enumerate*(enum: Enumerator);
  103. VAR fn, next: FinalizerNode; cont: BOOLEAN;
  104. BEGIN {EXCLUSIVE}
  105. fn := root.nextObj; cont := TRUE;
  106. WHILE fn # NIL DO
  107. next := fn.nextObj; (* current (or other) object may be removed by enum call *)
  108. enum(fn.objWeak, cont);
  109. IF cont THEN fn := next ELSE fn := NIL END
  110. END
  111. END Enumerate;
  112. (** Enumerate all objects in the collection not being finalized (Enumerator may not call Remove, Add, Enumerate or Clear). *)
  113. PROCEDURE EnumerateN*( enum: Enumerator );
  114. VAR fn, next: FinalizerNode; cont: BOOLEAN; obj: ANY;
  115. BEGIN {EXCLUSIVE}
  116. fn := root.nextObj; cont := TRUE;
  117. WHILE fn # NIL DO
  118. next := fn.nextObj; (* current (or other) object may be removed by enum call *)
  119. obj := NIL;
  120. Machine.Acquire(Machine.GC); (* prevent GC from running *)
  121. IF (fn.objWeak # NIL ) & (fn.objStrong = NIL ) THEN (* object is not yet on the finalizers list *)
  122. obj := fn.objWeak; (* now object is locally referenced, will therefore not be GCed *)
  123. END;
  124. Machine.Release(Machine.GC);
  125. IF obj # NIL THEN enum( obj, cont ); END;
  126. IF cont THEN fn := next ELSE fn := NIL END
  127. END
  128. END EnumerateN;
  129. (** Initialize new collection. May also be called to clear an existing collection. *)
  130. PROCEDURE &Clear*;
  131. BEGIN {EXCLUSIVE}
  132. NEW(root); root.nextObj := NIL (* head *)
  133. END Clear;
  134. END FinalizedCollection;
  135. VAR
  136. second- : LONGINT; (** number of ticks per second (Hz) *)
  137. (*
  138. PROCEDURE Watch;
  139. VAR free, total1, total2, largest, low, high: LONGINT;
  140. BEGIN
  141. IF TraceFin THEN
  142. Heaps.GetHeapInfo( total1, free, largest ); total1 := (total1 + 512) DIV 1024; free := (free + 512) DIV 1024;
  143. largest := (largest + 512) DIV 1024; Machine.GetFreeK( total2, low, high ); KernelLog.Enter; KernelLog.String( "Heap: " );
  144. KernelLog.Int( total1, 1 ); KernelLog.String( " total, " ); KernelLog.Int( free, 1 ); KernelLog.String( " free, " ); KernelLog.Int( largest, 1 );
  145. KernelLog.String( " largest, Mem: " ); KernelLog.Int( total2, 1 ); KernelLog.String( " total, " ); KernelLog.Int( low, 1 ); KernelLog.String( " low, " );
  146. KernelLog.Int( high, 1 ); KernelLog.String( " high" ); KernelLog.Exit
  147. END
  148. END Watch;
  149. *)
  150. (** Return the number of ticks since system start. For timeouts, time measurements, etc, please use Kernel.MilliTimer instead.
  151. Ticks increment rate is stored in "second" variable in Hz. *)
  152. PROCEDURE GetTicks*() : LONGINT;
  153. BEGIN
  154. RETURN Kernel32.GetTickCount()
  155. END GetTicks;
  156. (** -- Garbage collection -- *)
  157. (** Activate the garbage collector immediately. *)
  158. PROCEDURE GC*;
  159. BEGIN
  160. Heaps.LazySweepGC;
  161. END GC;
  162. (** -- Timers -- *)
  163. (** Set timer to expire in approximately "ms" milliseconds. *)
  164. PROCEDURE SetTimer*( VAR t: MilliTimer; ms: LONGINT );
  165. BEGIN
  166. IF Machine.Second # 1000 THEN (* convert to ticks *)
  167. ASSERT ( (ms >= 0) & (ms <= MAX( LONGINT ) DIV Machine.Second) );
  168. ms := ms * Machine.Second DIV 1000
  169. END;
  170. IF ms < 5 THEN INC( ms ) END; (* Nyquist adjustment *)
  171. t.start := Kernel32.GetTickCount(); t.target := t.start + ms
  172. END SetTimer;
  173. (** Test whether a timer has expired. *)
  174. PROCEDURE Expired*( VAR t: MilliTimer ): BOOLEAN;
  175. BEGIN
  176. RETURN Kernel32.GetTickCount() - t.target >= 0
  177. END Expired;
  178. (** Return elapsed time on a timer in milliseconds. *)
  179. PROCEDURE Elapsed*( VAR t: MilliTimer ): LONGINT;
  180. BEGIN
  181. RETURN (Kernel32.GetTickCount() - t.start) * (1000 DIV Machine.Second)
  182. END Elapsed;
  183. (** Return time left on a timer in milliseconds. *)
  184. PROCEDURE Left*( VAR t: MilliTimer ): LONGINT;
  185. BEGIN
  186. RETURN (t.target - Kernel32.GetTickCount()) * (1000 DIV Machine.Second)
  187. END Left;
  188. PROCEDURE Nothing;
  189. BEGIN
  190. END Nothing;
  191. BEGIN
  192. ASSERT (1000 MOD Machine.Second = 0); (* for Elapsed *)
  193. second := Machine.Second;
  194. Heaps.GC := Heaps.InvokeGC; (* must be done after all processors have started *)
  195. (*
  196. Heaps.GC := Nothing;
  197. *)
  198. END Kernel.
  199. (**
  200. Notes:
  201. o The FinalizedCollection object implements collections of finalized objects.
  202. o Objects added to a finalized collection (with Add) are removed automatically by the garbage collector when no references to them exist any more. They can also be removed explicitly with Remove.
  203. o All the objects currently in a collection can be enumerated by Enumerate, which takes an enumerator procedure as parameter. The enumerator can also be a method in an object, which is useful when state information is required during the enumeration. The enumerator may not call other methods of the same collection.
  204. o An object in a finalized collection can have an finalizer procedure associated with it, which gets called by a separate process when there are no references left to the object any more. A finalizer is usually used for some cleanup functions, e.g. releasing external resources. It is executed exactly once per object. During the next garbage collector cycle the object is finally removed.
  205. *)
  206. (*
  207. to do:
  208. o cancel finalizer when removing object
  209. o fix module free race: module containing finalizer is freed. although the finalizer list is cleared, the FinalizerCaller has already taken a reference to a finalizer, but hasn't called it yet.
  210. o consider: a module has a FinalizedCollection, without finalizers (NIL). when the module is freed, the objects are still in the finalization list, and will get finalized in the next garbage collection. The FinalizedCollection will survive the first collection, as the objects all have references to it through their c field. After all objects have been finalized, the FinalizedCollection itself is collected. No dangling pointers occur, except the untraced module field references from the type descriptors, which are only used for tracing purposes.
  211. o check cyclic dependencies between finalized objects.
  212. o GetTime(): LONGINT - return current time in ms
  213. o Delay(td: LONGINT) - wait td ms
  214. o AwaitTime(t: LONGINT) - wait at least until time t
  215. o Wakeup(obj: ANY) - wake up object that is waiting
  216. *)