Kernel.txt 58 KB

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