Kernel.txt 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050
  1. MODULE Kernel;
  2. (* THIS IS TEXT COPY OF Kernel.odc *)
  3. (* DO NOT EDIT *)
  4. (* A. V. Shiryaev, 2012.09
  5. Linux Kernel
  6. Based on 1.6-rc6 Windows Kernel
  7. + 20120822 Marc changes
  8. Some parts taken from OpenBUGS linKernel
  9. Most Windows-specific code removed
  10. Some Windows-specific code commented and marked red
  11. Windows COM-specific code re-marked from green to gray
  12. Linux(/OpenBSD)-specific code marked green
  13. TODO:
  14. handle stack overflow exceptions
  15. correct cmdLine
  16. Quit from TrapHandler
  17. *)
  18. IMPORT S := SYSTEM, Libc := LinLibc, Dl := LinDl;
  19. CONST
  20. strictStackSweep = TRUE;
  21. nameLen* = 256;
  22. littleEndian* = TRUE;
  23. timeResolution* = 1000; (* ticks per second *)
  24. processor* = 10; (* i386 *)
  25. objType* = "ocf"; (* file types *)
  26. symType* = "osf";
  27. docType* = "odc";
  28. (* loader constants *)
  29. done* = 0;
  30. fileNotFound* = 1;
  31. syntaxError* = 2;
  32. objNotFound* = 3;
  33. illegalFPrint* = 4;
  34. cyclicImport* = 5;
  35. noMem* = 6;
  36. commNotFound* = 7;
  37. commSyntaxError* = 8;
  38. moduleNotFound* = 9;
  39. any = 1000000;
  40. CX = 1;
  41. SP = 4; (* register number of stack pointer *)
  42. FP = 5; (* register number of frame pointer *)
  43. ML = 3; (* register which holds the module list at program start *)
  44. N = 128 DIV 16; (* free lists *)
  45. (* kernel flags in module desc *)
  46. init = 16; dyn = 17; dll = 24; iptrs = 30;
  47. (* meta interface consts *)
  48. mConst = 1; mTyp = 2; mVar = 3; mProc = 4; mField = 5;
  49. debug = FALSE;
  50. (*
  51. sigStackSize = MAX(Libc.SIGSTKSZ, 65536);
  52. *)
  53. trapReturn = 1; (* Return value for sigsetjmp given from siglongjmp *)
  54. (* constants for the message boxes *)
  55. mbClose* = -1; mbOk* = 0; mbCancel* =1; mbRetry* = 2; mbIgnore* = 3; mbYes* = 4; mbNo* = 5;
  56. TYPE
  57. Name* = ARRAY nameLen OF SHORTCHAR;
  58. Command* = PROCEDURE;
  59. Module* = POINTER TO RECORD [untagged]
  60. next-: Module;
  61. opts-: SET; (* 0..15: compiler opts, 16..31: kernel flags *)
  62. refcnt-: INTEGER; (* <0: module invalidated *)
  63. compTime-, loadTime-: ARRAY 6 OF SHORTINT;
  64. ext-: INTEGER; (* currently not used *)
  65. term-: Command; (* terminator *)
  66. nofimps-, nofptrs-: INTEGER;
  67. csize-, dsize-, rsize-: INTEGER;
  68. code-, data-, refs-: INTEGER;
  69. procBase-, varBase-: INTEGER; (* meta base addresses *)
  70. names-: POINTER TO ARRAY [untagged] OF SHORTCHAR; (* names[0] = 0X *)
  71. ptrs-: POINTER TO ARRAY [untagged] OF INTEGER;
  72. imports-: POINTER TO ARRAY [untagged] OF Module;
  73. export-: Directory; (* exported objects (name sorted) *)
  74. name-: Name
  75. END;
  76. Type* = POINTER TO RECORD [untagged]
  77. (* record: ptr to method n at offset - 4 * (n+1) *)
  78. size-: INTEGER; (* record: size, array: #elem, dyn array: 0, proc: sigfp *)
  79. mod-: Module;
  80. id-: INTEGER; (* name idx * 256 + lev * 16 + attr * 4 + form *)
  81. base-: ARRAY 16 OF Type; (* signature if form = ProcTyp *)
  82. fields-: Directory; (* new fields (declaration order) *)
  83. ptroffs-: ARRAY any OF INTEGER (* array of any length *)
  84. END;
  85. Object* = POINTER TO ObjDesc;
  86. ObjDesc* = RECORD [untagged]
  87. fprint-: INTEGER;
  88. offs-: INTEGER; (* pvfprint for record types *)
  89. id-: INTEGER; (* name idx * 256 + vis * 16 + mode *)
  90. struct-: Type (* id of basic type or pointer to typedesc/signature *)
  91. END;
  92. Directory* = POINTER TO RECORD [untagged]
  93. num-: INTEGER; (* number of entries *)
  94. obj-: ARRAY any OF ObjDesc (* array of any length *)
  95. END;
  96. Signature* = POINTER TO RECORD [untagged]
  97. retStruct-: Type; (* id of basic type or pointer to typedesc or 0 *)
  98. num-: INTEGER; (* number of parameters *)
  99. par-: ARRAY any OF RECORD [untagged] (* parameters *)
  100. id-: INTEGER; (* name idx * 256 + kind *)
  101. struct-: Type (* id of basic type or pointer to typedesc *)
  102. END
  103. END;
  104. Handler* = PROCEDURE;
  105. Reducer* = POINTER TO ABSTRACT RECORD
  106. next: Reducer
  107. END;
  108. Identifier* = ABSTRACT RECORD
  109. typ*: INTEGER;
  110. obj-: ANYPTR
  111. END;
  112. TrapCleaner* = POINTER TO ABSTRACT RECORD
  113. next: TrapCleaner
  114. END;
  115. TryHandler* = PROCEDURE (a, b, c: INTEGER);
  116. (* meta extension suport *)
  117. ItemExt* = POINTER TO ABSTRACT RECORD END;
  118. ItemAttr* = RECORD
  119. obj*, vis*, typ*, adr*: INTEGER;
  120. mod*: Module;
  121. desc*: Type;
  122. ptr*: S.PTR;
  123. ext*: ItemExt
  124. END;
  125. Hook* = POINTER TO ABSTRACT RECORD END;
  126. LoaderHook* = POINTER TO ABSTRACT RECORD (Hook)
  127. res*: INTEGER;
  128. importing*, imported*, object*: ARRAY 256 OF CHAR
  129. END;
  130. GuiHook* = POINTER TO ABSTRACT RECORD (Hook) END; (* Implemented by HostGnome *)
  131. Block = POINTER TO RECORD [untagged]
  132. tag: Type;
  133. last: INTEGER; (* arrays: last element *)
  134. actual: INTEGER; (* arrays: used during mark phase *)
  135. first: INTEGER (* arrays: first element *)
  136. END;
  137. FreeBlock = POINTER TO FreeDesc;
  138. FreeDesc = RECORD [untagged]
  139. tag: Type; (* f.tag = ADR(f.size) *)
  140. size: INTEGER;
  141. next: FreeBlock
  142. END;
  143. Cluster = POINTER TO RECORD [untagged]
  144. size: INTEGER; (* total size *)
  145. next: Cluster;
  146. max: INTEGER
  147. (* start of first block *)
  148. END;
  149. FList = POINTER TO RECORD
  150. next: FList;
  151. blk: Block;
  152. iptr, aiptr: BOOLEAN
  153. END;
  154. CList = POINTER TO RECORD
  155. next: CList;
  156. do: Command;
  157. trapped: BOOLEAN
  158. END;
  159. PtrType = RECORD v: S.PTR END; (* used for array of pointer *)
  160. Char8Type = RECORD v: SHORTCHAR END;
  161. Char16Type = RECORD v: CHAR END;
  162. Int8Type = RECORD v: BYTE END;
  163. Int16Type = RECORD v: SHORTINT END;
  164. Int32Type = RECORD v: INTEGER END;
  165. Int64Type = RECORD v: LONGINT END;
  166. BoolType = RECORD v: BOOLEAN END;
  167. SetType = RECORD v: SET END;
  168. Real32Type = RECORD v: SHORTREAL END;
  169. Real64Type = RECORD v: REAL END;
  170. ProcType = RECORD v: PROCEDURE END;
  171. UPtrType = RECORD v: INTEGER END;
  172. StrPtr = POINTER TO ARRAY [untagged] OF SHORTCHAR;
  173. (* Linux specific boot loader info. Record must be identical to struct in the loader. *)
  174. BootInfo* = POINTER TO RECORD [untagged]
  175. modList: Module;
  176. argc-: INTEGER;
  177. argv-: Libc.StrArray
  178. END;
  179. VAR
  180. baseStack: INTEGER; (* modList, root, and baseStack must be together for remote debugging *)
  181. root: Cluster; (* cluster list *)
  182. modList-: Module; (* root of module list *)
  183. trapCount-: INTEGER;
  184. err-, pc-, sp-, fp-, stack-, val-: INTEGER;
  185. free: ARRAY N OF FreeBlock; (* free list *)
  186. sentinelBlock: FreeDesc;
  187. sentinel: FreeBlock;
  188. candidates: ARRAY 1024 OF INTEGER;
  189. nofcand: INTEGER;
  190. allocated: INTEGER; (* bytes allocated on BlackBox heap *)
  191. total: INTEGER; (* current total size of BlackBox heap *)
  192. used: INTEGER; (* bytes allocated on system heap *)
  193. finalizers: FList;
  194. hotFinalizers: FList;
  195. cleaners: CList;
  196. reducers: Reducer;
  197. trapStack: TrapCleaner;
  198. actual: Module; (* valid during module initialization *)
  199. res: INTEGER; (* auxiliary global variables used for trap handling *)
  200. old: INTEGER;
  201. trapViewer, trapChecker: Handler;
  202. trapped, guarded, secondTrap: BOOLEAN;
  203. interrupted: BOOLEAN;
  204. static, inDll, terminating: BOOLEAN;
  205. restart: Command;
  206. told, shift: INTEGER; (* used in Time() *)
  207. loader: LoaderHook;
  208. loadres: INTEGER;
  209. wouldFinalize: BOOLEAN;
  210. watcher*: PROCEDURE (event: INTEGER); (* for debugging *)
  211. (*
  212. sigStack: Libc.PtrVoid;
  213. *)
  214. zerofd: INTEGER;
  215. pageSize: INTEGER;
  216. loopContext: Libc.sigjmp_buf; (* trap return context, if no Kernel.Try has been used. *)
  217. currentTryContext: POINTER TO Libc.sigjmp_buf; (* trap return context, if Kernel.Try has been used. *)
  218. isReadableContext: Libc.sigjmp_buf; (* for IsReadable *)
  219. isReadableCheck: BOOLEAN;
  220. guiHook: GuiHook;
  221. cmdLine-: ARRAY 1024 OF CHAR;
  222. (* !!! This variable has to be the last variable in the list. !!! *)
  223. bootInfo-: BootInfo;
  224. (* code procedures for fpu *)
  225. PROCEDURE [1] FINIT 0DBH, 0E3H;
  226. PROCEDURE [1] FLDCW 0D9H, 06DH, 0FCH; (* -4, FP *)
  227. PROCEDURE [1] FSTCW 0D9H, 07DH, 0FCH; (* -4, FP *)
  228. (* code procedure for memory erase *)
  229. PROCEDURE [code] Erase (adr, words: INTEGER)
  230. 089H, 0C7H, (* MOV EDI, EAX *)
  231. 031H, 0C0H, (* XOR EAX, EAX *)
  232. 059H, (* POP ECX *)
  233. 0F2H, 0ABH; (* REP STOS *)
  234. (* code procedure for stack allocate *)
  235. PROCEDURE [code] ALLOC (* argument in CX *)
  236. (*
  237. PUSH EAX
  238. ADD ECX,-5
  239. JNS L0
  240. XOR ECX,ECX
  241. L0: AND ECX,-4 (n-8+3)/4*4
  242. MOV EAX,ECX
  243. AND EAX,4095
  244. SUB ESP,EAX
  245. MOV EAX,ECX
  246. SHR EAX,12
  247. JEQ L2
  248. L1: PUSH 0
  249. SUB ESP,4092
  250. DEC EAX
  251. JNE L1
  252. L2: ADD ECX,8
  253. MOV EAX,[ESP,ECX,-4]
  254. PUSH EAX
  255. MOV EAX,[ESP,ECX,-4]
  256. SHR ECX,2
  257. RET
  258. *);
  259. PROCEDURE (VAR id: Identifier) Identified* (): BOOLEAN, NEW, ABSTRACT;
  260. PROCEDURE (r: Reducer) Reduce* (full: BOOLEAN), NEW, ABSTRACT;
  261. PROCEDURE (c: TrapCleaner) Cleanup*, NEW, EMPTY;
  262. (* meta extension suport *)
  263. PROCEDURE (e: ItemExt) Lookup* (name: ARRAY OF CHAR; VAR i: ANYREC), NEW, ABSTRACT;
  264. PROCEDURE (e: ItemExt) Index* (index: INTEGER; VAR elem: ANYREC), NEW, ABSTRACT;
  265. PROCEDURE (e: ItemExt) Deref* (VAR ref: ANYREC), NEW, ABSTRACT;
  266. PROCEDURE (e: ItemExt) Valid* (): BOOLEAN, NEW, ABSTRACT;
  267. PROCEDURE (e: ItemExt) Size* (): INTEGER, NEW, ABSTRACT;
  268. PROCEDURE (e: ItemExt) BaseTyp* (): INTEGER, NEW, ABSTRACT;
  269. PROCEDURE (e: ItemExt) Len* (): INTEGER, NEW, ABSTRACT;
  270. PROCEDURE (e: ItemExt) Call* (OUT ok: BOOLEAN), NEW, ABSTRACT;
  271. PROCEDURE (e: ItemExt) BoolVal* (): BOOLEAN, NEW, ABSTRACT;
  272. PROCEDURE (e: ItemExt) PutBoolVal* (x: BOOLEAN), NEW, ABSTRACT;
  273. PROCEDURE (e: ItemExt) CharVal* (): CHAR, NEW, ABSTRACT;
  274. PROCEDURE (e: ItemExt) PutCharVal* (x: CHAR), NEW, ABSTRACT;
  275. PROCEDURE (e: ItemExt) IntVal* (): INTEGER, NEW, ABSTRACT;
  276. PROCEDURE (e: ItemExt) PutIntVal* (x: INTEGER), NEW, ABSTRACT;
  277. PROCEDURE (e: ItemExt) LongVal* (): LONGINT, NEW, ABSTRACT;
  278. PROCEDURE (e: ItemExt) PutLongVal* (x: LONGINT), NEW, ABSTRACT;
  279. PROCEDURE (e: ItemExt) RealVal* (): REAL, NEW, ABSTRACT;
  280. PROCEDURE (e: ItemExt) PutRealVal* (x: REAL), NEW, ABSTRACT;
  281. PROCEDURE (e: ItemExt) SetVal* (): SET, NEW, ABSTRACT;
  282. PROCEDURE (e: ItemExt) PutSetVal* (x: SET), NEW, ABSTRACT;
  283. PROCEDURE (e: ItemExt) PtrVal* (): ANYPTR, NEW, ABSTRACT;
  284. PROCEDURE (e: ItemExt) PutPtrVal* (x: ANYPTR), NEW, ABSTRACT;
  285. PROCEDURE (e: ItemExt) GetSStringVal* (OUT x: ARRAY OF SHORTCHAR;
  286. OUT ok: BOOLEAN), NEW, ABSTRACT;
  287. PROCEDURE (e: ItemExt) PutSStringVal* (IN x: ARRAY OF SHORTCHAR;
  288. OUT ok: BOOLEAN), NEW, ABSTRACT;
  289. PROCEDURE (e: ItemExt) GetStringVal* (OUT x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
  290. PROCEDURE (e: ItemExt) PutStringVal* (IN x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
  291. (* -------------------- miscellaneous tools -------------------- *)
  292. PROCEDURE Msg (IN str: ARRAY OF CHAR);
  293. VAR ss: ARRAY 1024 OF SHORTCHAR; res, l: INTEGER;
  294. BEGIN
  295. ss := SHORT(str);
  296. l := LEN(ss$);
  297. ss[l] := 0AX; ss[l + 1] := 0X;
  298. res := Libc.printf(ss)
  299. END Msg;
  300. PROCEDURE Int (x: LONGINT);
  301. VAR j, k: INTEGER; ch: CHAR; a, s: ARRAY 32 OF CHAR;
  302. BEGIN
  303. IF x # MIN(LONGINT) THEN
  304. IF x < 0 THEN s[0] := "-"; k := 1; x := -x ELSE k := 0 END;
  305. j := 0; REPEAT a[j] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(j) UNTIL x = 0
  306. ELSE
  307. a := "8085774586302733229"; s[0] := "-"; k := 1;
  308. j := 0; WHILE a[j] # 0X DO INC(j) END
  309. END;
  310. ASSERT(k + j < LEN(s), 20);
  311. REPEAT DEC(j); ch := a[j]; s[k] := ch; INC(k) UNTIL j = 0;
  312. s[k] := 0X;
  313. Msg(s);
  314. END Int;
  315. PROCEDURE (h: GuiHook) MessageBox* (
  316. title, msg: ARRAY OF CHAR; buttons: SET): INTEGER, NEW, ABSTRACT;
  317. PROCEDURE (h: GuiHook) Beep*, NEW, ABSTRACT;
  318. (* Is extended by HostGnome to show dialogs. If no dialog is present or
  319. if the dialog is not closed by using one button, then "mbClose" is returned *)
  320. PROCEDURE MessageBox* (title, msg: ARRAY OF CHAR; buttons: SET): INTEGER;
  321. VAR res: INTEGER;
  322. BEGIN
  323. IF guiHook # NIL THEN
  324. res := guiHook.MessageBox(title, msg, buttons)
  325. ELSE
  326. Msg(" ");
  327. Msg("****");
  328. Msg("* " + title);
  329. Msg("* " + msg);
  330. Msg("****");
  331. res := mbClose;
  332. END;
  333. RETURN res
  334. END MessageBox;
  335. PROCEDURE SetGuiHook* (hook: GuiHook);
  336. BEGIN
  337. guiHook := hook
  338. END SetGuiHook;
  339. PROCEDURE SplitName* (name: ARRAY OF CHAR; VAR head, tail: ARRAY OF CHAR);
  340. (* portable *)
  341. VAR i, j: INTEGER; ch, lch: CHAR;
  342. BEGIN
  343. i := 0; ch := name[0];
  344. IF ch # 0X THEN
  345. REPEAT
  346. head[i] := ch; lch := ch; INC(i); ch := name[i]
  347. UNTIL (ch = 0X)
  348. OR ((ch >= "A") & (ch <= "Z") OR (ch >= "À") & (ch # "×") & (ch <= "Þ"))
  349. & ((lch < "A") OR (lch > "Z") & (lch < "À") OR (lch = "×") OR (lch > "Þ"));
  350. head[i] := 0X; j := 0;
  351. WHILE ch # 0X DO tail[j] := ch; INC(i); INC(j); ch := name[i] END;
  352. tail[j] := 0X;
  353. IF tail = "" THEN tail := head$; head := "" END
  354. ELSE head := ""; tail := ""
  355. END
  356. END SplitName;
  357. PROCEDURE MakeFileName* (VAR name: ARRAY OF CHAR; type: ARRAY OF CHAR);
  358. VAR i, j: INTEGER; ext: ARRAY 8 OF CHAR; ch: CHAR;
  359. BEGIN
  360. i := 0;
  361. WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
  362. IF name[i] = "." THEN
  363. IF name[i + 1] = 0X THEN name[i] := 0X END
  364. ELSIF i < LEN(name) - 4 THEN
  365. IF type = "" THEN ext := docType ELSE ext := type$ END;
  366. name[i] := "."; INC(i); j := 0; ch := ext[0];
  367. WHILE ch # 0X DO
  368. IF (ch >= "A") & (ch <= "Z") THEN
  369. ch := CHR(ORD(ch) + ORD("a") - ORD("A"))
  370. END;
  371. name[i] := ch; INC(i); INC(j); ch := ext[j]
  372. END;
  373. name[i] := 0X
  374. END
  375. END MakeFileName;
  376. PROCEDURE Time* (): LONGINT;
  377. VAR t: INTEGER;
  378. BEGIN
  379. (* t := WinApi.GetTickCount(); *)
  380. (* Linux *)
  381. t := Libc.clock() DIV (Libc.CLOCKS_PER_SECOND DIV 1000); (* processor time to milliseconds *)
  382. IF t < told THEN INC(shift) END;
  383. told := t;
  384. RETURN shift * 100000000L + t
  385. END Time;
  386. PROCEDURE Beep* ();
  387. VAR ss: ARRAY 2 OF SHORTCHAR;
  388. BEGIN
  389. IF guiHook # NIL THEN
  390. guiHook.Beep
  391. ELSE
  392. ss[0] := 007X; ss[1] := 0X;
  393. res := Libc.printf(ss); res := Libc.fflush(Libc.NULL)
  394. END
  395. END Beep;
  396. PROCEDURE SearchProcVar* (var: INTEGER; VAR m: Module; VAR adr: INTEGER);
  397. BEGIN
  398. adr := var; m := NIL;
  399. IF var # 0 THEN
  400. m := modList;
  401. WHILE (m # NIL) & ((var < m.code) OR (var >= m.code + m.csize)) DO m := m.next END;
  402. IF m # NIL THEN DEC(adr, m.code) END
  403. END
  404. END SearchProcVar;
  405. (* -------------------- system memory management --------------------- *)
  406. (* A. V. Shiryaev, 2012.09: NOTE: it seems that GC works correctly with positive addesses only *)
  407. (*
  408. PROCEDURE HeapAlloc (adr: INTEGER; size: INTEGER; prot: SET): Libc.PtrVoid;
  409. VAR
  410. x: Libc.PtrVoid;
  411. res: INTEGER;
  412. BEGIN
  413. x := Libc.calloc(1, size); (* calloc initialize allocated space to zero *)
  414. IF x # Libc.NULL THEN
  415. res := Libc.mprotect(x, size, prot);
  416. IF res # 0 THEN
  417. Libc.free(x);
  418. x := Libc.NULL;
  419. Msg("Kernel.HeapAlloc: mprotect failed!");
  420. HALT(100)
  421. END
  422. END;
  423. RETURN x
  424. END HeapAlloc;
  425. *)
  426. PROCEDURE HeapAlloc (adr: Libc.PtrVoid; size: INTEGER; prot: SET): Libc.PtrVoid;
  427. VAR x: Libc.PtrVoid;
  428. BEGIN
  429. x := Libc.mmap(adr, size, prot, Libc.MAP_PRIVATE + Libc.MAP_ANON, zerofd, 0);
  430. IF x = Libc.MAP_FAILED THEN
  431. x := Libc.NULL
  432. ELSE
  433. ASSERT(size MOD 4 = 0, 100);
  434. Erase(x, size DIV 4)
  435. END;
  436. RETURN x
  437. END HeapAlloc;
  438. (*
  439. PROCEDURE HeapFree (adr: Libc.PtrVoid; size: INTEGER);
  440. VAR res: INTEGER;
  441. BEGIN
  442. (*
  443. ASSERT(size MOD 4 = 0, 100);
  444. Erase(adr, size DIV 4);
  445. res := Libc.mprotect(adr, size, Libc.PROT_NONE);
  446. ASSERT(res = 0, 101);
  447. *)
  448. Libc.free(adr)
  449. END HeapFree;
  450. *)
  451. PROCEDURE HeapFree (adr: Libc.PtrVoid; size: INTEGER);
  452. VAR res: INTEGER;
  453. BEGIN
  454. (*
  455. ASSERT(size MOD 4 = 0, 100);
  456. Erase(adr, size DIV 4);
  457. res := Libc.mprotect(adr, size, Libc.PROT_NONE);
  458. ASSERT(res = 0, 101);
  459. *)
  460. res := Libc.munmap(adr, size);
  461. ASSERT(res = 0, 102)
  462. END HeapFree;
  463. PROCEDURE AllocHeapMem (size: INTEGER; VAR c: Cluster);
  464. (* allocate at least size bytes, typically at least 256 kbytes are allocated *)
  465. CONST N = 65536; (* cluster size for dll *)
  466. prot = Libc.PROT_READ + Libc.PROT_WRITE (* + Libc.PROT_EXEC *);
  467. VAR adr: INTEGER;
  468. allocated: INTEGER;
  469. BEGIN
  470. INC(size, 16);
  471. ASSERT(size > 0, 100); adr := 0;
  472. IF size < N THEN adr := HeapAlloc(1, N, prot) END;
  473. IF adr = 0 THEN adr := HeapAlloc(1, size, prot); allocated := size ELSE allocated := N END;
  474. IF adr = 0 THEN c := NIL
  475. ELSE
  476. c := S.VAL(Cluster, (adr + 15) DIV 16 * 16); c.max := adr;
  477. c.size := allocated - (S.VAL(INTEGER, c) - adr);
  478. INC(used, c.size); INC(total, c.size)
  479. END
  480. (* post: (c = NIL) OR (c MOD 16 = 0) & (c.size >= size) *)
  481. END AllocHeapMem;
  482. PROCEDURE FreeHeapMem (c: Cluster);
  483. BEGIN
  484. DEC(used, c.size); DEC(total, c.size);
  485. HeapFree(c.max, (S.VAL(INTEGER, c) - c.max) + c.size)
  486. END FreeHeapMem;
  487. PROCEDURE AllocModMem* (descSize, modSize: INTEGER; VAR descAdr, modAdr: INTEGER);
  488. CONST
  489. prot = Libc.PROT_READ + Libc.PROT_WRITE (* + Libc.PROT_EXEC *);
  490. BEGIN
  491. descAdr := HeapAlloc(0, descSize, prot);
  492. IF descAdr # 0 THEN
  493. modAdr := HeapAlloc(0, modSize, prot);
  494. IF modAdr # 0 THEN INC(used, descSize + modSize)
  495. ELSE HeapFree(descAdr, descSize); descAdr := 0
  496. END
  497. ELSE modAdr := 0
  498. END
  499. END AllocModMem;
  500. PROCEDURE DeallocModMem* (descSize, modSize, descAdr, modAdr: INTEGER);
  501. BEGIN
  502. DEC(used, descSize + modSize);
  503. HeapFree(descAdr, descSize);
  504. HeapFree(modAdr, modSize)
  505. END DeallocModMem;
  506. PROCEDURE InvalModMem (modSize, modAdr: INTEGER);
  507. BEGIN
  508. DEC(used, modSize);
  509. HeapFree(modAdr, modSize)
  510. END InvalModMem;
  511. (*
  512. PROCEDURE IsReadable* (from, to: INTEGER): BOOLEAN;
  513. (* check wether memory between from (incl.) and to (excl.) may be read *)
  514. BEGIN
  515. RETURN WinApi.IsBadReadPtr(from, to - from) = 0
  516. END IsReadable;
  517. *)
  518. (* Alexander Shiryaev, 2012.10: Linux: can be implemented through mincore/madvise *)
  519. (* This procedure can be called from TrapHandler also *)
  520. PROCEDURE IsReadable* (from, to: INTEGER): BOOLEAN;
  521. (* check wether memory between from (incl.) and to (excl.) may be read *)
  522. VAR res: BOOLEAN; res1: INTEGER;
  523. x: SHORTCHAR;
  524. mask, omask: Libc.sigset_t;
  525. BEGIN
  526. (* save old sigmask and unblock SIGSEGV *)
  527. res1 := Libc.sigemptyset(S.ADR(mask));
  528. ASSERT(res1 = 0, 100);
  529. res1 := Libc.sigaddset(S.ADR(mask), Libc.SIGSEGV);
  530. ASSERT(res1 = 0, 101);
  531. res1 := Libc.sigprocmask(Libc.SIG_UNBLOCK, S.ADR(mask), S.ADR(omask));
  532. ASSERT(res1 = 0, 102);
  533. res := FALSE;
  534. res1 := Libc.sigsetjmp(isReadableContext, Libc.TRUE);
  535. IF res1 = 0 THEN
  536. isReadableCheck := TRUE;
  537. (* read memory *)
  538. REPEAT
  539. S.GET(from, x);
  540. INC(from)
  541. UNTIL from = to;
  542. res := TRUE
  543. ELSE
  544. ASSERT(res1 = 1, 103)
  545. END;
  546. isReadableCheck := FALSE;
  547. (* restore saved sigmask *)
  548. res1 := Libc.sigprocmask(Libc.SIG_SETMASK, S.ADR(omask), Libc.NULL);
  549. ASSERT(res1 = 0, 104);
  550. RETURN res
  551. END IsReadable;
  552. (* --------------------- NEW implementation (portable) -------------------- *)
  553. PROCEDURE^ NewBlock (size: INTEGER): Block;
  554. PROCEDURE NewRec* (typ: INTEGER): INTEGER; (* implementation of NEW(ptr) *)
  555. VAR size: INTEGER; b: Block; tag: Type; l: FList;
  556. BEGIN
  557. IF ODD(typ) THEN (* record contains interface pointers *)
  558. tag := S.VAL(Type, typ - 1);
  559. b := NewBlock(tag.size);
  560. IF b = NIL THEN RETURN 0 END;
  561. b.tag := tag;
  562. l := S.VAL(FList, S.ADR(b.last)); (* anchor new object! *)
  563. l := S.VAL(FList, NewRec(S.TYP(FList))); (* NEW(l) *)
  564. l.blk := b; l.iptr := TRUE; l.next := finalizers; finalizers := l;
  565. RETURN S.ADR(b.last)
  566. ELSE
  567. tag := S.VAL(Type, typ);
  568. b := NewBlock(tag.size);
  569. IF b = NIL THEN RETURN 0 END;
  570. b.tag := tag; S.GET(typ - 4, size);
  571. IF size # 0 THEN (* record uses a finalizer *)
  572. l := S.VAL(FList, S.ADR(b.last)); (* anchor new object! *)
  573. l := S.VAL(FList, NewRec(S.TYP(FList))); (* NEW(l) *)
  574. l.blk := b; l.next := finalizers; finalizers := l
  575. END;
  576. RETURN S.ADR(b.last)
  577. END
  578. END NewRec;
  579. PROCEDURE NewArr* (eltyp, nofelem, nofdim: INTEGER): INTEGER; (* impl. of NEW(ptr, dim0, dim1, ...) *)
  580. VAR b: Block; size, headSize: INTEGER; t: Type; fin: BOOLEAN; l: FList;
  581. BEGIN
  582. IF (nofdim < 0)OR(nofdim>1FFFFFFCH) THEN RETURN 0 END;(*20120822 Marc*)
  583. headSize := 4 * nofdim + 12; fin := FALSE;
  584. CASE eltyp OF
  585. (*
  586. | -1: eltyp := S.ADR(IntPtrType); fin := TRUE
  587. *)
  588. | -1: HALT(100)
  589. | 0: eltyp := S.ADR(PtrType)
  590. | 1: eltyp := S.ADR(Char8Type)
  591. | 2: eltyp := S.ADR(Int16Type)
  592. | 3: eltyp := S.ADR(Int8Type)
  593. | 4: eltyp := S.ADR(Int32Type)
  594. | 5: eltyp := S.ADR(BoolType)
  595. | 6: eltyp := S.ADR(SetType)
  596. | 7: eltyp := S.ADR(Real32Type)
  597. | 8: eltyp := S.ADR(Real64Type)
  598. | 9: eltyp := S.ADR(Char16Type)
  599. | 10: eltyp := S.ADR(Int64Type)
  600. | 11: eltyp := S.ADR(ProcType)
  601. | 12: eltyp := S.ADR(UPtrType)
  602. ELSE (* eltyp is desc *)
  603. IF ODD(eltyp) THEN DEC(eltyp); fin := TRUE END
  604. END;
  605. t := S.VAL(Type, eltyp);
  606. ASSERT(t .size> 0,100);
  607. IF (nofelem < 0) OR( (7FFFFFFFH-headSize) DIV t.size < nofelem) THEN (* 20120822 Marc*)
  608. RETURN 0
  609. END;
  610. size := headSize + nofelem * t.size;
  611. b := NewBlock(size);
  612. IF b = NIL THEN RETURN 0 END;
  613. b.tag := S.VAL(Type, eltyp + 2); (* tag + array mark *)
  614. b.last := S.ADR(b.last) + size - t.size; (* pointer to last elem *)
  615. b.first := S.ADR(b.last) + headSize; (* pointer to first elem *)
  616. IF fin THEN
  617. l := S.VAL(FList, S.ADR(b.last)); (* anchor new object! *)
  618. l := S.VAL(FList, NewRec(S.TYP(FList))); (* NEW(l) *)
  619. l.blk := b; l.aiptr := TRUE; l.next := finalizers; finalizers := l
  620. END;
  621. RETURN S.ADR(b.last)
  622. END NewArr;
  623. (* -------------------- handler installation (portable) --------------------- *)
  624. PROCEDURE ThisFinObj* (VAR id: Identifier): ANYPTR;
  625. VAR l: FList;
  626. BEGIN
  627. ASSERT(id.typ # 0, 100);
  628. l := finalizers;
  629. WHILE l # NIL DO
  630. IF S.VAL(INTEGER, l.blk.tag) = id.typ THEN
  631. id.obj := S.VAL(ANYPTR, S.ADR(l.blk.last));
  632. IF id.Identified() THEN RETURN id.obj END
  633. END;
  634. l := l.next
  635. END;
  636. RETURN NIL
  637. END ThisFinObj;
  638. PROCEDURE InstallReducer* (r: Reducer);
  639. BEGIN
  640. r.next := reducers; reducers := r
  641. END InstallReducer;
  642. PROCEDURE InstallTrapViewer* (h: Handler);
  643. BEGIN
  644. trapViewer := h
  645. END InstallTrapViewer;
  646. PROCEDURE InstallTrapChecker* (h: Handler);
  647. BEGIN
  648. trapChecker := h
  649. END InstallTrapChecker;
  650. PROCEDURE PushTrapCleaner* (c: TrapCleaner);
  651. VAR t: TrapCleaner;
  652. BEGIN
  653. t := trapStack; WHILE (t # NIL) & (t # c) DO t := t.next END;
  654. ASSERT(t = NIL, 20);
  655. c.next := trapStack; trapStack := c
  656. END PushTrapCleaner;
  657. PROCEDURE PopTrapCleaner* (c: TrapCleaner);
  658. VAR t: TrapCleaner;
  659. BEGIN
  660. t := NIL;
  661. WHILE (trapStack # NIL) & (t # c) DO
  662. t := trapStack; trapStack := trapStack.next
  663. END
  664. END PopTrapCleaner;
  665. PROCEDURE InstallCleaner* (p: Command);
  666. VAR c: CList;
  667. BEGIN
  668. c := S.VAL(CList, NewRec(S.TYP(CList))); (* NEW(c) *)
  669. c.do := p; c.trapped := FALSE; c.next := cleaners; cleaners := c
  670. END InstallCleaner;
  671. PROCEDURE RemoveCleaner* (p: Command);
  672. VAR c0, c: CList;
  673. BEGIN
  674. c := cleaners; c0 := NIL;
  675. WHILE (c # NIL) & (c.do # p) DO c0 := c; c := c.next END;
  676. IF c # NIL THEN
  677. IF c0 = NIL THEN cleaners := cleaners.next ELSE c0.next := c.next END
  678. END
  679. END RemoveCleaner;
  680. PROCEDURE Cleanup*;
  681. VAR c, c0: CList;
  682. BEGIN
  683. c := cleaners; c0 := NIL;
  684. WHILE c # NIL DO
  685. IF ~c.trapped THEN
  686. c.trapped := TRUE; c.do; c.trapped := FALSE; c0 := c
  687. ELSE
  688. IF c0 = NIL THEN cleaners := cleaners.next
  689. ELSE c0.next := c.next
  690. END
  691. END;
  692. c := c.next
  693. END
  694. END Cleanup;
  695. (* -------------------- meta information (portable) --------------------- *)
  696. PROCEDURE (h: LoaderHook) ThisMod* (IN name: ARRAY OF SHORTCHAR): Module, NEW, ABSTRACT;
  697. PROCEDURE SetLoaderHook*(h: LoaderHook);
  698. BEGIN
  699. loader := h
  700. END SetLoaderHook;
  701. PROCEDURE InitModule (mod: Module); (* initialize linked modules *)
  702. VAR body: Command;
  703. res: INTEGER; errno: INTEGER;
  704. BEGIN
  705. IF ~(dyn IN mod.opts) & (mod.next # NIL) & ~(init IN mod.next.opts) THEN InitModule(mod.next) END;
  706. IF ~(init IN mod.opts) THEN
  707. body := S.VAL(Command, mod.code);
  708. INCL(mod.opts, init);
  709. actual := mod;
  710. (* A. V. Shiryaev: Allow execution on code pages *)
  711. (* Linux: must be page-aligned *)
  712. res := Libc.mprotect(
  713. (mod.code DIV pageSize) * pageSize,
  714. ((mod.csize + mod.code MOD pageSize - 1) DIV pageSize) * pageSize + pageSize,
  715. Libc.PROT_READ + Libc.PROT_WRITE + Libc.PROT_EXEC);
  716. IF res = -1 THEN
  717. S.GET( Libc.__errno_location(), errno );
  718. Msg("ERROR: Kernel.InitModule: mprotect failed!");
  719. Msg(mod.name$); Int(mod.code); Int(mod.csize); Int(errno);
  720. HALT(100)
  721. ELSE ASSERT(res = 0)
  722. END;
  723. body(); actual := NIL
  724. END
  725. END InitModule;
  726. PROCEDURE ThisLoadedMod* (IN name: ARRAY OF SHORTCHAR): Module; (* loaded modules only *)
  727. VAR m: Module;
  728. BEGIN
  729. loadres := done;
  730. m := modList;
  731. WHILE (m # NIL) & ((m.name # name) OR (m.refcnt < 0)) DO m := m.next END;
  732. IF (m # NIL) & ~(init IN m.opts) THEN InitModule(m) END;
  733. IF m = NIL THEN loadres := moduleNotFound END;
  734. RETURN m
  735. END ThisLoadedMod;
  736. PROCEDURE ThisMod* (IN name: ARRAY OF CHAR): Module;
  737. VAR n : Name;
  738. BEGIN
  739. n := SHORT(name$);
  740. IF loader # NIL THEN
  741. loader.res := done;
  742. RETURN loader.ThisMod(n)
  743. ELSE
  744. RETURN ThisLoadedMod(n)
  745. END
  746. END ThisMod;
  747. PROCEDURE LoadMod* (IN name: ARRAY OF CHAR);
  748. VAR m: Module;
  749. BEGIN
  750. m := ThisMod(name)
  751. END LoadMod;
  752. PROCEDURE GetLoaderResult* (OUT res: INTEGER; OUT importing, imported, object: ARRAY OF CHAR);
  753. BEGIN
  754. IF loader # NIL THEN
  755. res := loader.res;
  756. importing := loader.importing$;
  757. imported := loader.imported$;
  758. object := loader.object$
  759. ELSE
  760. res := loadres;
  761. importing := "";
  762. imported := "";
  763. object := ""
  764. END
  765. END GetLoaderResult;
  766. PROCEDURE ThisObject* (mod: Module; name: ARRAY OF SHORTCHAR): Object;
  767. VAR l, r, m: INTEGER; p: StrPtr;
  768. BEGIN
  769. l := 0; r := mod.export.num;
  770. WHILE l < r DO (* binary search *)
  771. m := (l + r) DIV 2;
  772. p := S.VAL(StrPtr, S.ADR(mod.names[mod.export.obj[m].id DIV 256]));
  773. IF p^ = name THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[m])) END;
  774. IF p^ < name THEN l := m + 1 ELSE r := m END
  775. END;
  776. RETURN NIL
  777. END ThisObject;
  778. PROCEDURE ThisDesc* (mod: Module; fprint: INTEGER): Object;
  779. VAR i, n: INTEGER;
  780. BEGIN
  781. i := 0; n := mod.export.num;
  782. WHILE (i < n) & (mod.export.obj[i].id DIV 256 = 0) DO
  783. IF mod.export.obj[i].offs = fprint THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[i])) END;
  784. INC(i)
  785. END;
  786. RETURN NIL
  787. END ThisDesc;
  788. PROCEDURE ThisField* (rec: Type; name: ARRAY OF SHORTCHAR): Object;
  789. VAR n: INTEGER; p: StrPtr; obj: Object; m: Module;
  790. BEGIN
  791. m := rec.mod;
  792. obj := S.VAL(Object, S.ADR(rec.fields.obj[0])); n := rec.fields.num;
  793. WHILE n > 0 DO
  794. p := S.VAL(StrPtr, S.ADR(m.names[obj.id DIV 256]));
  795. IF p^ = name THEN RETURN obj END;
  796. DEC(n); INC(S.VAL(INTEGER, obj), 16)
  797. END;
  798. RETURN NIL
  799. END ThisField;
  800. PROCEDURE ThisCommand* (mod: Module; name: ARRAY OF SHORTCHAR): Command;
  801. VAR x: Object; sig: Signature;
  802. BEGIN
  803. x := ThisObject(mod, name);
  804. IF (x # NIL) & (x.id MOD 16 = mProc) THEN
  805. sig := S.VAL(Signature, x.struct);
  806. IF (sig.retStruct = NIL) & (sig.num = 0) THEN RETURN S.VAL(Command, mod.procBase + x.offs) END
  807. END;
  808. RETURN NIL
  809. END ThisCommand;
  810. PROCEDURE ThisType* (mod: Module; name: ARRAY OF SHORTCHAR): Type;
  811. VAR x: Object;
  812. BEGIN
  813. x := ThisObject(mod, name);
  814. IF (x # NIL) & (x.id MOD 16 = mTyp) & (S.VAL(INTEGER, x.struct) DIV 256 # 0) THEN
  815. RETURN x.struct
  816. ELSE
  817. RETURN NIL
  818. END
  819. END ThisType;
  820. PROCEDURE TypeOf* (IN rec: ANYREC): Type;
  821. BEGIN
  822. RETURN S.VAL(Type, S.TYP(rec))
  823. END TypeOf;
  824. PROCEDURE LevelOf* (t: Type): SHORTINT;
  825. BEGIN
  826. RETURN SHORT(t.id DIV 16 MOD 16)
  827. END LevelOf;
  828. PROCEDURE NewObj* (VAR o: S.PTR; t: Type);
  829. VAR i: INTEGER;
  830. BEGIN
  831. IF t.size = -1 THEN o := NIL
  832. ELSE
  833. i := 0; WHILE t.ptroffs[i] >= 0 DO INC(i) END;
  834. IF t.ptroffs[i+1] >= 0 THEN INC(S.VAL(INTEGER, t)) END; (* with interface pointers *)
  835. o := S.VAL(S.PTR, NewRec(S.VAL(INTEGER, t))) (* generic NEW *)
  836. END
  837. END NewObj;
  838. PROCEDURE GetObjName* (mod: Module; obj: Object; VAR name: Name);
  839. VAR p: StrPtr;
  840. BEGIN
  841. p := S.VAL(StrPtr, S.ADR(mod.names[obj.id DIV 256]));
  842. name := p^$
  843. END GetObjName;
  844. PROCEDURE GetTypeName* (t: Type; VAR name: Name);
  845. VAR p: StrPtr;
  846. BEGIN
  847. p := S.VAL(StrPtr, S.ADR(t.mod.names[t.id DIV 256]));
  848. name := p^$
  849. END GetTypeName;
  850. PROCEDURE RegisterMod* (mod: Module);
  851. VAR i: INTEGER;
  852. t: Libc.time_t; tm: Libc.tm;
  853. BEGIN
  854. mod.next := modList; modList := mod; mod.refcnt := 0; INCL(mod.opts, dyn); i := 0;
  855. WHILE i < mod.nofimps DO
  856. IF mod.imports[i] # NIL THEN INC(mod.imports[i].refcnt) END;
  857. INC(i)
  858. END;
  859. t := Libc.time(NIL);
  860. tm := Libc.localtime(t);
  861. mod.loadTime[0] := SHORT(tm.tm_year + 1900); (* Linux counts years from 1900 but BlackBox from 0000 *)
  862. mod.loadTime[1] := SHORT(tm.tm_mon + 1) (* Linux month range 0-11 but BB month range 1-12 *);
  863. mod.loadTime[2] := SHORT(tm.tm_mday);
  864. mod.loadTime[3] := SHORT(tm.tm_hour);
  865. mod.loadTime[4] := SHORT(tm.tm_min);
  866. mod.loadTime[5] := SHORT(tm.tm_sec);
  867. tm := NIL;
  868. IF ~(init IN mod.opts) THEN InitModule(mod) END
  869. END RegisterMod;
  870. PROCEDURE^ Collect*;
  871. PROCEDURE UnloadMod* (mod: Module);
  872. VAR i: INTEGER; t: Command;
  873. BEGIN
  874. IF mod.refcnt = 0 THEN
  875. t := mod.term; mod.term := NIL;
  876. IF t # NIL THEN t() END; (* terminate module *)
  877. i := 0;
  878. WHILE i < mod.nofptrs DO (* release global pointers *)
  879. S.PUT(mod.varBase + mod.ptrs[i], 0); INC(i)
  880. END;
  881. (*
  882. ReleaseIPtrs(mod); (* release global interface pointers *)
  883. *)
  884. Collect; (* call finalizers *)
  885. i := 0;
  886. WHILE i < mod.nofimps DO (* release imported modules *)
  887. IF mod.imports[i] # NIL THEN DEC(mod.imports[i].refcnt) END;
  888. INC(i)
  889. END;
  890. mod.refcnt := -1;
  891. IF dyn IN mod.opts THEN (* release memory *)
  892. InvalModMem(mod.data + mod.dsize - mod.refs, mod.refs)
  893. END
  894. END
  895. END UnloadMod;
  896. (* -------------------- dynamic procedure call --------------------- *) (* COMPILER DEPENDENT *)
  897. PROCEDURE [1] PUSH (p: INTEGER) 050H; (* push AX *)
  898. PROCEDURE [1] CALL (a: INTEGER) 0FFH, 0D0H; (* call AX *)
  899. PROCEDURE [1] RETI (): LONGINT;
  900. PROCEDURE [1] RETR (): REAL;
  901. (*
  902. type par
  903. 32 bit scalar value
  904. 64 bit scalar low hi
  905. var scalar address
  906. record address tag
  907. array address size
  908. open array address length .. length
  909. *)
  910. PROCEDURE Call* (adr: INTEGER; sig: Signature; IN par: ARRAY OF INTEGER; n: INTEGER): LONGINT;
  911. VAR p, kind, sp, size: INTEGER; typ: Type; r: REAL;
  912. BEGIN
  913. p := sig.num;
  914. WHILE p > 0 DO (* push parameters from right to left *)
  915. DEC(p);
  916. typ := sig.par[p].struct;
  917. kind := sig.par[p].id MOD 16;
  918. IF (S.VAL(INTEGER, typ) DIV 256 = 0) OR (typ.id MOD 4 IN {0, 3}) THEN (* scalar *)
  919. IF (kind = 10) & ((S.VAL(INTEGER, typ) = 8) OR (S.VAL(INTEGER, typ) = 10)) THEN (* 64 bit *)
  920. DEC(n); PUSH(par[n]) (* push hi word *)
  921. END;
  922. DEC(n); PUSH(par[n]) (* push value/address *)
  923. ELSIF typ.id MOD 4 = 1 THEN (* record *)
  924. IF kind # 10 THEN (* var par *)
  925. DEC(n); PUSH(par[n]); (* push tag *)
  926. DEC(n); PUSH(par[n]) (* push address *)
  927. ELSE
  928. DEC(n, 2); (* skip tag *)
  929. S.GETREG(SP, sp); sp := (sp - typ.size) DIV 4 * 4; S.PUTREG(SP, sp); (* allocate space *)
  930. S.MOVE(par[n], sp, typ.size) (* copy to stack *)
  931. END
  932. ELSIF typ.size = 0 THEN (* open array *)
  933. size := typ.id DIV 16 MOD 16; (* number of open dimensions *)
  934. WHILE size > 0 DO
  935. DEC(size); DEC(n); PUSH(par[n]) (* push length *)
  936. END;
  937. DEC(n); PUSH(par[n]) (* push address *)
  938. ELSE (* fix array *)
  939. IF kind # 10 THEN (* var par *)
  940. DEC(n, 2); PUSH(par[n]) (* push address *)
  941. ELSE
  942. DEC(n); size := par[n]; DEC(n);
  943. S.GETREG(SP, sp); sp := (sp - size) DIV 4 * 4; S.PUTREG(SP, sp); (* allocate space *)
  944. S.MOVE(par[n], sp, size) (* copy to stack *)
  945. END
  946. END
  947. END;
  948. ASSERT(n = 0);
  949. IF S.VAL(INTEGER, sig.retStruct) = 7 THEN (* shortreal *)
  950. CALL(adr);
  951. RETURN S.VAL(INTEGER, SHORT(RETR())) (* return value in fpu register *)
  952. ELSIF S.VAL(INTEGER, sig.retStruct) = 8 THEN (* real *)
  953. CALL(adr); r := RETR();
  954. RETURN S.VAL(LONGINT, r) (* return value in fpu register *)
  955. ELSE
  956. CALL(adr);
  957. RETURN RETI() (* return value in integer registers *)
  958. END
  959. END Call;
  960. (* -------------------- reference information (portable) --------------------- *)
  961. PROCEDURE RefCh (VAR ref: INTEGER; VAR ch: SHORTCHAR);
  962. BEGIN
  963. S.GET(ref, ch); INC(ref)
  964. END RefCh;
  965. PROCEDURE RefNum (VAR ref: INTEGER; VAR x: INTEGER);
  966. VAR s, n: INTEGER; ch: SHORTCHAR;
  967. BEGIN
  968. s := 0; n := 0; RefCh(ref, ch);
  969. WHILE ORD(ch) >= 128 DO INC(n, ASH(ORD(ch) - 128, s) ); INC(s, 7); RefCh(ref, ch) END;
  970. x := n + ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s)
  971. END RefNum;
  972. PROCEDURE RefName (VAR ref: INTEGER; VAR n: Name);
  973. VAR i: INTEGER; ch: SHORTCHAR;
  974. BEGIN
  975. i := 0; RefCh(ref, ch);
  976. WHILE ch # 0X DO n[i] := ch; INC(i); RefCh(ref, ch) END;
  977. n[i] := 0X
  978. END RefName;
  979. PROCEDURE GetRefProc* (VAR ref: INTEGER; VAR adr: INTEGER; VAR name: Name);
  980. VAR ch: SHORTCHAR;
  981. BEGIN
  982. S.GET(ref, ch);
  983. WHILE ch >= 0FDX DO (* skip variables *)
  984. INC(ref); RefCh(ref, ch);
  985. IF ch = 10X THEN INC(ref, 4) END;
  986. RefNum(ref, adr); RefName(ref, name); S.GET(ref, ch)
  987. END;
  988. WHILE (ch > 0X) & (ch < 0FCX) DO (* skip source refs *)
  989. INC(ref); RefNum(ref, adr); S.GET(ref, ch)
  990. END;
  991. IF ch = 0FCX THEN INC(ref); RefNum(ref, adr); RefName(ref, name)
  992. ELSE adr := 0
  993. END
  994. END GetRefProc;
  995. PROCEDURE GetRefVar* (VAR ref: INTEGER; VAR mode, form: SHORTCHAR; VAR desc: Type;
  996. VAR adr: INTEGER; VAR name: Name);
  997. BEGIN
  998. S.GET(ref, mode); desc := NIL;
  999. IF mode >= 0FDX THEN
  1000. mode := SHORT(CHR(ORD(mode) - 0FCH));
  1001. INC(ref); RefCh(ref, form);
  1002. IF form = 10X THEN
  1003. S.GET(ref, desc); INC(ref, 4); form := SHORT(CHR(16 + desc.id MOD 4))
  1004. END;
  1005. RefNum(ref, adr); RefName(ref, name)
  1006. ELSE
  1007. mode := 0X; form := 0X; adr := 0
  1008. END
  1009. END GetRefVar;
  1010. PROCEDURE SourcePos* (mod: Module; codePos: INTEGER): INTEGER;
  1011. VAR ref, pos, ad, d: INTEGER; ch: SHORTCHAR; name: Name;
  1012. BEGIN
  1013. ref := mod.refs; pos := 0; ad := 0; S.GET(ref, ch);
  1014. WHILE ch # 0X DO
  1015. WHILE (ch > 0X) & (ch < 0FCX) DO
  1016. INC(ad, ORD(ch)); INC(ref); RefNum(ref, d);
  1017. IF ad > codePos THEN RETURN pos END;
  1018. INC(pos, d); S.GET(ref, ch)
  1019. END;
  1020. IF ch = 0FCX THEN INC(ref); RefNum(ref, d); RefName(ref, name); S.GET(ref, ch) END;
  1021. WHILE ch >= 0FDX DO (* skip variables *)
  1022. INC(ref); RefCh(ref, ch);
  1023. IF ch = 10X THEN INC(ref, 4) END;
  1024. RefNum(ref, d); RefName(ref, name); S.GET(ref, ch)
  1025. END
  1026. END;
  1027. RETURN -1
  1028. END SourcePos;
  1029. (* -------------------- dynamic link libraries --------------------- *)
  1030. (*
  1031. PROCEDURE DlOpen (name: ARRAY OF SHORTCHAR): Dl.HANDLE;
  1032. CONST flags = Dl.RTLD_LAZY + Dl.RTLD_GLOBAL;
  1033. VAR h: Dl.HANDLE;
  1034. i: INTEGER;
  1035. BEGIN
  1036. h := Dl.NULL;
  1037. i := 0; WHILE (i < LEN(name)) & (name[i] # 0X) DO INC(i) END;
  1038. IF i < LEN(name) THEN
  1039. h := Dl.dlopen(name, flags);
  1040. WHILE (h = Dl.NULL) & (i > 0) DO
  1041. DEC(i);
  1042. WHILE (i > 0) & (name[i] # '.') DO DEC(i) END;
  1043. IF i > 0 THEN
  1044. name[i] := 0X;
  1045. h := Dl.dlopen(name, flags);
  1046. (* IF h # Dl.NULL THEN Msg(name$) END *)
  1047. END
  1048. END
  1049. END;
  1050. RETURN h
  1051. END DlOpen;
  1052. *)
  1053. PROCEDURE LoadDll* (IN name: ARRAY OF SHORTCHAR; VAR ok: BOOLEAN);
  1054. VAR h: Dl.HANDLE;
  1055. BEGIN
  1056. ok := FALSE;
  1057. h := Dl.dlopen(name, Dl.RTLD_LAZY + Dl.RTLD_GLOBAL);
  1058. IF h # Dl.NULL THEN ok := TRUE END
  1059. END LoadDll;
  1060. PROCEDURE ThisDllObj* (mode, fprint: INTEGER; IN dll, name: ARRAY OF SHORTCHAR): INTEGER;
  1061. VAR ad: INTEGER; h: Dl.HANDLE;
  1062. BEGIN
  1063. ad := 0;
  1064. IF mode IN {mVar, mProc} THEN
  1065. h := Dl.dlopen(dll, Dl.RTLD_LAZY+ Dl.RTLD_GLOBAL);
  1066. IF h # Dl.NULL THEN
  1067. ad := Dl.dlsym(h, name);
  1068. END
  1069. END;
  1070. RETURN ad
  1071. END ThisDllObj;
  1072. (* -------------------- garbage collector (portable) --------------------- *)
  1073. PROCEDURE Mark (this: Block);
  1074. VAR father, son: Block; tag: Type; flag, offset, actual: INTEGER;
  1075. BEGIN
  1076. IF ~ODD(S.VAL(INTEGER, this.tag)) THEN
  1077. father := NIL;
  1078. LOOP
  1079. INC(S.VAL(INTEGER, this.tag));
  1080. flag := S.VAL(INTEGER, this.tag) MOD 4;
  1081. tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
  1082. IF flag >= 2 THEN actual := this.first; this.actual := actual
  1083. ELSE actual := S.ADR(this.last)
  1084. END;
  1085. LOOP
  1086. offset := tag.ptroffs[0];
  1087. IF offset < 0 THEN
  1088. INC(S.VAL(INTEGER, tag), offset + 4); (* restore tag *)
  1089. IF (flag >= 2) & (actual < this.last) & (offset < -4) THEN (* next array element *)
  1090. INC(actual, tag.size); this.actual := actual
  1091. ELSE (* up *)
  1092. this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
  1093. IF father = NIL THEN RETURN END;
  1094. son := this; this := father;
  1095. flag := S.VAL(INTEGER, this.tag) MOD 4;
  1096. tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
  1097. offset := tag.ptroffs[0];
  1098. IF flag >= 2 THEN actual := this.actual ELSE actual := S.ADR(this.last) END;
  1099. S.GET(actual + offset, father); S.PUT(actual + offset, S.ADR(son.last));
  1100. INC(S.VAL(INTEGER, tag), 4)
  1101. END
  1102. ELSE
  1103. S.GET(actual + offset, son);
  1104. IF son # NIL THEN
  1105. DEC(S.VAL(INTEGER, son), 4);
  1106. IF ~ODD(S.VAL(INTEGER, son.tag)) THEN (* down *)
  1107. this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
  1108. S.PUT(actual + offset, father); father := this; this := son;
  1109. EXIT
  1110. END
  1111. END;
  1112. INC(S.VAL(INTEGER, tag), 4)
  1113. END
  1114. END
  1115. END
  1116. END
  1117. END Mark;
  1118. PROCEDURE MarkGlobals;
  1119. VAR m: Module; i, p: INTEGER;
  1120. BEGIN
  1121. m := modList;
  1122. WHILE m # NIL DO
  1123. IF m.refcnt >= 0 THEN
  1124. i := 0;
  1125. WHILE i < m.nofptrs DO
  1126. S.GET(m.varBase + m.ptrs[i], p); INC(i);
  1127. IF p # 0 THEN Mark(S.VAL(Block, p - 4)) END
  1128. END
  1129. END;
  1130. m := m.next
  1131. END
  1132. END MarkGlobals;
  1133. (* This is the specification for the code procedure following below:
  1134. PROCEDURE Next (b: Block): Block; (* next block in same cluster *)
  1135. VAR size: INTEGER;
  1136. BEGIN
  1137. S.GET(S.VAL(INTEGER, b.tag) DIV 4 * 4, size);
  1138. IF ODD(S.VAL(INTEGER, b.tag) DIV 2) THEN INC(size, b.last - S.ADR(b.last)) END;
  1139. RETURN S.VAL(Block, S.VAL(INTEGER, b) + (size + 19) DIV 16 * 16)
  1140. END Next;
  1141. *)
  1142. PROCEDURE [code] Next (b: Block): Block (* next block in same cluster *)
  1143. (*
  1144. MOV ECX,[EAX] b.tag
  1145. AND CL,0FCH b.tag DIV * 4
  1146. MOV ECX,[ECX] size
  1147. TESTB [EAX],02H ODD(b.tag DIV 2)
  1148. JE L1
  1149. ADD ECX,[EAX,4] size + b.last
  1150. SUB ECX,EAX
  1151. SUB ECX,4 size + b.last - ADR(b.last)
  1152. L1:
  1153. ADD ECX,19 size + 19
  1154. AND CL,0F0H (size + 19) DIV 16 * 16
  1155. ADD EAX,ECX b + size
  1156. *)
  1157. 08BH, 008H,
  1158. 080H, 0E1H, 0FCH,
  1159. 08BH, 009H,
  1160. 0F6H, 000H, 002H,
  1161. 074H, 008H,
  1162. 003H, 048H, 004H,
  1163. 029H, 0C1H,
  1164. 083H, 0E9H, 004H,
  1165. 083H, 0C1H, 013H,
  1166. 080H, 0E1H, 0F0H,
  1167. 001H, 0C8H;
  1168. PROCEDURE CheckCandidates;
  1169. (* pre: nofcand > 0 *)
  1170. VAR i, j, h, p, end: INTEGER; c: Cluster; blk, next: Block;
  1171. BEGIN
  1172. (* sort candidates (shellsort) *)
  1173. h := 1; REPEAT h := h*3 + 1 UNTIL h > nofcand;
  1174. REPEAT h := h DIV 3; i := h;
  1175. WHILE i < nofcand DO p := candidates[i]; j := i;
  1176. WHILE (j >= h) & (candidates[j-h] > p) DO
  1177. candidates[j] := candidates[j-h]; j := j-h
  1178. END;
  1179. candidates[j] := p; INC(i)
  1180. END
  1181. UNTIL h = 1;
  1182. (* sweep *)
  1183. c := root; i := 0;
  1184. WHILE c # NIL DO
  1185. blk := S.VAL(Block, S.VAL(INTEGER, c) + 12);
  1186. end := S.VAL(INTEGER, blk) + (c.size - 12) DIV 16 * 16;
  1187. WHILE candidates[i] < S.VAL(INTEGER, blk) DO
  1188. INC(i);
  1189. IF i = nofcand THEN RETURN END
  1190. END;
  1191. WHILE S.VAL(INTEGER, blk) < end DO
  1192. next := Next(blk);
  1193. IF candidates[i] < S.VAL(INTEGER, next) THEN
  1194. IF (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last)) (* not a free block *)
  1195. & (~strictStackSweep OR (candidates[i] = S.ADR(blk.last))) THEN
  1196. Mark(blk)
  1197. END;
  1198. REPEAT
  1199. INC(i);
  1200. IF i = nofcand THEN RETURN END
  1201. UNTIL candidates[i] >= S.VAL(INTEGER, next)
  1202. END;
  1203. IF (S.VAL(INTEGER, blk.tag) MOD 4 = 0) & (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last))
  1204. & (blk.tag.base[0] = NIL) & (blk.actual > 0) THEN (* referenced interface record *)
  1205. Mark(blk)
  1206. END;
  1207. blk := next
  1208. END;
  1209. c := c.next
  1210. END
  1211. END CheckCandidates;
  1212. PROCEDURE MarkLocals;
  1213. VAR sp, p, min, max: INTEGER; c: Cluster;
  1214. BEGIN
  1215. S.GETREG(FP, sp); nofcand := 0; c := root;
  1216. WHILE c.next # NIL DO c := c.next END;
  1217. min := S.VAL(INTEGER, root); max := S.VAL(INTEGER, c) + c.size;
  1218. WHILE sp < baseStack DO
  1219. S.GET(sp, p);
  1220. IF (p > min) & (p < max) & (~strictStackSweep OR (p MOD 16 = 0)) THEN
  1221. candidates[nofcand] := p; INC(nofcand);
  1222. IF nofcand = LEN(candidates) - 1 THEN CheckCandidates; nofcand := 0 END
  1223. END;
  1224. INC(sp, 4)
  1225. END;
  1226. candidates[nofcand] := max; INC(nofcand); (* ensure complete scan for interface mark*)
  1227. IF nofcand > 0 THEN CheckCandidates END
  1228. END MarkLocals;
  1229. PROCEDURE MarkFinObj;
  1230. VAR f: FList;
  1231. BEGIN
  1232. wouldFinalize := FALSE;
  1233. f := finalizers;
  1234. WHILE f # NIL DO
  1235. IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
  1236. Mark(f.blk);
  1237. f := f.next
  1238. END;
  1239. f := hotFinalizers;
  1240. WHILE f # NIL DO IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
  1241. Mark(f.blk);
  1242. f := f.next
  1243. END
  1244. END MarkFinObj;
  1245. PROCEDURE CheckFinalizers;
  1246. VAR f, g, h, k: FList;
  1247. BEGIN
  1248. f := finalizers; g := NIL;
  1249. IF hotFinalizers = NIL THEN k := NIL
  1250. ELSE
  1251. k := hotFinalizers;
  1252. WHILE k.next # NIL DO k := k.next END
  1253. END;
  1254. WHILE f # NIL DO
  1255. h := f; f := f.next;
  1256. IF ~ODD(S.VAL(INTEGER, h.blk.tag)) THEN
  1257. IF g = NIL THEN finalizers := f ELSE g.next := f END;
  1258. IF k = NIL THEN hotFinalizers := h ELSE k.next := h END;
  1259. k := h; h.next := NIL
  1260. ELSE g := h
  1261. END
  1262. END;
  1263. h := hotFinalizers;
  1264. WHILE h # NIL DO Mark(h.blk); h := h.next END
  1265. END CheckFinalizers;
  1266. PROCEDURE ExecFinalizer (a, b, c: INTEGER);
  1267. VAR f: FList; fin: PROCEDURE(this: ANYPTR);
  1268. BEGIN
  1269. f := S.VAL(FList, a);
  1270. IF f.aiptr THEN (* ArrFinalizer(S.VAL(ANYPTR, S.ADR(f.blk.last))) *)
  1271. ELSE
  1272. S.GET(S.VAL(INTEGER, f.blk.tag) - 4, fin); (* method 0 *)
  1273. IF (fin # NIL) & (f.blk.tag.mod.refcnt >= 0) THEN fin(S.VAL(ANYPTR, S.ADR(f.blk.last))) END;
  1274. (*
  1275. IF f.iptr THEN RecFinalizer(S.VAL(ANYPTR, S.ADR(f.blk.last))) END
  1276. *)
  1277. END
  1278. END ExecFinalizer;
  1279. PROCEDURE^ Try* (h: TryHandler; a, b, c: INTEGER); (* COMPILER DEPENDENT *)
  1280. PROCEDURE CallFinalizers;
  1281. VAR f: FList;
  1282. BEGIN
  1283. WHILE hotFinalizers # NIL DO
  1284. f := hotFinalizers; hotFinalizers := hotFinalizers.next;
  1285. Try(ExecFinalizer, S.VAL(INTEGER, f), 0, 0)
  1286. END;
  1287. wouldFinalize := FALSE
  1288. END CallFinalizers;
  1289. PROCEDURE Insert (blk: FreeBlock; size: INTEGER); (* insert block in free list *)
  1290. VAR i: INTEGER;
  1291. BEGIN
  1292. blk.size := size - 4; blk.tag := S.VAL(Type, S.ADR(blk.size));
  1293. i := MIN(N - 1, (blk.size DIV 16));
  1294. blk.next := free[i]; free[i] := blk
  1295. END Insert;
  1296. PROCEDURE Sweep (dealloc: BOOLEAN);
  1297. VAR cluster, last, c: Cluster; blk, next: Block; fblk, b, t: FreeBlock; end, i: INTEGER;
  1298. BEGIN
  1299. cluster := root; last := NIL; allocated := 0;
  1300. i := N;
  1301. REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
  1302. WHILE cluster # NIL DO
  1303. blk := S.VAL(Block, S.VAL(INTEGER, cluster) + 12);
  1304. end := S.VAL(INTEGER, blk) + (cluster.size - 12) DIV 16 * 16;
  1305. fblk := NIL;
  1306. WHILE S.VAL(INTEGER, blk) < end DO
  1307. next := Next(blk);
  1308. IF ODD(S.VAL(INTEGER, blk.tag)) THEN
  1309. IF fblk # NIL THEN
  1310. Insert(fblk, S.VAL(INTEGER, blk) - S.VAL(INTEGER, fblk));
  1311. fblk := NIL
  1312. END;
  1313. DEC(S.VAL(INTEGER, blk.tag)); (* unmark *)
  1314. INC(allocated, S.VAL(INTEGER, next) - S.VAL(INTEGER, blk))
  1315. ELSIF fblk = NIL THEN
  1316. fblk := S.VAL(FreeBlock, blk)
  1317. END;
  1318. blk := next
  1319. END;
  1320. IF dealloc & (S.VAL(INTEGER, fblk) = S.VAL(INTEGER, cluster) + 12) THEN (* deallocate cluster *)
  1321. c := cluster; cluster := cluster.next;
  1322. IF last = NIL THEN root := cluster ELSE last.next := cluster END;
  1323. FreeHeapMem(c)
  1324. ELSE
  1325. IF fblk # NIL THEN Insert(fblk, end - S.VAL(INTEGER, fblk)) END;
  1326. last := cluster; cluster := cluster.next
  1327. END
  1328. END;
  1329. (* reverse free list *)
  1330. i := N;
  1331. REPEAT
  1332. DEC(i);
  1333. b := free[i]; fblk := sentinel;
  1334. WHILE b # sentinel DO t := b; b := t.next; t.next := fblk; fblk := t END;
  1335. free[i] := fblk
  1336. UNTIL i = 0
  1337. END Sweep;
  1338. PROCEDURE Collect*;
  1339. BEGIN
  1340. IF root # NIL THEN
  1341. CallFinalizers; (* trap cleanup *)
  1342. IF debug & (watcher # NIL) THEN watcher(1) END;
  1343. MarkGlobals;
  1344. MarkLocals;
  1345. CheckFinalizers;
  1346. Sweep(TRUE);
  1347. CallFinalizers
  1348. END
  1349. END Collect;
  1350. PROCEDURE FastCollect*;
  1351. BEGIN
  1352. IF root # NIL THEN
  1353. IF debug & (watcher # NIL) THEN watcher(2) END;
  1354. MarkGlobals;
  1355. MarkLocals;
  1356. MarkFinObj;
  1357. Sweep(FALSE)
  1358. END
  1359. END FastCollect;
  1360. PROCEDURE WouldFinalize* (): BOOLEAN;
  1361. BEGIN
  1362. RETURN wouldFinalize
  1363. END WouldFinalize;
  1364. (* --------------------- memory allocation (portable) -------------------- *)
  1365. PROCEDURE OldBlock (size: INTEGER): FreeBlock; (* size MOD 16 = 0 *)
  1366. VAR b, l: FreeBlock; s, i: INTEGER;
  1367. BEGIN
  1368. IF debug & (watcher # NIL) THEN watcher(3) END;
  1369. s := size - 4;
  1370. i := MIN(N - 1, s DIV 16);
  1371. WHILE (i # N - 1) & (free[i] = sentinel) DO INC(i) END;
  1372. b := free[i]; l := NIL;
  1373. WHILE b.size < s DO l := b; b := b.next END;
  1374. IF b # sentinel THEN
  1375. IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
  1376. ELSE b := NIL
  1377. END;
  1378. RETURN b
  1379. END OldBlock;
  1380. PROCEDURE LastBlock (limit: INTEGER): FreeBlock; (* size MOD 16 = 0 *)
  1381. VAR b, l: FreeBlock; s, i: INTEGER;
  1382. BEGIN
  1383. s := limit - 4;
  1384. i := 0;
  1385. REPEAT
  1386. b := free[i]; l := NIL;
  1387. WHILE (b # sentinel) & (S.VAL(INTEGER, b) + b.size # s) DO l := b; b := b.next END;
  1388. IF b # sentinel THEN
  1389. IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
  1390. ELSE b := NIL
  1391. END;
  1392. INC(i)
  1393. UNTIL (b # NIL) OR (i = N);
  1394. RETURN b
  1395. END LastBlock;
  1396. PROCEDURE NewBlock (size: INTEGER): Block;
  1397. VAR tsize, a, s: INTEGER; b: FreeBlock; new, c: Cluster; r: Reducer;
  1398. BEGIN
  1399. ASSERT(size>=0,20);
  1400. IF size >7FFFFFECH THEN RETURN NIL END; (*20120822 Marc*)
  1401. tsize := (size + 19) DIV 16 * 16;
  1402. b := OldBlock(tsize); (* 1) search for free block *)
  1403. IF b = NIL THEN
  1404. FastCollect; b := OldBlock(tsize); (* 2) collect *)
  1405. IF b = NIL THEN
  1406. Collect; b := OldBlock(tsize); (* 2a) fully collect *)
  1407. END;
  1408. IF b = NIL THEN
  1409. AllocHeapMem(tsize + 12, new); (* 3) allocate new cluster *)
  1410. IF new # NIL THEN
  1411. IF (root = NIL) OR (S.VAL(INTEGER, new) < S.VAL(INTEGER, root)) THEN
  1412. new.next := root; root := new
  1413. ELSE
  1414. c := root;
  1415. WHILE (c.next # NIL) & (S.VAL(INTEGER, new) > S.VAL(INTEGER, c.next)) DO c := c.next END;
  1416. new.next := c.next; c.next := new
  1417. END;
  1418. b := S.VAL(FreeBlock, S.VAL(INTEGER, new) + 12);
  1419. b.size := (new.size - 12) DIV 16 * 16 - 4
  1420. ELSE
  1421. RETURN NIL (* 4) give up *)
  1422. END
  1423. END
  1424. END;
  1425. (* b # NIL *)
  1426. a := b.size + 4 - tsize;
  1427. IF a > 0 THEN Insert(S.VAL(FreeBlock, S.VAL(INTEGER, b) + tsize), a) END;
  1428. IF size > 0 THEN Erase(S.ADR(b.size), (size + 3) DIV 4) END;
  1429. INC(allocated, tsize);
  1430. RETURN S.VAL(Block, b)
  1431. END NewBlock;
  1432. PROCEDURE Allocated* (): INTEGER;
  1433. BEGIN
  1434. RETURN allocated
  1435. END Allocated;
  1436. PROCEDURE Used* (): INTEGER;
  1437. BEGIN
  1438. RETURN used
  1439. END Used;
  1440. PROCEDURE Root* (): INTEGER;
  1441. BEGIN
  1442. RETURN S.VAL(INTEGER, root)
  1443. END Root;
  1444. (* -------------------- Trap Handling --------------------- *)
  1445. PROCEDURE^ InitFpu;
  1446. PROCEDURE Start* (code: Command);
  1447. BEGIN
  1448. restart := code;
  1449. (*
  1450. S.GETREG(SP, baseStack); (* save base stack *)
  1451. *)
  1452. res := Libc.sigsetjmp(loopContext, Libc.TRUE);
  1453. code()
  1454. END Start;
  1455. PROCEDURE Quit* (exitCode: INTEGER);
  1456. VAR m: Module; term: Command; t: BOOLEAN;
  1457. res: INTEGER;
  1458. BEGIN
  1459. trapViewer := NIL; trapChecker := NIL; restart := NIL;
  1460. t := terminating; terminating := TRUE; m := modList;
  1461. WHILE m # NIL DO (* call terminators *)
  1462. IF ~static OR ~t THEN
  1463. term := m.term; m.term := NIL;
  1464. IF term # NIL THEN term() END
  1465. END;
  1466. (*
  1467. ReleaseIPtrs(m);
  1468. *)
  1469. m := m.next
  1470. END;
  1471. CallFinalizers;
  1472. hotFinalizers := finalizers; finalizers := NIL;
  1473. CallFinalizers;
  1474. (*
  1475. IF ~inDll THEN
  1476. RemoveExcp(excpPtr^);
  1477. WinApi.ExitProcess(exitCode) (* never returns *)
  1478. END
  1479. *)
  1480. res := Libc.fflush(0);
  1481. Libc.exit(exitCode)
  1482. END Quit;
  1483. PROCEDURE FatalError* (id: INTEGER; str: ARRAY OF CHAR);
  1484. VAR res: INTEGER; title: ARRAY 16 OF CHAR; text: ARRAY 256 OF SHORTCHAR;
  1485. BEGIN
  1486. title := "Error xy";
  1487. title[6] := CHR(id DIV 10 + ORD("0"));
  1488. title[7] := CHR(id MOD 10 + ORD("0"));
  1489. (*
  1490. res := WinApi.MessageBoxW(0, str, title, {});
  1491. *)
  1492. text := SHORT(str$);
  1493. res := MessageBox(title$, SHORT(str), {mbOk});
  1494. (*
  1495. IF ~inDll THEN RemoveExcp(excpPtr^) END;
  1496. *)
  1497. (*
  1498. WinApi.ExitProcess(1)
  1499. *)
  1500. Libc.exit(1)
  1501. (* never returns *)
  1502. END FatalError;
  1503. PROCEDURE DefaultTrapViewer;
  1504. VAR len, ref, end, x, a, b, c: INTEGER; mod: Module;
  1505. name: Name; out: ARRAY 1024 OF SHORTCHAR;
  1506. PROCEDURE WriteString (s: ARRAY OF SHORTCHAR);
  1507. VAR i: INTEGER;
  1508. BEGIN
  1509. i := 0;
  1510. WHILE (len < LEN(out) - 1) & (s[i] # 0X) DO out[len] := s[i]; INC(i); INC(len) END
  1511. END WriteString;
  1512. PROCEDURE WriteHex (x, n: INTEGER);
  1513. VAR i, y: INTEGER;
  1514. BEGIN
  1515. IF len + n < LEN(out) THEN
  1516. i := len + n - 1;
  1517. WHILE i >= len DO
  1518. y := x MOD 16; x := x DIV 16;
  1519. IF y > 9 THEN y := y + (ORD("A") - ORD("0") - 10) END;
  1520. out[i] := SHORT(CHR(y + ORD("0"))); DEC(i)
  1521. END;
  1522. INC(len, n)
  1523. END
  1524. END WriteHex;
  1525. PROCEDURE WriteLn;
  1526. BEGIN
  1527. IF len < LEN(out) - 1 THEN out[len] := 0AX (* 0DX on Windows *); INC(len) END
  1528. END WriteLn;
  1529. BEGIN
  1530. len := 0;
  1531. IF err = 129 THEN WriteString("invalid with")
  1532. ELSIF err = 130 THEN WriteString("invalid case")
  1533. ELSIF err = 131 THEN WriteString("function without return")
  1534. ELSIF err = 132 THEN WriteString("type guard")
  1535. ELSIF err = 133 THEN WriteString("implied type guard")
  1536. ELSIF err = 134 THEN WriteString("value out of range")
  1537. ELSIF err = 135 THEN WriteString("index out of range")
  1538. ELSIF err = 136 THEN WriteString("string too long")
  1539. ELSIF err = 137 THEN WriteString("stack overflow")
  1540. ELSIF err = 138 THEN WriteString("integer overflow")
  1541. ELSIF err = 139 THEN WriteString("division by zero")
  1542. ELSIF err = 140 THEN WriteString("infinite real result")
  1543. ELSIF err = 141 THEN WriteString("real underflow")
  1544. ELSIF err = 142 THEN WriteString("real overflow")
  1545. ELSIF err = 143 THEN WriteString("undefined real result")
  1546. ELSIF err = 200 THEN WriteString("keyboard interrupt")
  1547. ELSIF err = 202 THEN WriteString("illegal instruction: ");
  1548. WriteHex(val, 4)
  1549. ELSIF err = 203 THEN WriteString("illegal memory read [ad = ");
  1550. WriteHex(val, 8); WriteString("]")
  1551. ELSIF err = 204 THEN WriteString("illegal memory write [ad = ");
  1552. WriteHex(val, 8); WriteString("]")
  1553. ELSIF err = 205 THEN WriteString("illegal execution [ad = ");
  1554. WriteHex(val, 8); WriteString("]")
  1555. ELSIF err < 0 THEN WriteString("exception #"); WriteHex(-err, 2)
  1556. ELSE err := err DIV 100 * 256 + err DIV 10 MOD 10 * 16 + err MOD 10;
  1557. WriteString("trap #"); WriteHex(err, 3)
  1558. END;
  1559. a := pc; b := fp; c := 12;
  1560. REPEAT
  1561. WriteLn; WriteString("- ");
  1562. mod := modList;
  1563. WHILE (mod # NIL) & ((a < mod.code) OR (a >= mod.code + mod.csize)) DO mod := mod.next END;
  1564. IF mod # NIL THEN
  1565. DEC(a, mod.code);
  1566. IF mod.refcnt >= 0 THEN
  1567. WriteString(mod.name); ref := mod.refs;
  1568. REPEAT GetRefProc(ref, end, name) UNTIL (end = 0) OR (a < end);
  1569. IF a < end THEN
  1570. WriteString("."); WriteString(name)
  1571. END
  1572. ELSE
  1573. WriteString("("); WriteString(mod.name); WriteString(")")
  1574. END;
  1575. WriteString(" ")
  1576. END;
  1577. WriteString("(pc="); WriteHex(a, 8);
  1578. WriteString(", fp="); WriteHex(b, 8); WriteString(")");
  1579. IF (b >= sp) & (b < stack) THEN
  1580. S.GET(b+4, a); (* stacked pc *)
  1581. S.GET(b, b); (* dynamic link *)
  1582. DEC(c)
  1583. ELSE c := 0
  1584. END
  1585. UNTIL c = 0;
  1586. out[len] := 0X;
  1587. x := MessageBox("BlackBox", out$, {mbOk})
  1588. END DefaultTrapViewer;
  1589. PROCEDURE TrapCleanup;
  1590. VAR t: TrapCleaner;
  1591. BEGIN
  1592. WHILE trapStack # NIL DO
  1593. t := trapStack; trapStack := trapStack.next; t.Cleanup
  1594. END;
  1595. IF (trapChecker # NIL) & (err # 128) THEN trapChecker END
  1596. END TrapCleanup;
  1597. PROCEDURE SetTrapGuard* (on: BOOLEAN);
  1598. BEGIN
  1599. guarded := on
  1600. END SetTrapGuard;
  1601. PROCEDURE Try* (h: TryHandler; a, b, c: INTEGER);
  1602. VAR res: INTEGER; context: Libc.sigjmp_buf; oldContext: POINTER TO Libc.sigjmp_buf;
  1603. BEGIN
  1604. oldContext := currentTryContext;
  1605. res := Libc.sigsetjmp(context, Libc.TRUE);
  1606. currentTryContext := S.ADR(context);
  1607. IF res = 0 THEN (* first time around *)
  1608. h(a, b, c);
  1609. ELSIF res = trapReturn THEN (* after a trap *)
  1610. ELSE
  1611. HALT(100)
  1612. END;
  1613. currentTryContext := oldContext;
  1614. END Try;
  1615. (* -------------------- Initialization --------------------- *)
  1616. PROCEDURE InitFpu; (* COMPILER DEPENDENT *)
  1617. (* could be eliminated, delayed for backward compatibility *)
  1618. VAR cw: SET;
  1619. BEGIN
  1620. FINIT;
  1621. FSTCW;
  1622. (* denorm, underflow, precision, zero div, overflow masked *)
  1623. (* invalid trapped *)
  1624. (* round to nearest, temp precision *)
  1625. cw := cw - {0..5, 8..11} + {1, 2, 3, 4, 5, 8, 9};
  1626. FLDCW
  1627. END InitFpu;
  1628. PROCEDURE (* [ccall] *) TrapHandler (sig: INTEGER; siginfo: Libc.Ptrsiginfo_t; context: Libc.Ptrucontext_t);
  1629. BEGIN
  1630. IF isReadableCheck THEN
  1631. isReadableCheck := FALSE;
  1632. Msg("~IsReadable");
  1633. Libc.siglongjmp(isReadableContext, 1)
  1634. END;
  1635. (*
  1636. S.GETREG(SP, sp);
  1637. S.GETREG(FP, fp);
  1638. *)
  1639. stack := baseStack;
  1640. sp := context.uc_mcontext.gregs[7]; (* TODO: is the stack pointer really stored in register 7? *)
  1641. fp := context.uc_mcontext.gregs[6]; (* TODO: is the frame pointer really stored in register 6? *)
  1642. pc := context.uc_mcontext.gregs[14]; (* TODO: is the pc really stored in register 14? *)
  1643. val := siginfo.si_addr;
  1644. (*
  1645. Int(sig); Int(siginfo.si_signo); Int(siginfo.si_code); Int(siginfo.si_errno);
  1646. Int(siginfo.si_status); Int(siginfo.si_value); Int(siginfo.si_int);
  1647. *)
  1648. err := sig;
  1649. IF trapped THEN DefaultTrapViewer END;
  1650. CASE sig OF
  1651. Libc.SIGINT:
  1652. err := 200 (* Interrupt (ANSI). *)
  1653. | Libc.SIGILL: (* Illegal instruction (ANSI). *)
  1654. err := 202; val := 0;
  1655. IF IsReadable(pc, pc + 4) THEN
  1656. S.GET(pc, val);
  1657. IF val MOD 100H = 8DH THEN (* lea reg,reg *)
  1658. IF val DIV 100H MOD 100H = 0F0H THEN
  1659. err := val DIV 10000H MOD 100H (* trap *)
  1660. ELSIF val DIV 1000H MOD 10H = 0EH THEN
  1661. err := 128 + val DIV 100H MOD 10H (* run time error *)
  1662. END
  1663. END
  1664. END
  1665. | Libc.SIGFPE:
  1666. CASE siginfo.si_code OF
  1667. 0: (* TODO: ?????? *)
  1668. IF siginfo.si_int = 8 THEN
  1669. err := 139
  1670. ELSIF siginfo.si_int = 0 THEN
  1671. err := 143
  1672. END
  1673. | Libc.FPE_INTDIV: err := 139 (* Integer divide by zero. *)
  1674. | Libc.FPE_INTOVF: err := 138 (* Integer overflow. *)
  1675. | Libc.FPE_FLTDIV: err := 140 (* Floating point divide by zero. *)
  1676. | Libc.FPE_FLTOVF: err := 142 (* Floating point overflow. *)
  1677. | Libc.FPE_FLTUND: err := 141 (* Floating point underflow. *)
  1678. | Libc.FPE_FLTRES: err := 143 (* Floating point inexact result. *)
  1679. | Libc.FPE_FLTINV: err := 143 (* Floating point invalid operation. *)
  1680. | Libc.FPE_FLTSUB: err := 134 (* Subscript out of range. *)
  1681. ELSE
  1682. END
  1683. | Libc.SIGSEGV: (* Segmentation violation (ANSI). *)
  1684. err := 203
  1685. ELSE
  1686. END;
  1687. INC(trapCount);
  1688. InitFpu;
  1689. TrapCleanup;
  1690. IF err # 128 THEN
  1691. IF (trapViewer = NIL) OR trapped THEN
  1692. DefaultTrapViewer
  1693. ELSE
  1694. trapped := TRUE;
  1695. trapViewer();
  1696. trapped := FALSE
  1697. END
  1698. END;
  1699. IF currentTryContext # NIL THEN (* Try failed *)
  1700. Libc.siglongjmp(currentTryContext, trapReturn)
  1701. ELSE
  1702. IF restart # NIL THEN (* Start failed *)
  1703. Libc.siglongjmp(loopContext, trapReturn)
  1704. END;
  1705. Quit(1); (* FIXME *)
  1706. END;
  1707. trapped := FALSE
  1708. END TrapHandler;
  1709. PROCEDURE InstallSignals*;
  1710. VAR sa, old: Libc.sigaction_t; res, i: INTEGER;
  1711. (*
  1712. sigstk: Libc.stack_t;
  1713. errno: INTEGER;
  1714. *)
  1715. BEGIN
  1716. (*
  1717. (* A. V. Shiryaev: Set alternative stack on which signals are to be processed *)
  1718. sigstk.ss_sp := sigStack;
  1719. sigstk.ss_size := sigStackSize;
  1720. sigstk.ss_flags := 0;
  1721. res := Libc.sigaltstack(sigstk, NIL);
  1722. IF res # 0 THEN Msg("ERROR: Kernel.InstallSignals: sigaltstack failed!");
  1723. S.GET( Libc.__errno_location(), errno );
  1724. Int(errno);
  1725. Libc.exit(1)
  1726. END;
  1727. *)
  1728. sa.sa_sigaction := TrapHandler;
  1729. (*
  1730. res := LinLibc.sigemptyset(S.ADR(sa.sa_mask));
  1731. *)
  1732. res := Libc.sigfillset(S.ADR(sa.sa_mask));
  1733. sa.sa_flags := (* Libc.SA_ONSTACK + *) Libc.SA_SIGINFO; (* TrapHandler takes three arguments *)
  1734. (*
  1735. IF LinLibc.sigaction(LinLibc.SIGINT, sa, old) # 0 THEN Msg("failed to install SIGINT") END;
  1736. IF LinLibc.sigaction(LinLibc.SIGILL, sa, old) # 0 THEN Msg("failed to install SIGILL") END;
  1737. IF LinLibc.sigaction(LinLibc.SIGFPE, sa, old) # 0 THEN Msg("failed to install SIGFPE") END;
  1738. IF LinLibc.sigaction(LinLibc.SIGSEGV, sa, old) # 0 THEN Msg("failed to install SIGSEGV") END;
  1739. IF LinLibc.sigaction(LinLibc.SIGPIPE, sa, old) # 0 THEN Msg("failed to install SIGPIPE") END;
  1740. IF LinLibc.sigaction(LinLibc.SIGTERM, sa, old) # 0 THEN Msg("failed to install SIGTERM") END;
  1741. *)
  1742. (* respond to all possible signals *)
  1743. FOR i := 1 TO Libc._NSIG - 1 DO
  1744. IF (i # Libc.SIGKILL)
  1745. & (i # Libc.SIGSTOP)
  1746. & (i # Libc.SIGWINCH)
  1747. THEN
  1748. IF Libc.sigaction(i, sa, old) # 0 THEN (* Msg("failed to install signal"); Int(i) *) END;
  1749. END
  1750. END
  1751. END InstallSignals;
  1752. PROCEDURE Init;
  1753. VAR i: INTEGER;
  1754. BEGIN
  1755. (*
  1756. (* for sigaltstack *)
  1757. sigStack := Libc.calloc(1, sigStackSize);
  1758. IF sigStack = Libc.NULL THEN
  1759. Msg("ERROR: Kernel.Init: calloc(1, sigStackSize) failed!");
  1760. Libc.exit(1)
  1761. END;
  1762. *)
  1763. (* for mmap *)
  1764. zerofd := Libc.open("/dev/zero", Libc.O_RDWR, {0..8});
  1765. IF zerofd < 0 THEN
  1766. Msg("ERROR: Kernel.Init: can not open /dev/zero!");
  1767. Libc.exit(1)
  1768. END;
  1769. (* for mprotect *)
  1770. pageSize := Libc.sysconf(Libc._SC_PAGESIZE);
  1771. IF pageSize < 0 THEN
  1772. Msg("ERROR: Kernel.Init: pageSize < 0!");
  1773. Libc.exit(1)
  1774. END;
  1775. isReadableCheck := FALSE;
  1776. InstallSignals; (* init exception handling *)
  1777. currentTryContext := NIL;
  1778. allocated := 0; total := 0; used := 0;
  1779. sentinelBlock.size := MAX(INTEGER);
  1780. sentinel := S.ADR(sentinelBlock);
  1781. (*
  1782. S.PUTREG(ML, S.ADR(modList));
  1783. *)
  1784. i := N;
  1785. REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
  1786. IF inDll THEN
  1787. (*
  1788. baseStack := FPageWord(4); (* begin of stack segment *)
  1789. *)
  1790. END;
  1791. InitFpu;
  1792. IF ~static THEN
  1793. InitModule(modList);
  1794. IF ~inDll THEN Quit(1) END
  1795. END;
  1796. told := 0; shift := 0
  1797. END Init;
  1798. PROCEDURE SetCmdLine;
  1799. VAR i, l: INTEGER;
  1800. BEGIN
  1801. l := LEN(cmdLine);
  1802. cmdLine := bootInfo.argv[0]$;
  1803. FOR i := 1 TO bootInfo.argc - 1 DO cmdLine := cmdLine + " " + bootInfo.argv[i]END
  1804. END SetCmdLine;
  1805. PROCEDURE SetCmdLine2;
  1806. VAR x: Libc.PtrSTR;
  1807. BEGIN
  1808. x := Libc.getenv("CMDLINE");
  1809. IF x # NIL THEN
  1810. cmdLine := x$
  1811. END
  1812. END SetCmdLine2;
  1813. BEGIN
  1814. IF modList = NIL THEN (* only once *)
  1815. S.GETREG(SP, baseStack); (* TODO: Check that this is ok. *)
  1816. IF bootInfo # NIL THEN
  1817. modList := bootInfo.modList; (* boot loader initializes the bootInfo struct *)
  1818. SetCmdLine
  1819. ELSE
  1820. S.GETREG(ML, modList); (* linker loads module list to BX *)
  1821. SetCmdLine2
  1822. END;
  1823. static := init IN modList.opts;
  1824. inDll := dll IN modList.opts;
  1825. Init
  1826. END
  1827. CLOSE
  1828. IF ~terminating THEN
  1829. terminating := TRUE;
  1830. Quit(0)
  1831. END
  1832. END Kernel.