Modules.Mod 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. MODULE Modules; (** AUTHOR "pjm"; PURPOSE "Modules and types"; *)
  2. IMPORT SYSTEM, Trace, Machine, Heaps;
  3. #IF COOP THEN
  4. IMPORT Activities, Environment, GarbageCollector, Processors, Queues;
  5. #END
  6. CONST
  7. Ok* = 0;
  8. AddressSize = SIZEOF (ADDRESS); (* architecture dependent size of addresses in bytes *)
  9. MaxTags* = 16; (* in type descriptor *)
  10. (** type descriptor field offsets relative to root (middle) *)
  11. Tag0Ofs* = -AddressSize * 2; (** first tag *)
  12. Mth0Ofs* = Tag0Ofs - AddressSize*MaxTags; (** first method *)
  13. Ptr0Ofs* = AddressSize; (** first pointer offset *)
  14. MaxObjFormats = 5; (* maximum number of object file formats installed *)
  15. (** flags in TypeDesc, RoundUp(log2(MaxTags)) low bits reserved for extLevel *)
  16. ProtTypeBit* = Heaps.ProtTypeBit;
  17. None* = 0; PowerDown* = 1; Reboot* = 2;
  18. ClearCode = TRUE;
  19. DefaultContext* = "A2";
  20. NoLoader=3400;
  21. TraceBoot=FALSE;
  22. (* flags *)
  23. PreciseGC* = 0;
  24. TYPE
  25. (* definitions for object-model loader support *)
  26. Name* = ARRAY 32 OF CHAR;
  27. (* the correponding name array is protected from being GCed via module's internal pointer arrray
  28. compiler generated!
  29. *)
  30. DynamicName* = POINTER {UNSAFE,UNTRACED} TO ARRAY 256 OF CHAR;
  31. Command* = RECORD
  32. (* Fields exported for initialization by loader/linker only! Consider read-only! *)
  33. name*: Name; (* name of the procedure *)
  34. argTdAdr*, retTdAdr* : ADDRESS; (* address of type descriptors of argument and return type, 0 if no type *)
  35. entryAdr* : ADDRESS; (* entry address of procedure *)
  36. END;
  37. ExportDesc* = RECORD
  38. fp*: ADDRESS;
  39. name* {UNTRACED}: DynamicName;
  40. adr*: ADDRESS;
  41. exports*: LONGINT; (* number of exports referenced by ExportArray *)
  42. dsc* {UNTRACED}: ExportArray; (* pointer to memory containing a raw array with "exports" entries *)
  43. END;
  44. ExportArray* = POINTER {UNSAFE,UNTRACED} TO ARRAY OF ExportDesc;
  45. Bytes* = POINTER TO ARRAY OF CHAR;
  46. TerminationHandler* = PROCEDURE;
  47. (* all implicit or explicit pointers in the subsequent data structures are protected with one pointer array
  48. *)
  49. TypeDesc* = POINTER TO RECORD
  50. descSize-: SIZE;
  51. sentinel-: LONGINT; (* = MPO-4 *)
  52. tag-: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  53. flags-: SET;
  54. mod- {UNTRACED}: Module; (* hint only, because module may have been freed (at Heaps.ModOfs) *)
  55. name-: Name;
  56. refsOffset-: SIZE;
  57. END;
  58. ExceptionTableEntry* = RECORD
  59. pcFrom*: ADDRESS;
  60. pcTo*: ADDRESS;
  61. pcHandler*: ADDRESS;
  62. END;
  63. ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
  64. ProcedureDescPointer* = POINTER TO ProcedureDesc;
  65. ProcedureDesc*= RECORD
  66. pcFrom-, pcLimit-: ADDRESS;
  67. offsets- {UNTRACED}: POINTER TO ARRAY OF ADDRESS;
  68. END;
  69. ProcedureDescs* = POINTER TO ARRAY OF ProcedureDescPointer;
  70. Module* = OBJECT (Heaps.RootObject) (* cf. Linker0 & Heaps.WriteType *)
  71. VAR
  72. next*: Module; (** once a module is published, all fields are read-only *)
  73. name*: Name;
  74. init, published: BOOLEAN;
  75. refcnt*: LONGINT; (* counts loaded modules that import this module *)
  76. sb*: ADDRESS; (* reference address between constants and local variables *)
  77. entry*: POINTER TO ARRAY OF ADDRESS;
  78. command*: POINTER TO ARRAY OF Command;
  79. ptrAdr*: POINTER TO ARRAY OF ADDRESS; (* traced explicitly in FindRoots *)
  80. typeInfo*: POINTER TO ARRAY OF TypeDesc;
  81. module*: POINTER TO ARRAY OF Module; (* imported modules: for reference counting *)
  82. procTable*: ProcedureDescs; (* information inserted by loader, sorted by pc after loading *)
  83. data*, code*, staticTypeDescs* (* ug *), refs*: Bytes;
  84. export*: ExportDesc;
  85. term*: TerminationHandler;
  86. exTable*: ExceptionTable;
  87. (* internal pointer array: to protect internal data structures from being GCed *)
  88. internal-: POINTER TO ARRAY OF ANY;
  89. crc*: LONGINT;
  90. body*: PROCEDURE;
  91. flags*: SET; (* e.g. compilation flags *)
  92. #IF ~COOP THEN
  93. PROCEDURE FindRoots*; (* override *)
  94. VAR i: LONGINT; ptr {UNTRACED}: ANY; false: BOOLEAN;
  95. VAR name: Name;
  96. BEGIN
  97. name := SELF.name;
  98. false := FALSE; IF false THEN BEGIN{EXCLUSIVE} END END; (* trick to make a module a protected record ... *)
  99. IF published THEN (* mark global pointers *)
  100. FOR i := 0 TO LEN(ptrAdr) - 1 DO
  101. SYSTEM.GET (ptrAdr[i], ptr);
  102. IF ptr # NIL THEN Heaps.Mark(ptr) END
  103. END;
  104. Heaps.AddRootObject(next);
  105. (* all other fields are being traversed by Mark of the Garbage Collector *)
  106. END;
  107. END FindRoots;
  108. #END
  109. END Module;
  110. LoaderProc* = PROCEDURE (CONST name, fileName: ARRAY OF CHAR; VAR res: WORD;
  111. VAR msg: ARRAY OF CHAR): Module; (** load an object file *)
  112. VAR
  113. extension-: ARRAY MaxObjFormats, 8 OF CHAR;
  114. loader: ARRAY MaxObjFormats OF LoaderProc;
  115. numLoaders: LONGINT;
  116. freeRoot*: Module; (** list of freed modules (temporary) *)
  117. root-: Module; (** list of modules (read-only) *)
  118. shutdown*: LONGINT; (** None, Reboot, PowerDown *)
  119. trace: BOOLEAN;
  120. register: RECORD
  121. first {UNTRACED}, last {UNTRACED}: Module;
  122. END;
  123. (* global sorted table of all procedures , basically for GC *)
  124. procedureDescriptors-: ProcedureDescs;
  125. (** Register a module loader. *)
  126. PROCEDURE Halt(CONST reason: ARRAY OF CHAR);
  127. BEGIN
  128. HALT(999);
  129. END Halt;
  130. PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  131. BEGIN
  132. Machine.Acquire(Machine.Modules);
  133. ASSERT(numLoaders < MaxObjFormats);
  134. loader[numLoaders] := proc;
  135. COPY(ext, extension[numLoaders]);
  136. ASSERT(ext = extension[numLoaders]); (* no overflow *)
  137. INC(numLoaders);
  138. Machine.Release(Machine.Modules)
  139. END AddLoader;
  140. (** Remove a module loader. *)
  141. PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
  142. VAR i, j: LONGINT;
  143. BEGIN
  144. Machine.Acquire(Machine.Modules);
  145. i := 0;
  146. WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
  147. IF i # numLoaders THEN
  148. FOR j := i TO numLoaders - 2 DO
  149. loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
  150. END;
  151. loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
  152. DEC(numLoaders)
  153. END;
  154. Machine.Release(Machine.Modules)
  155. END RemoveLoader;
  156. (** Append string from to to, truncating on overflow. *)
  157. PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
  158. VAR i, j, m: LONGINT;
  159. BEGIN
  160. j := 0; WHILE to[j] # 0X DO INC(j) END;
  161. m := LEN(to)-1;
  162. i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
  163. to[j] := 0X
  164. END Append;
  165. (** Add a module to the pool of accessible modules, or return named module. *)
  166. PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
  167. VAR n: Module; i: LONGINT; name: Name;
  168. BEGIN
  169. Machine.Acquire(Machine.Modules);
  170. n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
  171. IF n # NIL THEN (* module with same name exists, return it and ignore new m *)
  172. m := n; new := FALSE
  173. ELSE
  174. IF TraceBoot OR trace THEN
  175. Machine.Acquire(Machine.TraceOutput);
  176. Trace.String("publish "); Trace.String(m.name);
  177. Trace.Ln;
  178. Machine.Release(Machine.TraceOutput);
  179. END;
  180. Unregister(m);
  181. m.published := TRUE;
  182. m.next := root; root := m;
  183. m.refcnt := 0;
  184. SortExceptionTable(m.exTable);
  185. SortProcedureDescs(m.procTable);
  186. IF m.module # NIL THEN
  187. FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
  188. END;
  189. new := TRUE;
  190. END;
  191. Machine.Release(Machine.Modules);
  192. #IF ~COOP THEN
  193. IF (Heaps.GCType = Heaps.MetaDataForStackGC) & ~(PreciseGC IN m.flags) THEN
  194. name := m.name;
  195. Halt("Module does not provide metadata required by the GC.");
  196. END;
  197. #END
  198. END Publish;
  199. PROCEDURE Initialize*(VAR module: Module);
  200. VAR new: BOOLEAN; import: LONGINT;
  201. BEGIN
  202. IF (module = NIL) THEN RETURN END;
  203. Publish (module, new);
  204. IF new THEN
  205. FOR import := 0 TO LEN (module.module) - 1 DO
  206. IF ~module.module[import].published THEN
  207. ASSERT(register.first # NIL);
  208. Initialize(module.module[import]);
  209. END
  210. END;
  211. IF (module.code # NIL) & (LEN(module.code) > 0) THEN
  212. Machine.FlushDCacheRange(ADDRESSOF(module.code[0]), LEN(module.code));
  213. END;
  214. IF module.body # NIL THEN
  215. module.body
  216. END;
  217. module.init := TRUE;
  218. END;
  219. END Initialize;
  220. VAR callagain: BOOLEAN;
  221. PROCEDURE Initialize0*(module: Module);
  222. VAR new: BOOLEAN;
  223. BEGIN
  224. (*TRACE(module.name);*)
  225. (* module MUST have been removed from register list and must not have been initialized yet *)
  226. (* ASSERT(module.next = NIL); *)
  227. Publish (module, new);
  228. callagain := FALSE;
  229. IF new THEN
  230. IF module.name = "Objects" THEN
  231. callagain := TRUE;
  232. module.init := TRUE;
  233. END;
  234. (*
  235. Trace.Memory(SYSTEM.VAL(ADDRESS, module), 256);
  236. TRACE(module, module.name, module.body);
  237. TRACE(module);
  238. TRACE(ADDRESS OF module.next);
  239. TRACE(ADDRESS OF module.name);
  240. TRACE(ADDRESS OF module.init);
  241. TRACE(ADDRESS OF module.published);
  242. TRACE(ADDRESS OF module.body);
  243. TRACE(ADDRESS OF module.refcnt);
  244. TRACE(ADDRESS OF module.sb);
  245. TRACE(ADDRESS OF module.entry);
  246. TRACE(ADDRESS OF module.command);
  247. TRACE(ADDRESS OF module.ptrAdr);
  248. TRACE(ADDRESS OF module.typeInfo);
  249. TRACE(ADDRESS OF module.module);
  250. TRACE(ADDRESS OF module.procTable);
  251. TRACE(ADDRESS OF module.ptrTable);
  252. TRACE(ADDRESS OF module.data);
  253. TRACE(ADDRESS OF module.code);
  254. TRACE(ADDRESS OF module.staticTypeDescs);
  255. TRACE(ADDRESS OF module.refs);
  256. TRACE(ADDRESS OF module.export);
  257. TRACE(ADDRESS OF module.term);
  258. TRACE(ADDRESS OF module.exTable);
  259. TRACE(ADDRESS OF module.noProcs);
  260. TRACE(ADDRESS OF module.firstProc);
  261. TRACE(ADDRESS OF module.maxPtrs);
  262. TRACE(ADDRESS OF module.crc);
  263. TRACE(ADDRESS OF module.body);
  264. *)
  265. IF module.body # NIL THEN module.body END;
  266. IF callagain THEN
  267. 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 *)
  268. ELSE
  269. module.init := TRUE;
  270. END;
  271. END;
  272. END Initialize0;
  273. (** Return the named module or NIL if it is not loaded yet. *)
  274. PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
  275. VAR m: Module;
  276. BEGIN
  277. Machine.Acquire(Machine.Modules);
  278. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  279. Machine.Release(Machine.Modules);
  280. RETURN m
  281. END ModuleByName;
  282. PROCEDURE ByName(CONST name: ARRAY OF CHAR; VAR referenced: BOOLEAN): Module;
  283. VAR m: Module;
  284. BEGIN
  285. Machine.Acquire(Machine.Modules);
  286. referenced := FALSE;
  287. m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
  288. IF m = NIL THEN
  289. referenced := TRUE;
  290. m := register.first; WHILE (m#NIL) & (m.name # name) DO m := m.next END;
  291. END;
  292. Machine.Release(Machine.Modules);
  293. RETURN m
  294. END ByName;
  295. (* Generate a module file name. *)
  296. PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  297. VAR i, j: LONGINT;
  298. BEGIN
  299. i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
  300. j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
  301. fileName[i] := 0X
  302. END GetFileName;
  303. (* sort procedure descriptors by firstPC in ascending order *)
  304. PROCEDURE SortProcedureDescs(p: ProcedureDescs);
  305. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  306. BEGIN
  307. RETURN p[i].pcFrom < p[j].pcFrom;
  308. END Less;
  309. PROCEDURE Swap(i,j: LONGINT);
  310. VAR tmp: ProcedureDescPointer;
  311. BEGIN
  312. tmp := p[i];
  313. p[i] := p[j];
  314. p[j] := tmp;
  315. END Swap;
  316. PROCEDURE Quick( lo, hi: LONGINT);
  317. VAR i, j, m: LONGINT;
  318. BEGIN
  319. IF lo < hi THEN
  320. i := lo; j := hi; m := (lo + hi) DIV 2;
  321. REPEAT
  322. WHILE Less( i, m ) DO INC( i ) END;
  323. WHILE Less( m, j ) DO DEC( j ) END;
  324. IF i <= j THEN
  325. IF m = i THEN m := j
  326. ELSIF m = j THEN m := i
  327. END;
  328. Swap( i, j ); INC( i ); DEC( j )
  329. END
  330. UNTIL i > j;
  331. Quick( lo, j); Quick( i, hi)
  332. END;
  333. END Quick;
  334. BEGIN
  335. Quick(0, LEN(p)-1);
  336. END SortProcedureDescs;
  337. (* sort procedure descriptors by firstPC in ascending order *)
  338. PROCEDURE SortExceptionTable(p: ExceptionTable);
  339. PROCEDURE Less(i,j: LONGINT): BOOLEAN;
  340. BEGIN
  341. RETURN p[i].pcFrom < p[j].pcFrom;
  342. END Less;
  343. PROCEDURE Swap(i,j: LONGINT);
  344. VAR tmp: ExceptionTableEntry;
  345. BEGIN
  346. tmp := p[i];
  347. p[i] := p[j];
  348. p[j] := tmp;
  349. END Swap;
  350. PROCEDURE Quick( lo, hi: LONGINT);
  351. VAR i, j, m: LONGINT;
  352. BEGIN
  353. IF lo < hi THEN
  354. i := lo; j := hi; m := (lo + hi) DIV 2;
  355. REPEAT
  356. WHILE Less( i, m ) DO INC( i ) END;
  357. WHILE Less( m, j ) DO DEC( j ) END;
  358. IF i <= j THEN
  359. IF m = i THEN m := j
  360. ELSIF m = j THEN m := i
  361. END;
  362. Swap( i, j ); INC( i ); DEC( j )
  363. END
  364. UNTIL i > j;
  365. Quick( lo, j); Quick( i, hi)
  366. END;
  367. END Quick;
  368. BEGIN
  369. Quick(0, LEN(p)-1);
  370. END SortExceptionTable;
  371. (** Load the module if it is not already loaded. *) (* Algorithm J. Templ, ETHZ, 1994 *)
  372. PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: WORD; VAR msg: ARRAY OF CHAR): Module;
  373. VAR m: Module; fileName: ARRAY 64 OF CHAR; i: LONGINT; registered: BOOLEAN;
  374. BEGIN
  375. res := Ok; msg[0] := 0X; m := ByName(name, registered);
  376. IF (m#NIL) & (registered) THEN
  377. IF trace THEN
  378. Machine.Acquire (Machine.TraceOutput);
  379. Trace.String(">R>"); Trace.StringLn (name);
  380. Machine.Release (Machine.TraceOutput);
  381. END;
  382. IF ~m.published THEN (* no race on m.published, as update is done in Publish *)
  383. Initialize(m);
  384. END;
  385. IF trace THEN
  386. Machine.Acquire (Machine.TraceOutput);
  387. Trace.String("<R<"); Trace.StringLn (name);
  388. Machine.Release (Machine.TraceOutput);
  389. END;
  390. ELSIF m = NIL THEN
  391. IF trace THEN
  392. Machine.Acquire (Machine.TraceOutput);
  393. Trace.String(">L>"); Trace.StringLn (name);
  394. Machine.Release (Machine.TraceOutput);
  395. END;
  396. IF numLoaders = 0 THEN
  397. res := NoLoader; m := NIL;
  398. ELSE
  399. i:= 0;
  400. REPEAT
  401. GetFileName(name, extension[i], fileName);
  402. m := loader[i](name, fileName, res, msg);
  403. INC(i);
  404. UNTIL (m # NIL) OR (i=numLoaders);
  405. END;
  406. IF trace THEN
  407. Machine.Acquire (Machine.TraceOutput);
  408. Trace.String("?"); Trace.StringLn (name);
  409. Machine.Release (Machine.TraceOutput);
  410. END;
  411. IF (m # NIL) & ~m.published THEN (* no race on m.published, as update is done below in Publish *)
  412. Initialize(m);
  413. END;
  414. IF trace THEN
  415. Machine.Acquire (Machine.TraceOutput);
  416. IF m = NIL THEN
  417. Trace.String("could not load "); Trace.StringLn(name)
  418. ELSIF ~m.published THEN
  419. Trace.String("not published "); Trace.StringLn(name)
  420. ELSE
  421. Trace.String("<L<"); Trace.StringLn (name);
  422. END;
  423. Machine.Release (Machine.TraceOutput);
  424. END;
  425. END;
  426. RETURN m
  427. END ThisModule;
  428. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. Non-blocking version for reflection *)
  429. PROCEDURE ThisModuleByAdr0*(pc: ADDRESS): Module;
  430. VAR m: Module; found: BOOLEAN; list: LONGINT;
  431. BEGIN
  432. list := 0; found := FALSE;
  433. REPEAT
  434. CASE list OF
  435. 0: m := root
  436. |1: m := freeRoot
  437. END;
  438. WHILE (m # NIL) & ~found DO
  439. found := FindProc(pc, m.procTable) # NIL;
  440. IF ~found THEN m := m.next END;
  441. END;
  442. INC(list)
  443. UNTIL found OR (list=2);
  444. RETURN m
  445. END ThisModuleByAdr0;
  446. (** Return the module that contains code address pc or NIL if not found. Can also return freed modules. *)
  447. PROCEDURE ThisModuleByAdr*(pc: ADDRESS): Module;
  448. VAR m: Module;
  449. BEGIN
  450. Machine.Acquire(Machine.Modules);
  451. m := ThisModuleByAdr0(pc);
  452. Machine.Release(Machine.Modules);
  453. RETURN m
  454. END ThisModuleByAdr;
  455. CONST ModuleInitTimeout = HUGEINT(3000000000); (* Timeout for waiting until a module get initialized, 3 seconds for 1 GHz CPU *)
  456. (* Retrieve a procedure given a module name, the procedure name and some type information (kernel call) *)
  457. PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : ADDRESS; VAR entryAdr : ADDRESS);
  458. VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT; t: HUGEINT;
  459. BEGIN
  460. module := ThisModule(moduleName, res, ignoreMsg);
  461. IF (res = Ok) THEN
  462. (*!
  463. module body must have been called (see note at the end of this module);
  464. return NIL if the module does not get initialized within the specified timeout
  465. *)
  466. IF ~module.init THEN
  467. t := Machine.GetTimer();
  468. WHILE ~module.init & (Machine.GetTimer() - t < ModuleInitTimeout) DO END;
  469. IF ~module.init THEN (* timeout has expired *)
  470. RETURN;
  471. END;
  472. END;
  473. Machine.Acquire(Machine.Modules);
  474. i := 0; entryAdr := Heaps.NilVal;
  475. WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
  476. IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
  477. entryAdr := module.command[i].entryAdr;
  478. END;
  479. INC(i)
  480. END;
  481. Machine.Release(Machine.Modules);
  482. END;
  483. END GetProcedure;
  484. (** Return the named type *)
  485. PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
  486. VAR i: LONGINT; type: TypeDesc;
  487. BEGIN
  488. Machine.Acquire(Machine.Modules);
  489. i := 0;
  490. WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
  491. IF i = LEN(m.typeInfo) THEN
  492. type := NIL
  493. ELSE
  494. type := m.typeInfo[i]
  495. END;
  496. Machine.Release(Machine.Modules);
  497. RETURN type
  498. END ThisType;
  499. PROCEDURE ThisTypeByAdr*(adr: ADDRESS; VAR m: Module; VAR t: TypeDesc);
  500. BEGIN
  501. IF adr # 0 THEN
  502. Machine.Acquire(Machine.Modules);
  503. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  504. t := SYSTEM.VAL(TypeDesc, adr);
  505. m := t.mod;
  506. Machine.Release(Machine.Modules)
  507. ELSE
  508. m := NIL; t := NIL
  509. END
  510. END ThisTypeByAdr;
  511. (** create a new object given its type descriptor *)
  512. PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
  513. VAR x : ANY;
  514. BEGIN
  515. Heaps.NewRec(x, SYSTEM.VAL (ADDRESS, t.tag), isRealtime);
  516. RETURN x;
  517. END NewObj;
  518. (** return the type descriptor of an object *)
  519. PROCEDURE TypeOf*(obj : ANY): TypeDesc;
  520. VAR
  521. m : Module;
  522. t : TypeDesc;
  523. adr : ADDRESS;
  524. BEGIN
  525. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.TypeDescOffset, adr);
  526. ThisTypeByAdr(adr, m, t);
  527. RETURN t;
  528. END TypeOf;
  529. (** searches for the given pc in the global ProcKeyTable, if found it returns the corresponding data element *)
  530. PROCEDURE FindProc*(pc: ADDRESS; p: ProcedureDescs): ProcedureDescPointer;
  531. VAR l,r,x: LONGINT; isHit: BOOLEAN;
  532. BEGIN
  533. IF p # NIL THEN
  534. l := 0; r := LEN(p)-1;
  535. REPEAT
  536. x := (l + r) DIV 2;
  537. IF pc < p[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  538. isHit := ((p[x].pcFrom <= pc) & (pc < p[x].pcLimit));
  539. UNTIL isHit OR (l > r);
  540. IF isHit THEN
  541. RETURN p[x];
  542. END;
  543. END;
  544. RETURN NIL;
  545. END FindProc;
  546. (** 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. *)
  547. PROCEDURE InstallTermHandler*(h: TerminationHandler);
  548. VAR m: Module;
  549. BEGIN
  550. m := ThisModuleByAdr(SYSTEM.VAL (ADDRESS, h));
  551. IF m # NIL THEN
  552. m.term := h (* overwrite existing handler, if any *)
  553. END
  554. END InstallTermHandler;
  555. (** 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. *)
  556. PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: WORD; VAR msg: ARRAY OF CHAR);
  557. VAR p, m: Module; term: TerminationHandler; i: LONGINT;
  558. BEGIN
  559. m := ModuleByName(name);
  560. IF (m # NIL) & (m.refcnt = 0) THEN (* will be freed below *)
  561. IF m.term # NIL THEN (* call termination handler *)
  562. term := m.term; m.term := NIL; term (* may trap *)
  563. END;
  564. IF m.code # NIL THEN
  565. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  566. END;
  567. END;
  568. res := Ok; msg[0] := 0X;
  569. Machine.Acquire(Machine.Modules);
  570. p := NIL; m := root;
  571. WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
  572. IF m # NIL THEN
  573. IF m.refcnt = 0 THEN (* free the module *)
  574. FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
  575. m.init := FALSE; (* disallow ThisCommand *)
  576. Append("?", m.name);
  577. (* move module to free list *)
  578. IF p = NIL THEN root := root.next ELSE p.next := m.next END;
  579. m.next := freeRoot; freeRoot := m;
  580. (* clear global pointers and code *)
  581. IF m.ptrAdr # NIL THEN
  582. FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
  583. END;
  584. IF ClearCode & (m.code # NIL) THEN
  585. FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
  586. END;
  587. (* remove references to module data *)
  588. m.published := FALSE;
  589. m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
  590. (* do not clear m.type or m.module, as old heap block tags might reference type descs indirectly. *) (* m.staticTypeDescs, m.typeInfo ??? *)
  591. (* do not clear m.data or m.code, as they are used in ThisModuleByAdr (for debugging). *)
  592. (* do not clear m.refs, as they are used in Traps (for debugging). *)
  593. m.export.dsc := NIL; m.exTable := NIL;
  594. ELSE
  595. res := 1901; (* can not free module in use *)
  596. COPY(name, msg); Append(" reference count not zero", msg)
  597. END
  598. ELSE
  599. res := 1902; (* module not found *)
  600. COPY(name, msg); Append(" not found", msg)
  601. END;
  602. Machine.Release(Machine.Modules)
  603. END FreeModule;
  604. (** Shut down all modules by calling their termination handlers and then call Machine.Shutdown. *)
  605. PROCEDURE Shutdown*(code: LONGINT);
  606. VAR m: Module; term: TerminationHandler;
  607. BEGIN
  608. IF code # None THEN
  609. LOOP
  610. Machine.Acquire(Machine.Modules);
  611. m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
  612. IF m # NIL THEN term := m.term; m.term := NIL END; (* finalizer only called once *)
  613. Machine.Release(Machine.Modules);
  614. IF m = NIL THEN EXIT END;
  615. IF TraceBoot OR trace THEN
  616. Machine.Acquire (Machine.TraceOutput);
  617. Trace.String("TermHandler "); Trace.StringLn (m.name);
  618. Machine.Release (Machine.TraceOutput);
  619. END;
  620. term (* if this causes exception or hangs, another shutdown call will retry *)
  621. END;
  622. (* clean up finalizers *)
  623. m := root;
  624. WHILE m # NIL DO
  625. IF (m.code # NIL) & (LEN(m.code)>0) THEN
  626. Heaps.CleanupModuleFinalizers(ADDRESSOF(m.code[0]), LEN(m.code), m.name)
  627. END;
  628. m := m.next
  629. END;
  630. IF TraceBoot OR trace THEN
  631. Machine.Acquire (Machine.TraceOutput);
  632. Trace.StringLn ("Modules.Shutdown finished");
  633. Machine.Release (Machine.TraceOutput);
  634. END;
  635. Machine.Shutdown(code = Reboot) (* does not return *)
  636. END
  637. END Shutdown;
  638. (* Is this PC handled in the corresponding module. deep = scan the whole stack. *)
  639. PROCEDURE IsExceptionHandled*(VAR pc, fp: ADDRESS; deep: BOOLEAN): BOOLEAN;
  640. VAR
  641. handler: ADDRESS;
  642. BEGIN
  643. IF deep THEN
  644. handler := GetExceptionHandler(pc);
  645. IF handler # -1 THEN (* Handler in the current PAF *)
  646. RETURN TRUE
  647. ELSE
  648. WHILE (fp # 0) & (handler = -1) DO
  649. SYSTEM.GET (fp + 4, pc);
  650. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  651. handler := GetExceptionHandler(pc);
  652. SYSTEM.GET (fp, fp) (* Unwind PAF *)
  653. END;
  654. IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
  655. END
  656. ELSE
  657. RETURN GetExceptionHandler(pc) # -1
  658. END
  659. END IsExceptionHandled;
  660. (* Is this PC handled in the corresponding module. If the PC is handled the PC of the
  661. handler is return else -1 is return. There is no problem concurrently accessing this
  662. procedure, there is only reading work. *)
  663. PROCEDURE GetExceptionHandler*(pc: ADDRESS): ADDRESS;
  664. VAR
  665. m: Module;
  666. PROCEDURE BinSearch(exTable: ExceptionTable; key: ADDRESS): ADDRESS;
  667. VAR
  668. x, l, r: LONGINT;
  669. BEGIN
  670. l := 0; r:=LEN(exTable) - 1;
  671. REPEAT
  672. x := (l + r) DIV 2;
  673. IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
  674. UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
  675. IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
  676. RETURN exTable[x].pcHandler;
  677. ELSE
  678. RETURN -1;
  679. END
  680. END BinSearch;
  681. BEGIN
  682. m := ThisModuleByAdr(pc);
  683. IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
  684. RETURN BinSearch(m.exTable, pc);
  685. END;
  686. RETURN -1;
  687. END GetExceptionHandler;
  688. (** fof: to make custom solutions to the race process, described below, possible. This is not a solution to the generic problem !! *)
  689. PROCEDURE Initialized*(m: Module): BOOLEAN;
  690. BEGIN
  691. RETURN m.init;
  692. END Initialized;
  693. PROCEDURE Register- (module {UNTRACED}: Module);
  694. BEGIN {UNCOOPERATIVE, UNCHECKED}
  695. (*TRACE(module.name);*)
  696. IF register.first = NIL THEN
  697. register.first := module;
  698. ELSE
  699. SYSTEM.PUT (ADDRESS OF register.last.next, module); (* transitively unsafe access via register.last *)
  700. END;
  701. register.last := module;
  702. END Register;
  703. PROCEDURE Unregister(m: Module);
  704. VAR prev: Module;
  705. BEGIN
  706. ASSERT(m#NIL);
  707. IF register.first = NIL THEN RETURN
  708. ELSIF m = register.first THEN
  709. register.first := m.next;
  710. IF register.first = NIL THEN register.last := NIL END;
  711. ELSE
  712. prev := register.first;
  713. WHILE (prev.next # NIL) & (prev.next # m) DO
  714. prev := prev.next;
  715. END;
  716. IF prev.next = m THEN
  717. prev.next := prev.next.next;
  718. IF prev.next = NIL THEN register.last := prev END;
  719. END;
  720. END;
  721. m.next := NIL;
  722. END Unregister;
  723. PROCEDURE PublishRegisteredModules;
  724. VAR m {UNTRACED}, prev {UNTRACED}, cur {UNTRACED}: Module; import: SIZE;
  725. BEGIN
  726. #IF COOP THEN
  727. Activities.Call (Activities.Idle);
  728. #END
  729. WHILE register.first # NIL DO
  730. m := register.first;
  731. (*
  732. register.first := m.next;
  733. m.next := NIL;
  734. *)
  735. IF m.module # NIL THEN
  736. FOR import := 0 TO LEN (m.module) - 1 DO
  737. IF ~m.module[import].published THEN
  738. ASSERT(register.first # NIL);
  739. (*prev := NIL;
  740. cur := register.first;
  741. WHILE (cur # NIL) & (cur # m.module[import]) DO
  742. prev := cur;
  743. cur := cur.next
  744. END;
  745. (*ASSERT(cur = m.module[import]);*)
  746. ASSERT(cur = m.module[import]);
  747. IF prev = NIL THEN
  748. register.first := cur.next
  749. ELSE
  750. prev.next := cur.next;
  751. END;
  752. cur.next := NIL;
  753. *)
  754. Initialize0 (m.module[import]);
  755. END
  756. END;
  757. END;
  758. Initialize0 (m);
  759. END;
  760. END PublishRegisteredModules;
  761. #IF COOP THEN
  762. PROCEDURE FinalizeModules;
  763. VAR module {UNTRACED}: Module;
  764. PROCEDURE Finalize EXTERN "BaseTypes.Object.Finalize" (module {UNTRACED}: Module);
  765. BEGIN {UNCOOPERATIVE, UNCHECKED}
  766. module := root;
  767. WHILE module # NIL DO
  768. Finalize (module);
  769. module := module.next;
  770. END;
  771. END FinalizeModules;
  772. PROCEDURE {FINAL} Main;
  773. BEGIN {UNCOOPERATIVE, UNCHECKED}
  774. SYSTEM.SetActivity (NIL);
  775. SYSTEM.SetFramePointer (NIL);
  776. Environment.Initialize;
  777. GarbageCollector.Initialize;
  778. Processors.Initialize;
  779. Activities.Execute (PublishRegisteredModules);
  780. Processors.Terminate;
  781. FinalizeModules;
  782. Activities.Terminate;
  783. Queues.Terminate;
  784. Environment.Terminate;
  785. GarbageCollector.Terminate;
  786. Environment.Exit (Environment.status);
  787. END Main;
  788. #ELSE
  789. (* procedure that will be called last in a linked kernel *)
  790. PROCEDURE {FINAL, NOPAF} Main-;
  791. BEGIN
  792. (*Machine.Init;*)
  793. IF TraceBoot THEN
  794. Trace.String("publish registered modules"); Trace.Ln;
  795. END;
  796. PublishRegisteredModules;
  797. #IF ~SHAREDLIB THEN
  798. (* a standard A2 kernel does not reach this point, but for standalone executables this is required *)
  799. Machine.Shutdown(FALSE);
  800. #END;
  801. END Main;
  802. #END
  803. PROCEDURE Init;
  804. VAR
  805. s: ARRAY 4 OF CHAR;
  806. BEGIN
  807. (* root and initBlock are initialized by the linker *)
  808. shutdown := None;
  809. numLoaders := 0;
  810. freeRoot := NIL;
  811. Machine.GetConfig("TraceModules", s);
  812. trace := (s[0] = "1");
  813. END Init;
  814. BEGIN
  815. Init;
  816. END Modules.