Generic.Modules.Mod 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. MODULE Modules; (** AUTHOR "pjm"; PURPOSE "Modules and types"; *)
  2. IMPORT SYSTEM, Trace, Machine, Heaps, Runtime;
  3. CONST
  4. Ok* = 0;
  5. AddressSize = SIZEOF (ADDRESS); (* architecture dependent size of addresses in bytes *)
  6. MaxTags* = 16; (* in type descriptor *)
  7. (** type descriptor field offsets relative to root (middle) *)
  8. Tag0Ofs* = -AddressSize * 2; (** first tag *)
  9. Mth0Ofs* = Tag0Ofs - AddressSize*MaxTags; (** first method *)
  10. Ptr0Ofs* = AddressSize; (** first pointer offset *)
  11. MaxObjFormats = 5; (* maximum number of object file formats installed *)
  12. (** flags in TypeDesc, RoundUp(log2(MaxTags)) low bits reserved for extLevel *)
  13. ProtTypeBit* = Heaps.ProtTypeBit;
  14. None* = 0; PowerDown* = 1; Reboot* = 2;
  15. ClearCode = TRUE;
  16. InitTableLen = 1024;
  17. InitPtrTableLen = 2048;
  18. DefaultContext* = "A2";
  19. NoLoader=3400;
  20. TraceBoot=TRUE;
  21. TYPE
  22. (* definitions for object-model loader support *)
  23. Name* = ARRAY 32 OF CHAR;
  24. DynamicName* = POINTER {UNSAFE} TO ARRAY 256 OF CHAR;
  25. Command* = RECORD
  26. (* Fields exported for initialization by loader/linker only! Consider read-only! *)
  27. name*: Name; (* name of the procedure *)
  28. argTdAdr*, retTdAdr* : ADDRESS; (* address of type descriptors of argument and return type, 0 if no type *)
  29. entryAdr* : ADDRESS; (* entry address of procedure *)
  30. END;
  31. ExportDesc* = RECORD
  32. fp*: LONGINT;
  33. name* {UNTRACED}: DynamicName;
  34. adr*: ADDRESS;
  35. exports*: LONGINT;
  36. dsc* {UNTRACED}: ExportArray
  37. END;
  38. ExportArray* = POINTER {UNSAFE} TO ARRAY OF ExportDesc;
  39. Bytes* = POINTER TO ARRAY OF CHAR;
  40. TerminationHandler* = PROCEDURE;
  41. EntryType*=RECORD
  42. (* classes:
  43. 0: no Type
  44. 1: ObjectType
  45. 2: NilType
  46. 3: AnyType
  47. 4: ByteType
  48. 5: AddressType
  49. 6: SizeType
  50. 7: BooleanType
  51. 8: SetType
  52. 9: CharacterType
  53. 10: RangeType
  54. 11: SignedInteger
  55. 12: UnsignedIntegerType
  56. 13: FloatType
  57. 14: ComplexType
  58. 15: StringType
  59. 16: EnumerationType
  60. 17: ArrayType
  61. 18: MathArrayType
  62. 19: PointerType
  63. 20: PortType
  64. 21: RecordType
  65. 22: CellType
  66. 23: ProcedureType
  67. *)
  68. class*: SHORTINT;
  69. (* size in bits *)
  70. size*: INTEGER;
  71. type*: ADDRESS; (* type descriptor or additional information *)
  72. END;
  73. FieldEntry*= RECORD
  74. name*: DynamicName; (*! change to dynamic name ? *)
  75. offset*: SIZE; (* offset of this type *)
  76. type*: EntryType;
  77. flags*: SET;
  78. END;
  79. FieldEntries*= POINTER TO ARRAY OF FieldEntry;
  80. ProcedureEntries*=POINTER TO ARRAY OF ProcedureEntry;
  81. ProcedureEntry*=RECORD
  82. name*: DynamicName;
  83. address*: ADDRESS;
  84. size*: SIZE;
  85. parameters*: FieldEntries;
  86. variables*: FieldEntries;
  87. procedures*: ProcedureEntries;
  88. returnType*: EntryType;
  89. END;
  90. TypeDesc* = POINTER TO RECORD (* ug: adapt constant TypeDescRecSize if this type is changed !!! *)
  91. descSize: LONGINT;
  92. sentinel: LONGINT; (* = MPO-4 *)
  93. tag*: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  94. flags*: SET;
  95. mod*: Module; (* hint only, because module may have been freed (at Heaps.ModOfs) *)
  96. name*: Name;
  97. fields*: POINTER TO ARRAY OF FieldEntry;
  98. procedures*: POINTER TO ARRAY OF ProcedureEntry;
  99. END;
  100. ExceptionTableEntry* = RECORD
  101. pcFrom*: ADDRESS;
  102. pcTo*: ADDRESS;
  103. pcHandler*: ADDRESS;
  104. END;
  105. ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
  106. ProcTableEntry* = RECORD
  107. pcFrom*, pcLimit*, pcStatementBegin*, pcStatementEnd*: ADDRESS;
  108. noPtr*: LONGINT;
  109. END;
  110. ProcTable* = POINTER TO ARRAY OF ProcTableEntry;
  111. PtrTable* = POINTER TO ARRAY OF ADDRESS;
  112. ProcOffsetEntry* = RECORD
  113. data*: ProcTableEntry; (* code offsets of procedures *)
  114. startIndex*: LONGINT; (* index into global ptrOffsets table *)
  115. END;
  116. ProcOffsetTable* = POINTER TO ARRAY OF ProcOffsetEntry;
  117. Module* = OBJECT (Heaps.RootObject) (* cf. Linker0 & Heaps.WriteType *)
  118. VAR
  119. next*: Module; (** once a module is published, all fields are read-only *)
  120. name*: Name;
  121. init, published: BOOLEAN;
  122. refcnt*: LONGINT; (* counts loaded modules that import this module *)
  123. sb*: ADDRESS; (* reference address between constants and local variables *)
  124. entry*: POINTER TO ARRAY OF ADDRESS;
  125. command*: POINTER TO ARRAY OF Command;
  126. ptrAdr*: POINTER TO ARRAY OF ADDRESS;
  127. typeInfo*: POINTER TO ARRAY OF TypeDesc; (* traced explicitly in FindRoots *)
  128. module*: POINTER TO ARRAY OF Module; (* imported modules: for reference counting *)
  129. procTable*: ProcTable; (* information inserted by loader, removed after use in Publish *)
  130. ptrTable*: PtrTable; (* information inserted by loader, removed after use in Publish *)
  131. data*, code*, staticTypeDescs* (* ug *), refs*: Bytes;
  132. export*: ExportDesc;
  133. term*: TerminationHandler;
  134. exTable*: ExceptionTable;
  135. noProcs*: LONGINT; (* used for removing proc offsets when unloading module *)
  136. firstProc*: ADDRESS; (* procedure with lowest PC in module, also used for unloading *)
  137. maxPtrs*: LONGINT;
  138. crc*: LONGINT;
  139. body*: PROCEDURE;
  140. PROCEDURE FindRoots; (* override *)
  141. VAR i: LONGINT; ptr: ANY; (* moduleName: Name; *) false: BOOLEAN;
  142. BEGIN
  143. false := FALSE; IF false THEN BEGIN{EXCLUSIVE} END END; (* trick to make a module a protected record ... *)
  144. IF published THEN (* mark global pointers *)
  145. (* moduleName := name; *)
  146. FOR i := 0 TO LEN(ptrAdr) - 1 DO
  147. SYSTEM.GET (ptrAdr[i], ptr);
  148. IF ptr # NIL THEN Heaps.Mark(ptr) END
  149. END;
  150. Heaps.AddRootObject(next);
  151. (* all other fields are being traversed by Mark of the Garbage Collector *)
  152. END;
  153. END FindRoots;
  154. END Module;
  155. LoaderProc* = PROCEDURE (CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT;
  156. VAR msg: ARRAY OF CHAR): Module; (** load an object file *)
  157. VAR
  158. extension-: ARRAY MaxObjFormats, 8 OF CHAR;
  159. loader: ARRAY MaxObjFormats OF LoaderProc;
  160. numLoaders: LONGINT;
  161. kernelProc*: ARRAY 11 OF ADDRESS; (** kernel call addresses for loader *)
  162. freeRoot*: Module; (** list of freed modules (temporary) *)
  163. (* the following two variables are initialized by Linker *)
  164. root-: Module; (** list of modules (read-only) *)
  165. initBlock: ANY; (* placeholder - anchor for module init code (initialized by linker) *)
  166. procOffsets-: ProcOffsetTable; (* global table containing procedure code offsets and pointer offsets, sorted in ascending order of procedure code offsets *)
  167. numProcs: LONGINT; (* number of entries in procOffsets *)
  168. ptrOffsets-: PtrTable;
  169. numPtrs: LONGINT;
  170. shutdown*: LONGINT; (** None, Reboot, PowerDown *)
  171. trace: BOOLEAN;
  172. register: RECORD
  173. first, last: Module;
  174. END;
  175. (** Register a module loader. *)
  176. PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  177. BEGIN
  178. Machine.Acquire(Machine.Modules);
  179. ASSERT(numLoaders < MaxObjFormats);
  180. loader[numLoaders] := proc;
  181. COPY(ext, extension[numLoaders]);
  182. ASSERT(ext = extension[numLoaders]); (* no overflow *)
  183. INC(numLoaders);
  184. Machine.Release(Machine.Modules)
  185. END AddLoader;
  186. (** Remove a module loader. *)
  187. PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  188. VAR i, j: LONGINT;
  189. BEGIN
  190. Machine.Acquire(Machine.Modules);
  191. i := 0;
  192. WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
  193. IF i # numLoaders THEN
  194. FOR j := i TO numLoaders - 2 DO
  195. loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
  196. END;
  197. loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
  198. DEC(numLoaders)
  199. END;
  200. Machine.Release(Machine.Modules)
  201. END RemoveLoader;
  202. (** Append string from to to, truncating on overflow. *)
  203. PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
  204. VAR i, j, m: LONGINT;
  205. BEGIN
  206. j := 0; WHILE to[j] # 0X DO INC(j) END;
  207. m := LEN(to)-1;
  208. i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
  209. to[j] := 0X
  210. END Append;
  211. (** Add a module to the pool of accessible modules, or return named module. *)
  212. PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
  213. VAR n: Module; i: LONGINT; a: ANY;
  214. BEGIN
  215. (*
  216. ASSERT((m.code # NIL) & (LEN(m.code^) > 0));
  217. *)
  218. Machine.Acquire(Machine.Modules);
  219. n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
  220. IF n # NIL THEN (* module with same name exists, return it and ignore new m *)
  221. m := n; new := FALSE
  222. ELSE
  223. IF TraceBoot THEN
  224. Machine.Acquire(Machine.TraceOutput);
  225. Trace.String("publish "); Trace.String(m.name);
  226. (*
  227. a := m;
  228. IF a IS Heaps.RootObject THEN Trace.String(" IS RootObj") END;
  229. IF a IS Module THEN Trace.String(" IS Module"); END;
  230. *)
  231. Trace.Ln;
  232. Machine.Release(Machine.TraceOutput);
  233. END;
  234. m.published := TRUE;
  235. m.next := root; root := m;
  236. m.refcnt := 0;
  237. (*! reactivate: does not work with statically linked image
  238. SortProcTable(m);
  239. InsertProcOffsets(m.procTable, m.ptrTable, m.maxPtrs);
  240. (*! yes: used, cf. ThisModuleByAdr *)
  241. m.procTable := NIL; m.ptrTable := NIL; (* not used any more as entered in global variable *)
  242. *)
  243. IF m.module # NIL THEN
  244. FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
  245. END;
  246. new := TRUE;
  247. END;
  248. Machine.Release(Machine.Modules)
  249. END Publish;
  250. (*
  251. (* runtime call for new compiler -- called by body of loaded module *)
  252. PROCEDURE PublishThis*(m: Module): BOOLEAN;
  253. VAR new: BOOLEAN; i:LONGINT; module: Module;
  254. BEGIN
  255. IF m = SELF THEN
  256. RETURN Runtime.InsertModule(SYSTEM.VAL(ADDRESS,m))
  257. END;
  258. Publish(m,new);
  259. RETURN new
  260. END PublishThis;
  261. *)
  262. PROCEDURE Initialize*(VAR module: Module);
  263. VAR new: BOOLEAN;
  264. BEGIN
  265. Publish (module, new);
  266. IF new THEN
  267. IF module.body # NIL THEN
  268. Machine.FlushDCacheRange(ADDRESSOF(module.code[0]), LEN(module.code));
  269. module.body
  270. END;
  271. module.init := TRUE;
  272. END;
  273. END Initialize;
  274. VAR callagain: BOOLEAN;
  275. PROCEDURE Initialize0*(module: Module);
  276. VAR new: BOOLEAN;
  277. BEGIN
  278. (*TRACE(module.name);*)
  279. (* module MUST have been removed from register list and must not have been initialized yet *)
  280. ASSERT(module.next = NIL);
  281. Publish (module, new);
  282. callagain := FALSE;
  283. IF new THEN
  284. IF module.name = "Objects" THEN
  285. callagain := TRUE;
  286. module.init := TRUE;
  287. END;
  288. (*
  289. Trace.Memory(SYSTEM.VAL(ADDRESS, module), 256);
  290. TRACE(module, module.name, module.body);
  291. TRACE(module);
  292. TRACE(ADDRESS OF module.next);
  293. TRACE(ADDRESS OF module.name);
  294. TRACE(ADDRESS OF module.init);
  295. TRACE(ADDRESS OF module.published);
  296. TRACE(ADDRESS OF module.body);
  297. TRACE(ADDRESS OF module.refcnt);
  298. TRACE(ADDRESS OF module.sb);
  299. TRACE(ADDRESS OF module.entry);
  300. TRACE(ADDRESS OF module.command);
  301. TRACE(ADDRESS OF module.ptrAdr);
  302. TRACE(ADDRESS OF module.typeInfo);
  303. TRACE(ADDRESS OF module.module);
  304. TRACE(ADDRESS OF module.procTable);
  305. TRACE(ADDRESS OF module.ptrTable);
  306. TRACE(ADDRESS OF module.data);
  307. TRACE(ADDRESS OF module.code);
  308. TRACE(ADDRESS OF module.staticTypeDescs);
  309. TRACE(ADDRESS OF module.refs);
  310. TRACE(ADDRESS OF module.export);
  311. TRACE(ADDRESS OF module.term);
  312. TRACE(ADDRESS OF module.exTable);
  313. TRACE(ADDRESS OF module.noProcs);
  314. TRACE(ADDRESS OF module.firstProc);
  315. TRACE(ADDRESS OF module.maxPtrs);
  316. TRACE(ADDRESS OF module.crc);
  317. TRACE(ADDRESS OF module.body);
  318. *)
  319. IF module.body # NIL THEN module.body END;
  320. IF callagain THEN
  321. PublishRegisteredModules (* does not return on intel architecture. Returns on ARM but looses procedure stack frame: we are not allowed to refer to local variables after this *)
  322. ELSE
  323. module.init := TRUE;
  324. END;
  325. END;
  326. END Initialize0;
  327. (** Return the named module or NIL if it is not loaded yet. *)
  328. PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
  329. VAR m: Module;
  330. BEGIN
  331. Machine.Acquire(Machine.Modules);
  332. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  333. Machine.Release(Machine.Modules);
  334. RETURN m
  335. END ModuleByName;
  336. (* Generate a module file name. *)
  337. PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  338. VAR i, j: LONGINT;
  339. BEGIN
  340. i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
  341. j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
  342. fileName[i] := 0X
  343. END GetFileName;
  344. PROCEDURE SortProcTable(m: Module);
  345. VAR i, j, min : LONGINT;
  346. PROCEDURE Max(a,b: LONGINT): LONGINT;
  347. BEGIN
  348. IF a > b THEN RETURN a ELSE RETURN b END;
  349. END Max;
  350. PROCEDURE SwapProcTableEntries(p, q : LONGINT);
  351. VAR procentry : ProcTableEntry;
  352. k, i, basep, baseq: LONGINT; ptr: SIZE;
  353. BEGIN
  354. k := Max(m.procTable[p].noPtr, m.procTable[q].noPtr);
  355. IF k > 0 THEN (* swap entries in ptrTable first *)
  356. basep := p * m.maxPtrs; baseq := q * m.maxPtrs;
  357. FOR i := 0 TO k - 1 DO
  358. ptr := m.ptrTable[basep + i];
  359. m.ptrTable[basep + i] := m.ptrTable[baseq + i];
  360. m.ptrTable[baseq + i] := ptr
  361. END
  362. END;
  363. procentry := m.procTable[p];
  364. m.procTable[p] := m.procTable[q];
  365. m.procTable[q] := procentry
  366. END SwapProcTableEntries;
  367. PROCEDURE NormalizePointerArray;
  368. VAR ptrTable: PtrTable; i,j,k: LONGINT;
  369. BEGIN
  370. NEW(ptrTable, m.maxPtrs*m.noProcs);
  371. k := 0;
  372. FOR i := 0 TO LEN(m.procTable)-1 DO
  373. FOR j := 0 TO m.procTable[i].noPtr-1 DO
  374. ptrTable[i*m.maxPtrs+j] := m.ptrTable[k];
  375. INC(k);
  376. END;
  377. END;
  378. m.ptrTable := ptrTable;
  379. END NormalizePointerArray;
  380. BEGIN
  381. NormalizePointerArray;
  382. FOR i := 0 TO m.noProcs - 2 DO
  383. min := i;
  384. FOR j := i + 1 TO m.noProcs - 1 DO
  385. IF m.procTable[j].pcFrom < m.procTable[min].pcFrom THEN min:= j END
  386. END;
  387. IF min # i THEN SwapProcTableEntries(i, min) END
  388. END
  389. END SortProcTable;
  390. PROCEDURE SelectionSort(exTable: ExceptionTable);
  391. VAR
  392. p, q, min: LONGINT;
  393. entry: ExceptionTableEntry;
  394. BEGIN
  395. FOR p := 0 TO LEN(exTable) - 2 DO
  396. min := p;
  397. FOR q := p + 1 TO LEN(exTable) - 1 DO
  398. IF exTable[min].pcFrom > exTable[q].pcFrom THEN min := q END;
  399. entry := exTable[min]; exTable[min] := exTable[p]; exTable[p] := entry;
  400. END
  401. END
  402. END SelectionSort;
  403. (** Load the module if it is not already loaded. *) (* Algorithm J. Templ, ETHZ, 1994 *)
  404. PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Module;
  405. TYPE Body = PROCEDURE;
  406. VAR m, p: Module; fileName: ARRAY 64 OF CHAR; body: Body; new: BOOLEAN; i: LONGINT;
  407. BEGIN
  408. res := Ok; msg[0] := 0X; m := ModuleByName(name);
  409. IF m = NIL THEN
  410. IF trace THEN
  411. Machine.Acquire (Machine.TraceOutput);
  412. Trace.String(">"); Trace.StringLn (name);
  413. Machine.Release (Machine.TraceOutput);
  414. END;
  415. IF numLoaders = 0 THEN
  416. res := NoLoader; m := NIL;
  417. ELSE
  418. i:= 0;
  419. REPEAT
  420. GetFileName(name, extension[i], fileName);
  421. m := loader[i](name, fileName, res, msg);
  422. INC(i);
  423. UNTIL (m # NIL) OR (i=numLoaders);
  424. END;
  425. IF trace THEN
  426. Machine.Acquire (Machine.TraceOutput);
  427. Trace.String("?"); Trace.StringLn (name);
  428. Machine.Release (Machine.TraceOutput);
  429. END;
  430. p := m;
  431. IF (m # NIL) & ~m.published THEN (* no race on m.published, as update is done below in Publish *)
  432. Initialize(m);
  433. END;
  434. IF trace THEN
  435. Machine.Acquire (Machine.TraceOutput);
  436. IF m = NIL THEN
  437. Trace.String("could not load "); Trace.StringLn(name)
  438. ELSIF ~m.published THEN
  439. Trace.String("not published "); Trace.StringLn(name)
  440. ELSE
  441. Trace.String("<"); Trace.StringLn (name);
  442. END;
  443. Machine.Release (Machine.TraceOutput);
  444. END;
  445. END;
  446. RETURN m
  447. END ThisModule;
  448. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. Non-blocking version for reflection *)
  449. PROCEDURE ThisModuleByAdr0*(pc: ADDRESS): Module;
  450. VAR m: Module; cbase, dbase: ADDRESS; i: LONGINT; found: BOOLEAN; list: LONGINT;
  451. BEGIN
  452. list := 0; found := FALSE;
  453. REPEAT
  454. CASE list OF
  455. 0: m := root
  456. |1: m := freeRoot
  457. END;
  458. WHILE (m # NIL) & ~found DO
  459. IF m.procTable # NIL THEN
  460. i := 0;
  461. WHILE ~found & (i<LEN(m.procTable)) DO
  462. IF (m.procTable[i].pcFrom <= pc) & (pc <m.procTable[i].pcLimit) THEN
  463. found := TRUE;
  464. END;
  465. INC(i);
  466. END;
  467. END;
  468. IF ~found THEN
  469. m := m.next;
  470. END;
  471. END;
  472. INC(list)
  473. UNTIL found OR (list=2);
  474. RETURN m
  475. END ThisModuleByAdr0;
  476. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. *)
  477. PROCEDURE ThisModuleByAdr*(pc: ADDRESS): Module;
  478. VAR m: Module; cbase, dbase: ADDRESS; i: LONGINT; found: BOOLEAN; list: LONGINT;
  479. BEGIN
  480. Machine.Acquire(Machine.Modules);
  481. m := ThisModuleByAdr0(pc);
  482. Machine.Release(Machine.Modules);
  483. RETURN m
  484. END ThisModuleByAdr;
  485. CONST ModuleInitTimeout = HUGEINT(3000000000); (* Timeout for waiting until a module get initialized, 3 seconds for 1 GHz CPU *)
  486. (* Retrieve a procedure given a module name, the procedure name and some type information (kernel call) *)
  487. PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  488. VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT; t: HUGEINT;
  489. BEGIN
  490. module := ThisModule(moduleName, res, ignoreMsg);
  491. IF (res = Ok) THEN
  492. (*!
  493. module body must have been called (see note at the end of this module);
  494. return NIL if the module does not get initialized within the specified timeout
  495. *)
  496. IF ~module.init THEN
  497. t := Machine.GetTimer();
  498. WHILE ~module.init & (Machine.GetTimer() - t < ModuleInitTimeout) DO END;
  499. IF ~module.init THEN (* timeout has expired *)
  500. RETURN;
  501. END;
  502. END;
  503. Machine.Acquire(Machine.Modules);
  504. i := 0; entryAdr := Heaps.NilVal;
  505. WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
  506. IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
  507. entryAdr := module.command[i].entryAdr;
  508. END;
  509. INC(i)
  510. END;
  511. Machine.Release(Machine.Modules);
  512. END;
  513. END GetProcedure;
  514. (** Return the named type *)
  515. PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
  516. VAR i: LONGINT; type: TypeDesc;
  517. BEGIN
  518. Machine.Acquire(Machine.Modules);
  519. i := 0;
  520. WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
  521. IF i = LEN(m.typeInfo) THEN
  522. type := NIL
  523. ELSE
  524. type := m.typeInfo[i]
  525. END;
  526. Machine.Release(Machine.Modules);
  527. RETURN type
  528. END ThisType;
  529. PROCEDURE ThisTypeByAdr*(adr: ADDRESS; VAR m: Module; VAR t: TypeDesc);
  530. BEGIN
  531. IF adr # 0 THEN
  532. Machine.Acquire(Machine.Modules);
  533. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  534. t := SYSTEM.VAL(TypeDesc, adr);
  535. m := t.mod;
  536. Machine.Release(Machine.Modules)
  537. ELSE
  538. m := NIL; t := NIL
  539. END
  540. END ThisTypeByAdr;
  541. (** create a new object given its type descriptor *)
  542. PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
  543. VAR x : ANY;
  544. BEGIN
  545. Heaps.NewRec(x, SYSTEM.VAL (ADDRESS, t.tag), isRealtime);
  546. RETURN x;
  547. END NewObj;
  548. (** return the type descriptor of an object *)
  549. PROCEDURE TypeOf*(obj : ANY): TypeDesc;
  550. VAR
  551. m : Module;
  552. t : TypeDesc;
  553. adr : ADDRESS;
  554. BEGIN
  555. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.TypeDescOffset, adr);
  556. ThisTypeByAdr(adr, m, t);
  557. RETURN t;
  558. END TypeOf;
  559. PROCEDURE FindPos(key: ADDRESS; VAR pos: LONGINT): BOOLEAN;
  560. VAR l, r, x: LONGINT; isHit: BOOLEAN;
  561. BEGIN
  562. IF numProcs > 0 THEN
  563. l := 0; r := numProcs - 1;
  564. REPEAT
  565. x := (l + r) DIV 2;
  566. IF key < procOffsets[x].data.pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  567. isHit := ((procOffsets[x].data.pcFrom <= key) & (key < procOffsets[x].data.pcLimit));
  568. UNTIL isHit OR (l > r);
  569. IF isHit THEN
  570. pos := x;
  571. RETURN TRUE
  572. END;
  573. END;
  574. RETURN FALSE
  575. END FindPos;
  576. (** searches for the given pc in the global ProcKeyTable, if found it returns the corresponding data element *)
  577. PROCEDURE FindProc*(pc: ADDRESS; VAR data: ProcTableEntry; VAR index: LONGINT; VAR success: BOOLEAN);
  578. VAR x: LONGINT;
  579. BEGIN
  580. success := FindPos(pc, x);
  581. IF success THEN
  582. data := procOffsets[x].data;
  583. index := procOffsets[x].startIndex
  584. END
  585. END FindProc;
  586. PROCEDURE FindInsertionPos(VAR entry: ProcTableEntry; VAR pos: LONGINT): BOOLEAN;
  587. VAR l, r, x: LONGINT; success, isHit: BOOLEAN;
  588. BEGIN
  589. pos := -1;
  590. success := FALSE;
  591. IF numProcs = 0 THEN (* empty table *)
  592. pos := 0; success := TRUE
  593. ELSE
  594. l := 0; r := numProcs - 1;
  595. REPEAT
  596. x := (l + r) DIV 2;
  597. IF entry.pcLimit < procOffsets[x].data.pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  598. isHit := ((x = 0) OR (procOffsets[x - 1].data.pcLimit <= entry.pcFrom)) & (entry.pcLimit <= procOffsets[x].data.pcFrom);
  599. UNTIL isHit OR (l > r);
  600. IF isHit THEN
  601. pos := x; success := TRUE
  602. ELSE
  603. IF (x = numProcs - 1) & (procOffsets[x].data.pcLimit <= entry.pcFrom) THEN
  604. pos := x + 1; success := TRUE
  605. END
  606. END
  607. END;
  608. RETURN success
  609. END FindInsertionPos;
  610. PROCEDURE NumTotalPtrs(procTable: ProcTable): LONGINT;
  611. VAR i, num: LONGINT;
  612. BEGIN
  613. num := 0;
  614. IF procTable # NIL THEN
  615. FOR i := 0 TO LEN(procTable) - 1 DO
  616. num := num + procTable[i].noPtr
  617. END;
  618. END;
  619. RETURN num
  620. END NumTotalPtrs;
  621. (* insert the procedure code offsets and pointer offsets of a single module into the global table *)
  622. PROCEDURE InsertProcOffsets(procTable: ProcTable; ptrTable: PtrTable; maxPtr: LONGINT);
  623. VAR success: BOOLEAN; i, j, pos, poslast, newLen, num,numberPointer: LONGINT;
  624. temp: ADDRESS;
  625. newProcOffsets: ProcOffsetTable; newPtrOffsets: PtrTable;
  626. ptrOfsLen,procOfsLen: LONGINT;
  627. BEGIN
  628. (* this procedure is called by procedure Publish only and is protected by the Machine.Modules lock *)
  629. IF procTable=NIL THEN RETURN END;
  630. IF ptrTable=NIL THEN RETURN END;
  631. IF LEN(procTable) > 0 THEN
  632. IF procOffsets = NIL THEN procOfsLen := 0 ELSE procOfsLen := LEN(procOffsets) END;
  633. IF numProcs + LEN(procTable) > procOfsLen THEN
  634. newLen := procOfsLen + InitTableLen;
  635. WHILE numProcs + LEN(procTable) > newLen DO newLen := newLen + InitTableLen END;
  636. NEW(newProcOffsets, newLen);
  637. FOR i := 0 TO numProcs - 1 DO
  638. newProcOffsets[i] := procOffsets[i]
  639. END;
  640. procOffsets := newProcOffsets
  641. END;
  642. num := NumTotalPtrs(procTable);
  643. IF ptrOffsets = NIL THEN ptrOfsLen := 0 ELSE ptrOfsLen := LEN(ptrOffsets) END;
  644. IF numPtrs + num > ptrOfsLen THEN
  645. newLen := ptrOfsLen + InitPtrTableLen;
  646. WHILE numPtrs + num > newLen DO newLen := newLen + InitPtrTableLen END;
  647. NEW(newPtrOffsets, newLen);
  648. FOR i := 0 TO numPtrs - 1 DO
  649. newPtrOffsets[i] := ptrOffsets[i]
  650. END;
  651. ptrOffsets := newPtrOffsets
  652. END;
  653. success := FindInsertionPos(procTable[0], pos); success := success & FindInsertionPos(procTable[LEN(procTable) - 1], poslast);
  654. IF (~success) OR (pos # poslast) THEN Machine.Release(Machine.Modules); HALT(2001) END;
  655. FOR i := numProcs - 1 TO pos BY -1 DO procOffsets[i + LEN(procTable)] := procOffsets[i] END;
  656. numberPointer := 0;
  657. FOR i := 0 TO LEN(procTable) - 1 DO
  658. procOffsets[pos + i].data := procTable[i];
  659. procOffsets[pos + i].startIndex := numPtrs; (* this field is never accessed in case of procTable[i].noPtr = 0, so we may as well put numPtrs in there *)
  660. FOR j := 0 TO procTable[i].noPtr - 1 DO
  661. (*
  662. temp := ptrTable[numberPointer]; INC(numberPointer);
  663. *)
  664. temp := ptrTable[i * maxPtr + j];
  665. ptrOffsets[numPtrs + j] := temp;
  666. END;
  667. numPtrs := numPtrs + procTable[i].noPtr;
  668. END;
  669. numProcs := numProcs + LEN(procTable);
  670. END
  671. END InsertProcOffsets;
  672. (** deletes a sequence of entries given in procTable from the global procOffsets table - the table remains sorted,
  673. this procedure is called within AosLocks.AosModules, so no lock is taken here. *)
  674. PROCEDURE DeleteProcOffsets(firstProcPC: ADDRESS; noProcsInMod: LONGINT);
  675. VAR pos, i, noPtrsInMod, oldIndex: LONGINT; success: BOOLEAN;
  676. BEGIN
  677. IF noProcsInMod > 0 THEN
  678. success := FindPos(firstProcPC, pos);
  679. IF success THEN
  680. (* delete entries in ptrOffsets first *)
  681. noPtrsInMod := 0;
  682. FOR i := pos TO pos + noProcsInMod - 1 DO
  683. noPtrsInMod := noPtrsInMod + procOffsets[i].data.noPtr
  684. END;
  685. oldIndex := procOffsets[pos].startIndex;
  686. FOR i := procOffsets[pos].startIndex + noPtrsInMod TO numPtrs - 1 DO
  687. ptrOffsets[i - noPtrsInMod] := ptrOffsets[i]
  688. END;
  689. numPtrs := numPtrs - noPtrsInMod;
  690. (* delete entries in procOffsets *)
  691. FOR i := pos + noProcsInMod TO numProcs - 1 DO
  692. procOffsets[i - noProcsInMod] := procOffsets[i]
  693. END;
  694. numProcs := numProcs - noProcsInMod;
  695. (* adjust startIndex of procOffsets entries greater than those that have been deleted *)
  696. FOR i := 0 TO numProcs - 1 DO
  697. IF procOffsets[i].startIndex > oldIndex THEN
  698. procOffsets[i].startIndex := procOffsets[i].startIndex - noPtrsInMod
  699. END
  700. END;
  701. ELSE
  702. Trace.String("corrupt global procOffsets table"); Trace.Ln;
  703. Machine.Release(Machine.Modules);
  704. HALT(2000)
  705. END
  706. END
  707. END DeleteProcOffsets;
  708. (** Install procedure to execute when module is freed or shut down. The handler can distinguish the two cases by checking Modules.shutdown. If it is None, the module is being freed, otherwise the system is being shut down or rebooted. Only one handler may be installed per module. The last handler installed is active. *)
  709. PROCEDURE InstallTermHandler*(h: TerminationHandler);
  710. VAR m: Module;
  711. BEGIN
  712. m := ThisModuleByAdr(SYSTEM.VAL (ADDRESS, h));
  713. IF m # NIL THEN
  714. m.term := h (* overwrite existing handler, if any *)
  715. END
  716. END InstallTermHandler;
  717. (** Free a module. The module's termination handler, if any, is called first. Then all objects that have finalizers in this module are finalized (even if they are still reachable). Then the module's data and code are invalidated. *)
  718. PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR);
  719. VAR p, m: Module; term: TerminationHandler; i: LONGINT;
  720. BEGIN
  721. m := ModuleByName(name);
  722. IF (m # NIL) & (m.refcnt = 0) THEN (* will be freed below *)
  723. IF m.term # NIL THEN (* call termination handler *)
  724. term := m.term; m.term := NIL; term (* may trap *)
  725. END;
  726. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  727. END;
  728. res := Ok; msg[0] := 0X;
  729. Machine.Acquire(Machine.Modules);
  730. Trace.String("Acquired Machine.Modules x"); Trace.Ln;
  731. p := NIL; m := root;
  732. WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
  733. Trace.String("Acquired Machine.Modules y"); Trace.Ln;
  734. IF m # NIL THEN
  735. Trace.String("found module"); Trace.Ln;
  736. IF m.refcnt = 0 THEN (* free the module *)
  737. FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
  738. m.init := FALSE; (* disallow ThisCommand *)
  739. Append("?", m.name);
  740. (* move module to free list *)
  741. IF p = NIL THEN root := root.next ELSE p.next := m.next END;
  742. m.next := freeRoot; freeRoot := m;
  743. (* clear global pointers and code *)
  744. IF m.ptrAdr # NIL THEN
  745. Trace.String("ptradr del"); Trace.Ln;
  746. FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
  747. END;
  748. IF ClearCode & (m.code # NIL) THEN
  749. Trace.String("clear code"); Trace.Ln;
  750. FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
  751. END;
  752. Trace.String("clear code f"); Trace.Ln;
  753. (* remove references to module data *)
  754. m.published := FALSE;
  755. m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
  756. (* do not clear m.type or m.module, as old heap block tags might reference type descs indirectly. *) (* m.staticTypeDescs, m.typeInfo ??? *)
  757. (* do not clear m.data or m.code, as they are used in ThisModuleByAdr (for debugging). *)
  758. (* do not clear m.refs, as they are used in Traps (for debugging). *)
  759. m.export.dsc := NIL; m.exTable := NIL;
  760. (*Trace.String("delete proc offsets"); Trace.Ln;
  761. DeleteProcOffsets(m.firstProc, m.noProcs);
  762. *)
  763. ELSE
  764. res := 1901; (* can not free module in use *)
  765. COPY(name, msg); Append(" reference count not zero", msg)
  766. END
  767. ELSE
  768. res := 1902; (* module not found *)
  769. COPY(name, msg); Append(" not found", msg)
  770. END;
  771. Machine.Release(Machine.Modules)
  772. END FreeModule;
  773. (** Shut down all modules by calling their termination handlers and then call Machine.Shutdown. *)
  774. PROCEDURE Shutdown*(code: LONGINT);
  775. VAR m: Module; term: TerminationHandler;
  776. BEGIN
  777. IF code # None THEN
  778. LOOP
  779. Machine.Acquire(Machine.Modules);
  780. m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
  781. IF m # NIL THEN term := m.term; m.term := NIL END;
  782. Machine.Release(Machine.Modules);
  783. IF m = NIL THEN EXIT END;
  784. IF trace THEN
  785. Machine.Acquire (Machine.TraceOutput);
  786. Trace.String("TermHandler "); Trace.StringLn (m.name);
  787. Machine.Release (Machine.TraceOutput);
  788. END;
  789. term (* if this causes exception or hangs, another shutdown call will retry *)
  790. END;
  791. (* clean up finalizers *)
  792. m := root;
  793. WHILE m # NIL DO
  794. IF LEN(m.code)>0 THEN
  795. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  796. END;
  797. m := m.next
  798. END;
  799. IF trace THEN
  800. Machine.Acquire (Machine.TraceOutput);
  801. Trace.StringLn ("Modules.Shutdown finished");
  802. Machine.Release (Machine.TraceOutput);
  803. END;
  804. Machine.Shutdown(code = Reboot) (* does not return *)
  805. END
  806. END Shutdown;
  807. (* Is this PC handled in the corresponding module. deep = scan the whole stack. *)
  808. PROCEDURE IsExceptionHandled*(VAR pc, fp: ADDRESS; deep: BOOLEAN): BOOLEAN;
  809. VAR
  810. handler: ADDRESS;
  811. BEGIN
  812. IF deep THEN
  813. handler := GetExceptionHandler(pc);
  814. IF handler # -1 THEN (* Handler in the current PAF *)
  815. RETURN TRUE
  816. ELSE
  817. WHILE (fp # 0) & (handler = -1) DO
  818. SYSTEM.GET (fp + 4, pc);
  819. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  820. handler := GetExceptionHandler(pc);
  821. SYSTEM.GET (fp, fp) (* Unwind PAF *)
  822. END;
  823. IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
  824. END
  825. ELSE
  826. RETURN GetExceptionHandler(pc) # -1
  827. END
  828. END IsExceptionHandled;
  829. (* Is this PC handled in the corresponding module. If the PC is handled the PC of the
  830. handler is return else -1 is return. There is no problem concurrently accessing this
  831. procedure, there is only reading work. *)
  832. PROCEDURE GetExceptionHandler*(pc: ADDRESS): ADDRESS;
  833. VAR
  834. m: Module;
  835. PROCEDURE BinSearch(exTable: ExceptionTable; key: ADDRESS): ADDRESS;
  836. VAR
  837. x, l, r: LONGINT;
  838. BEGIN
  839. l := 0; r:=LEN(exTable) - 1;
  840. REPEAT
  841. x := (l + r) DIV 2;
  842. IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  843. UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
  844. IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
  845. RETURN exTable[x].pcHandler;
  846. ELSE
  847. RETURN -1;
  848. END
  849. END BinSearch;
  850. BEGIN
  851. m := ThisModuleByAdr(pc);
  852. IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
  853. RETURN BinSearch(m.exTable, pc);
  854. END;
  855. RETURN -1;
  856. END GetExceptionHandler;
  857. (** fof: to make custom solutions to the race process, described below, possible. This is not a solution to the generic problem !! *)
  858. PROCEDURE Initialized*(m: Module): BOOLEAN;
  859. BEGIN
  860. RETURN m.init;
  861. END Initialized;
  862. (** Return the specified kernel procedure address. *)
  863. PROCEDURE GetKernelProc*(num: LONGINT): ADDRESS;
  864. VAR adr: ADDRESS;
  865. BEGIN
  866. adr := kernelProc[253-num];
  867. ASSERT(adr # 0);
  868. RETURN adr
  869. END GetKernelProc;
  870. PROCEDURE Register- (module {UNTRACED}: Module);
  871. BEGIN {UNCOOPERATIVE, UNCHECKED}
  872. (*TRACE(module.name);*)
  873. IF register.first = NIL THEN
  874. register.first := module;
  875. ELSE
  876. register.last.next := module;
  877. END;
  878. register.last := module;
  879. END Register;
  880. PROCEDURE PublishRegisteredModules;
  881. VAR m {UNTRACED}, prev {UNTRACED}, cur {UNTRACED}: Module; module, import: SIZE;
  882. BEGIN
  883. WHILE register.first # NIL DO
  884. m := register.first;
  885. register.first := m.next;
  886. m.next := NIL;
  887. IF m.module # NIL THEN
  888. FOR import := 0 TO LEN (m.module) - 1 DO
  889. IF ~m.module[import].published THEN
  890. ASSERT(register.first # NIL);
  891. prev := NIL;
  892. cur := register.first;
  893. WHILE (cur # NIL) & (cur # m.module[import]) DO
  894. prev := cur;
  895. cur := cur.next
  896. END;
  897. (*ASSERT(cur = m.module[import]);*)
  898. ASSERT(cur = m.module[import]);
  899. IF prev = NIL THEN
  900. register.first := cur.next
  901. ELSE
  902. prev.next := cur.next;
  903. END;
  904. cur.next := NIL;
  905. Initialize0 (m.module[import]);
  906. END
  907. END;
  908. END;
  909. Initialize0 (m);
  910. END;
  911. END PublishRegisteredModules;
  912. (* procedure that will be called last in a linked kernel *)
  913. PROCEDURE {FINAL} Main;
  914. BEGIN
  915. (*Machine.Init;*)
  916. Trace.String("publish registered modules"); Trace.Ln;
  917. PublishRegisteredModules;
  918. END Main;
  919. PROCEDURE Init;
  920. VAR
  921. newArr: PROCEDURE (VAR p: ANY; elemTag: ADDRESS; numElems, numDims: SIZE; isRealtime: BOOLEAN);
  922. newSys: PROCEDURE (VAR p: ANY; size: SIZE; isRealtime: BOOLEAN);
  923. newRec: PROCEDURE (VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  924. getProcedure: PROCEDURE(CONST m, p : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  925. s: ARRAY 4 OF CHAR;
  926. module: Module; new: BOOLEAN; i: LONGINT;
  927. BEGIN
  928. (* root and initBlock are initialized by the linker *)
  929. shutdown := None;
  930. newArr := Heaps.NewArr;
  931. newSys := Heaps.NewSys;
  932. newRec := Heaps.NewRec;
  933. getProcedure := GetProcedure;
  934. kernelProc[0] := SYSTEM.VAL (ADDRESS, newRec); (* 253 *)
  935. kernelProc[1] := SYSTEM.VAL (ADDRESS, newSys); (* 252 *)
  936. kernelProc[2] := SYSTEM.VAL (ADDRESS, newArr); (* 251 *)
  937. kernelProc[3] := 0; (* 250 *)
  938. kernelProc[4] := 0; (* 249 *)
  939. kernelProc[5] := 0; (* 248 *)
  940. kernelProc[6] := 0; (* 247 *)
  941. kernelProc[7] := 0; (* 246 *)
  942. kernelProc[8] := 0; (* 245 *)
  943. kernelProc[9] := 0; (* 244 *)
  944. kernelProc[10] := SYSTEM.VAL(ADDRESS, getProcedure); (* 243 *)
  945. numLoaders := 0;
  946. freeRoot := NIL;
  947. Machine.GetConfig("TraceModules", s);
  948. trace := (s[0] = "1");
  949. (*
  950. FOR i := 0 TO Runtime.modules-1 DO
  951. module := SYSTEM.VAL(Module,Runtime.kernelModule[i]);
  952. IF TraceBoot THEN
  953. Trace.String("publishing module ");
  954. Trace.String(module.name); Trace.Ln;
  955. END;
  956. Publish(module,new);
  957. ASSERT(new,112233);
  958. END;
  959. *)
  960. (*
  961. module := SYSTEM.VAL(Module,SELF);
  962. Publish(module,new);
  963. *)
  964. END Init;
  965. BEGIN
  966. Init;
  967. END Modules.
  968. (*
  969. 19.03.1998 pjm Started
  970. 06.10.1998 pjm FreeModule
  971. Note:
  972. o GetProcedure race: process A calls ThisModule, the module is published, but before its body has finished executing, process B calls GetProcedure, causing the assert (m.init) to fail. Process B should perhaps wait in this case until the body has executed, or GetProcedure should return NIL (but that will just move the race to the user).
  973. *)