Kernel.txt 56 KB

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