Kernel.txt 58 KB

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