pagemem.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. {
  2. $Id: $
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2004 by Daniel Mantione
  5. member of the Free Pascal development team
  6. Implements a memory manager that makes use of the fact that
  7. a program is running in a virtual address space where pages
  8. can be allocated at random, instead of a more traditional
  9. growing heap.
  10. See the file COPYING.FPC, included in this distribution,
  11. for details about the copyright.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. **********************************************************************}
  16. {$IFNDEF FPC_DOTTEDUNITS}
  17. unit pagemem;
  18. {$ENDIF FPC_DOTTEDUNITS}
  19. {*****************************************************************************}
  20. interface
  21. {*****************************************************************************}
  22. {*****************************************************************************}
  23. implementation
  24. {*****************************************************************************}
  25. {$packrecords 1}
  26. {$packenum 1}
  27. type Tpage_type=(pt_8byte_with_bitmap,pt_suballocation,pt_direct_page);
  28. Ppage_type=^Tpage_type;
  29. Pcriterium=^Tcriterium;
  30. Tcriterium=record
  31. criterium1,criterium2:cardinal;
  32. end;
  33. Ptree_struct=^Ttree_struct;
  34. Ttree_struct=record
  35. left,right:ptruint;
  36. end;
  37. {This page layout is targeted at very short strings and linked lists
  38. with very low payload. It uses fixed memory sizes of 8 byte. Memory
  39. overhead should be avoided at all here. An allocation bitmap does this
  40. very well, only 1 bit per memory block.}
  41. Ppage_8byte_with_bitmap=^Tpage_8byte_with_bitmap;
  42. Tpage_8byte_with_bitmap=record
  43. page_type:Tpage_type;
  44. search_index:byte;
  45. free_count:word;
  46. page_birthyear:cardinal;
  47. freelist_prev,freelist_next:Ppage_8byte_with_bitmap;
  48. block_allocation_map:array[0..15] of cardinal;
  49. end;
  50. Ppage_suballocation=^Tpage_suballocation;
  51. Tpage_suballocation=record
  52. page_type:Tpage_type;
  53. reserved:array[1..3] of byte;
  54. page_birthyear:cardinal;
  55. end;
  56. {This page layout is targeted at large memory blocks. We allocate
  57. pages directly from the OS for such blocks.}
  58. Ppage_direct=^Tpage_direct;
  59. Tpage_direct=record
  60. page_type:Tpage_type;
  61. reserved:array[1..3] of byte;
  62. size:cardinal;
  63. end;
  64. Pfree_block=^Tfree_block;
  65. Tfree_block=record
  66. size:cardinal;
  67. tree_sizememloc:Ttree_struct;
  68. tree_memlocation:Ttree_struct;
  69. end;
  70. Tsplay_status=(ts_not_found,ts_found_on_left,
  71. ts_found_on_p,ts_found_on_right);
  72. Psuballoc_header=^Tsuballoc_header;
  73. Tsuballoc_header=record
  74. alloc_size:ptruint;
  75. end;
  76. const tree_sizememloc_offset=4;
  77. tree_memlocation_offset=12;
  78. page_size=4096;
  79. page_shift=12;
  80. page_mask=$00000fff;
  81. page_8byte_with_bitmap_maxspace=
  82. (page_size-sizeof(Tpage_8byte_with_bitmap)) div 8;
  83. memblock_align=4;
  84. memblock_alignround=memblock_align-1;
  85. min_suballoc_size=sizeof(Tfree_block);
  86. const freelist_8byte_with_bitmap:Ppage_8byte_with_bitmap=nil;
  87. page_8byte_with_bitmap_init:Tpage_8byte_with_bitmap=
  88. (
  89. page_type:pt_8byte_with_bitmap;
  90. search_index:0;
  91. free_count:page_8byte_with_bitmap_maxspace;
  92. page_birthyear:0;
  93. freelist_prev:nil;
  94. freelist_next:nil;
  95. block_allocation_map:($ffffffff,$ffffffff,$ffffffff,$ffffffff,
  96. $ffffffff,$ffffffff,$ffffffff,$ffffffff,
  97. $ffffffff,$ffffffff,$ffffffff,$ffffffff,
  98. $ffffffff,$ffffffff,$ffffffff,$ffffffff)
  99. );
  100. var tree_sizememloc,tree_memlocation:Pfree_block;
  101. {****************************************************************************
  102. Page allocation/deallocation
  103. ****************************************************************************}
  104. function fpmmap(adr:pointer;len,prot,flags,fd,off:sizeint):pointer;external name 'FPC_SYSC_MMAP';
  105. function fpmunmap(adr:pointer;len:sizeint):pointer;external name 'FPC_SYSC_MUNMAP';
  106. function geterrno:longint;external name 'FPC_SYS_GETERRNO';
  107. const PROT_READ = $1; { page can be read }
  108. PROT_WRITE = $2; { page can be written }
  109. PROT_EXEC = $4; { page can be executed }
  110. PROT_NONE = $0; { page can not be accessed }
  111. MAP_SHARED = $1; { Share changes }
  112. MAP_PRIVATE = $2; { Changes are private }
  113. MAP_TYPE = $f; { Mask for type of mapping }
  114. MAP_FIXED = $10; { Interpret addr exactly }
  115. MAP_ANONYMOUS = $20; { don't use a file }
  116. MAP_GROWSDOWN = $100; { stack-like segment }
  117. MAP_DENYWRITE = $800; { ETXTBSY }
  118. MAP_EXECUTABLE = $1000; { mark it as an executable }
  119. MAP_LOCKED = $2000; { pages are locked }
  120. MAP_NORESERVE = $4000; { don't check for reservations }
  121. function req_pages(count:cardinal):pointer;
  122. {Requests count consecutive pages from the OS.}
  123. begin
  124. req_pages:=fpmmap(nil,count shl page_shift,PROT_READ or PROT_WRITE,
  125. MAP_PRIVATE or MAP_ANONYMOUS,0,0);
  126. if geterrno<>0 then
  127. req_pages:=nil; {This one can fail, so we can handle an out of memory
  128. situation.}
  129. end;
  130. procedure sack_pages(p:pointer;count:cardinal);
  131. begin
  132. fpmunmap(p,count shl page_shift);
  133. if geterrno<>0 then
  134. runerror(204); {This one should succees.}
  135. end;
  136. {****************************************************************************
  137. 8-bit bitmap allocated memory
  138. ****************************************************************************}
  139. procedure new_page_8byte_with_bitmap;
  140. var page:Ppage_8byte_with_bitmap;
  141. begin
  142. page:=req_pages(1);
  143. page^:=page_8byte_with_bitmap_init;
  144. page^.freelist_next:=freelist_8byte_with_bitmap;
  145. page^.freelist_prev:=nil;
  146. if freelist_8byte_with_bitmap<>nil then
  147. freelist_8byte_with_bitmap^.freelist_prev:=page;
  148. freelist_8byte_with_bitmap:=page;
  149. end;
  150. function pgetmem_8byte_with_bitmap:pointer;
  151. var page:Ppage_8byte_with_bitmap;
  152. bit:cardinal;
  153. begin
  154. if freelist_8byte_with_bitmap=nil then
  155. new_page_8byte_with_bitmap;
  156. page:=freelist_8byte_with_bitmap;
  157. with page^ do
  158. begin
  159. {Search a dword in which a bit is set.}
  160. while block_allocation_map[search_index]=0 do
  161. search_index:=(search_index+1) and 15;
  162. ptrint(pgetmem_8byte_with_bitmap):=ptrint(page)+sizeof(page^)+search_index*256;
  163. {Search for a set bit in the dword.}
  164. bit:=1;
  165. while block_allocation_map[search_index] and bit=0 do
  166. begin
  167. bit:=bit shl 1;
  168. inc(ptrint(pgetmem_8byte_with_bitmap),8);
  169. end;
  170. {Allocate the block.}
  171. block_allocation_map[search_index]:=block_allocation_map[search_index] and not bit;
  172. dec(free_count);
  173. if free_count=0 then
  174. begin
  175. {There is no space left in this page. Remove it from the freelist.}
  176. if freelist_next<>nil then
  177. freelist_next^.freelist_prev:=freelist_prev;
  178. if freelist_prev<>nil then
  179. freelist_prev^.freelist_next:=freelist_next;
  180. if freelist_8byte_with_bitmap=page then
  181. freelist_8byte_with_bitmap:=freelist_next;
  182. freelist_prev:=nil;
  183. freelist_next:=nil;
  184. end;
  185. end;
  186. end;
  187. function pfreemem_8byte_with_bitmap(page:Ppage_8byte_with_bitmap;p:pointer):ptrint;
  188. var index,bit:cardinal;
  189. begin
  190. index:=(ptrint(p)-ptrint(page)-sizeof(page^)) div 8;
  191. bit:=index and 31;
  192. index:=index shr 5;
  193. with page^ do
  194. begin
  195. if free_count=0 then
  196. begin
  197. {Page will get free slots. Must be included in freelist.}
  198. if freelist_8byte_with_bitmap=nil then
  199. freelist_8byte_with_bitmap:=page
  200. else
  201. begin
  202. freelist_next:=freelist_8byte_with_bitmap;
  203. freelist_8byte_with_bitmap^.freelist_prev:=page;
  204. freelist_8byte_with_bitmap:=page;
  205. end;
  206. {Make sure the next allocation finds the slot without much searching.}
  207. search_index:=index;
  208. end;
  209. block_allocation_map[index]:=block_allocation_map[index] or (1 shl bit);
  210. inc(free_count);
  211. if free_count=page_8byte_with_bitmap_maxspace then
  212. begin
  213. {The page is completely free. It can be returned to the OS, but
  214. remove it from the freelist first.}
  215. if freelist_next<>nil then
  216. freelist_next^.freelist_prev:=freelist_prev;
  217. if freelist_prev<>nil then
  218. freelist_prev^.freelist_next:=freelist_next;
  219. if freelist_8byte_with_bitmap=page then
  220. freelist_8byte_with_bitmap:=freelist_next;
  221. sack_pages(page,1);
  222. end;
  223. end;
  224. pfreemem_8byte_with_bitmap:=8;
  225. end;
  226. {****************************************************************************
  227. Splay tree stuff
  228. ****************************************************************************}
  229. { $define debug}
  230. {$ifdef debug}
  231. procedure write_sizememloc_tree(tree:Pfree_block;level:cardinal);
  232. var i:cardinal;
  233. begin
  234. if tree=nil then
  235. exit;
  236. write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.left),level+1);
  237. for i:=1 to level do
  238. write(' ');
  239. writeln(tree^.size,' ',hexstr(ptruint(tree),8));
  240. write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.right),level+1);
  241. end;
  242. procedure write_memlocation_tree(tree:Pfree_block;level:cardinal);
  243. var i:cardinal;
  244. begin
  245. if tree=nil then
  246. exit;
  247. write_memlocation_tree(Pfree_block(tree^.tree_memlocation.left),level+1);
  248. for i:=1 to level do
  249. write(' ');
  250. writeln(hexstr(ptruint(tree),8));
  251. write_memlocation_tree(Pfree_block(tree^.tree_memlocation.right),level+1);
  252. end;
  253. {$endif}
  254. procedure rotate_l(var p:ptruint;offset:cardinal);
  255. var p1:ptruint;
  256. begin
  257. p1:=Ptree_struct(p+offset)^.right;
  258. Ptree_struct(p+offset)^.right:=Ptree_struct(p1+offset)^.left;
  259. Ptree_struct(p1+offset)^.left:=p;
  260. p:=p1;
  261. end;
  262. procedure rotate_r(var p:ptruint;offset:cardinal);
  263. var p1:ptruint;
  264. begin
  265. p1:=Ptree_struct(p+offset)^.left;
  266. Ptree_struct(p+offset)^.left:=Ptree_struct(p1+offset)^.right;
  267. Ptree_struct(p1+offset)^.right:=p;
  268. p:=p1;
  269. end;
  270. procedure zigzig(var p:ptruint;offset:cardinal);inline;
  271. begin
  272. rotate_r(p,offset);
  273. rotate_r(p,offset);
  274. end;
  275. procedure zigzag(var p:ptruint;offset:cardinal);inline;
  276. begin
  277. rotate_l(Ptree_struct(p+offset)^.left,offset);
  278. rotate_r(p,offset);
  279. end;
  280. procedure zagzig(var p:ptruint;offset:cardinal);inline;
  281. begin
  282. rotate_r(Ptree_struct(p+offset)^.right,offset);
  283. rotate_l(p,offset);
  284. end;
  285. procedure zagzag(var p:ptruint;offset:cardinal);inline;
  286. begin
  287. rotate_l(p,offset);
  288. rotate_l(p,offset);
  289. end;
  290. procedure delete_from_tree(var p:ptruint;offset:cardinal);
  291. var p1:ptruint;
  292. pp1:^ptruint;
  293. begin
  294. if Ptree_struct(p+offset)^.left=0 then
  295. p:=Ptree_struct(p+offset)^.right
  296. else
  297. begin
  298. if Ptree_struct(p+offset)^.right<>0 then
  299. begin
  300. {Both are occupied. Move right to rightmost leaf of left.}
  301. p1:=Ptree_struct(p+offset)^.left;
  302. repeat
  303. pp1:=@Ptree_struct(p1+offset)^.right;
  304. p1:=pp1^;
  305. until p1=0;
  306. pp1^:=Ptree_struct(p+offset)^.right;
  307. end;
  308. p:=Ptree_struct(p+offset)^.left;
  309. end;
  310. end;
  311. function find_sizememloc(size:ptruint;var p:Pfree_block):Tsplay_status;
  312. begin
  313. find_sizememloc:=ts_found_on_p;
  314. if p=nil then
  315. find_sizememloc:=ts_not_found
  316. else if size<p^.size then {Do nothing if equal...}
  317. case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.left)) of
  318. ts_not_found:
  319. if p^.size<size then
  320. find_sizememloc:=ts_not_found;
  321. ts_found_on_left:
  322. zigzig(ptruint(p),tree_sizememloc_offset);
  323. ts_found_on_p:
  324. find_sizememloc:=ts_found_on_left;
  325. ts_found_on_right:
  326. zigzag(ptruint(p),tree_sizememloc_offset);
  327. end
  328. else if size>p^.size then
  329. case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.right)) of
  330. ts_not_found:
  331. if p^.size<size then
  332. find_sizememloc:=ts_not_found;
  333. ts_found_on_left:
  334. zagzig(ptruint(p),tree_sizememloc_offset);
  335. ts_found_on_p:
  336. find_sizememloc:=ts_found_on_right;
  337. ts_found_on_right:
  338. zagzag(ptruint(p),tree_sizememloc_offset);
  339. end;
  340. end;
  341. {$if 0}
  342. function find_sizememloc(size,loc:ptruint;var p:Pfree_block):Tsplay_status;
  343. var on_left:boolean;
  344. begin
  345. find_sizememloc:=ts_found_on_p;
  346. if p=nil then
  347. find_sizememloc:=ts_not_found
  348. else
  349. begin
  350. on_left:=size<p^.size;
  351. if size=p^.size then
  352. if loc=ptruint(p) then
  353. exit
  354. else
  355. on_left:=loc<ptruint(p);
  356. if on_left then
  357. case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.left)) of
  358. ts_not_found:
  359. find_sizememloc:=ts_not_found;
  360. ts_found_on_left:
  361. zigzig(ptruint(p),tree_sizememloc_offset);
  362. ts_found_on_p:
  363. find_sizememloc:=ts_found_on_left;
  364. ts_found_on_right:
  365. zigzag(ptruint(p),tree_sizememloc_offset);
  366. end
  367. else
  368. case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.right)) of
  369. ts_not_found:
  370. find_sizememloc:=ts_not_found;
  371. ts_found_on_left:
  372. zagzig(ptruint(p),tree_sizememloc_offset);
  373. ts_found_on_p:
  374. find_sizememloc:=ts_found_on_right;
  375. ts_found_on_right:
  376. zagzag(ptruint(p),tree_sizememloc_offset);
  377. end;
  378. end;
  379. end;
  380. {$endif}
  381. function insert_sizememloc(node:Pfree_block;var p:Pfree_block):Tsplay_status;
  382. {Preconditions:
  383. node^.size is set
  384. node^.tree_sizememloc.left is set to nil
  385. node^.tree_sizememloc.right is set to nil}
  386. var on_left:boolean;
  387. begin
  388. insert_sizememloc:=ts_found_on_p;
  389. if p=nil then
  390. p:=node
  391. else
  392. begin
  393. on_left:=node^.size<p^.size;
  394. if node^.size=p^.size then
  395. on_left:=ptruint(node)<ptruint(p);
  396. if on_left then
  397. case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.left)) of
  398. ts_found_on_left:
  399. zigzig(ptruint(p),tree_sizememloc_offset);
  400. ts_found_on_p:
  401. insert_sizememloc:=ts_found_on_left;
  402. ts_found_on_right:
  403. zigzag(ptruint(p),tree_sizememloc_offset);
  404. end
  405. else
  406. case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.right)) of
  407. ts_found_on_left:
  408. zagzig(ptruint(p),tree_sizememloc_offset);
  409. ts_found_on_p:
  410. insert_sizememloc:=ts_found_on_right;
  411. ts_found_on_right:
  412. zagzag(ptruint(p),tree_sizememloc_offset);
  413. end;
  414. end;
  415. {$ifdef debug}
  416. writeln('sizememlocboom na insert');
  417. write_sizememloc_tree(tree_sizememloc,1);
  418. {$endif}
  419. end;
  420. {$if 0}
  421. function find_memlocation(location:ptruint;var p:Pfree_block;
  422. find_smaller:boolean):Tsplay_status;
  423. begin
  424. find_memlocation:=ts_found_on_p;
  425. if p=nil then
  426. find_memlocation:=ts_not_found
  427. else if location<ptruint(p) then {Do nothing if equal...}
  428. case find_memlocation(location,Pfree_block(p^.tree_memlocation.left),
  429. find_smaller) of
  430. ts_not_found:
  431. if (ptruint(p)>location) or not find_smaller then
  432. find_memlocation:=ts_not_found;
  433. ts_found_on_left:
  434. zigzig(ptruint(p),tree_memlocation_offset);
  435. ts_found_on_p:
  436. find_memlocation:=ts_found_on_left;
  437. ts_found_on_right:
  438. zigzag(ptruint(p),tree_memlocation_offset);
  439. end
  440. else if location>ptruint(p) then
  441. case find_memlocation(location,Pfree_block(p^.tree_memlocation.right),
  442. find_smaller) of
  443. ts_not_found:
  444. if (ptruint(p)>location) or not find_smaller then
  445. find_memlocation:=ts_not_found;
  446. ts_found_on_left:
  447. zagzig(ptruint(p),tree_memlocation_offset);
  448. ts_found_on_p:
  449. find_memlocation:=ts_found_on_right;
  450. ts_found_on_right:
  451. zagzag(ptruint(p),tree_memlocation_offset);
  452. end;
  453. end;
  454. {$endif}
  455. function insert_memlocation(node:Pfree_block;var p:Pfree_block):Tsplay_status;
  456. {Preconditions:
  457. node^.size is set
  458. node^.tree_sizememloc.left is set to nil
  459. node^.tree_sizememloc.right is set to nil}
  460. begin
  461. insert_memlocation:=ts_found_on_p;
  462. if p=nil then
  463. p:=node
  464. else if ptruint(node)<=ptruint(p) then {Equal? Insert on left.}
  465. case insert_memlocation(node,Pfree_block(p^.tree_memlocation.left)) of
  466. ts_found_on_left:
  467. zigzig(ptruint(p),tree_memlocation_offset);
  468. ts_found_on_p:
  469. insert_memlocation:=ts_found_on_left;
  470. ts_found_on_right: zigzag(ptruint(p),tree_memlocation_offset);
  471. end
  472. else if ptruint(node)>ptruint(p) then
  473. case insert_memlocation(node,Pfree_block(p^.tree_memlocation.right)) of
  474. ts_found_on_left:
  475. zagzig(ptruint(p),tree_memlocation_offset);
  476. ts_found_on_p:
  477. insert_memlocation:=ts_found_on_right;
  478. ts_found_on_right:
  479. zagzag(ptruint(p),tree_memlocation_offset);
  480. end;
  481. {$ifdef debug}
  482. writeln('memlocationboom na insert');
  483. write_memlocation_tree(tree_memlocation,1);
  484. {$endif}
  485. end;
  486. function get_memlocation(node:Pfree_block):Pfree_block;
  487. {Iteratively delete node from tree without splaying.}
  488. var p:^Pfree_block;
  489. begin
  490. p:=@tree_memlocation;
  491. while (p^<>nil) and (p^<>node) do
  492. if ptruint(node)<ptruint(p^) then
  493. p:=@p^^.tree_memlocation.left
  494. else
  495. p:=@p^^.tree_memlocation.right;
  496. get_memlocation:=p^;
  497. if p^<>nil then
  498. delete_from_tree(ptruint(p^),tree_memlocation_offset);
  499. end;
  500. function get_sizememloc(node:Pfree_block):Pfree_block;
  501. {Iteratively delete node from tree without splaying.}
  502. var p:^Pfree_block;
  503. on_left:boolean;
  504. begin
  505. p:=@tree_sizememloc;
  506. while (p^<>nil) and (p^<>node) do
  507. begin
  508. on_left:=node^.size<p^^.size;
  509. if node^.size=p^^.size then
  510. on_left:=ptruint(node)<ptruint(p^);
  511. if on_left then
  512. p:=@p^^.tree_sizememloc.left
  513. else
  514. p:=@p^^.tree_sizememloc.right;
  515. end;
  516. get_sizememloc:=p^;
  517. if p^<>nil then
  518. delete_from_tree(ptruint(p^),tree_sizememloc_offset);
  519. end;
  520. function get_block_by_size(size:cardinal):Pfree_block;
  521. var what:^ptruint;
  522. begin
  523. case find_sizememloc(size,tree_sizememloc) of
  524. ts_not_found:
  525. begin
  526. get_block_by_size:=nil;
  527. exit;
  528. end;
  529. ts_found_on_left:
  530. what:=@tree_sizememloc^.tree_sizememloc.left;
  531. ts_found_on_p:
  532. what:=@tree_sizememloc;
  533. ts_found_on_right:
  534. what:=@tree_sizememloc^.tree_sizememloc.right;
  535. end;
  536. get_block_by_size:=Pfree_block(what^);
  537. delete_from_tree(what^,tree_sizememloc_offset);
  538. if get_memlocation(get_block_by_size)=nil then
  539. runerror(204);
  540. end;
  541. function get_block_by_memlocation(location:ptruint):Pfree_block;
  542. var what:^ptruint;
  543. begin
  544. get_block_by_memlocation:=get_memlocation(Pfree_block(location));
  545. if get_block_by_memlocation<>nil then
  546. begin
  547. get_sizememloc(get_block_by_memlocation);
  548. { case find_sizememloc(get_block_by_memlocation^.size,
  549. ptruint(get_block_by_memlocation),tree_sizememloc) of
  550. ts_not_found:
  551. runerror(204);
  552. ts_found_on_left:
  553. what:=@tree_sizememloc^.tree_sizememloc.left;
  554. ts_found_on_p:
  555. what:=@tree_sizememloc;
  556. ts_found_on_right:
  557. what:=@tree_sizememloc^.tree_sizememloc.right;
  558. end;
  559. delete_from_tree(what^,tree_sizememloc_offset);}
  560. end;
  561. end;
  562. function get_smaller_neighbour(location:ptruint):Pfree_block;
  563. var p,what:^ptruint;
  564. begin
  565. {Find a smaller block. Don't splay as it will be deleted.}
  566. p:=@tree_memlocation;
  567. what:=nil;
  568. while (p^<>0) do
  569. if location<=p^ then
  570. p:=@Pfree_block(p^)^.tree_memlocation.left
  571. else
  572. begin
  573. what:=p;
  574. p:=@Pfree_block(p^)^.tree_memlocation.right;
  575. end;
  576. if (what=nil) or (ptruint(what^)+Pfree_block(what^)^.size<>location) then
  577. begin
  578. get_smaller_neighbour:=nil;
  579. exit;
  580. end;
  581. get_smaller_neighbour:=Pfree_block(what^);
  582. delete_from_tree(ptruint(what^),tree_memlocation_offset);
  583. get_sizememloc(get_smaller_neighbour);
  584. end;
  585. {function pgetmem_directpage(memsize:ptrint):pointer;
  586. var npages:ptrint;
  587. begin
  588. npages:=(memsize+sizeof(Tpage_direct)+page_size-1) div page_size;
  589. pgetmem_directpage:=req_pages(npages);
  590. with Ppage_direct(pgetmem_directpage)^ do
  591. begin
  592. page_type:=pt_direct_page;
  593. size:=memsize;
  594. end;
  595. end;
  596. }
  597. function pgetmem_suballocpage(memsize:ptrint):pointer;
  598. var free_block:Pfree_block;
  599. page:pointer;
  600. needsize,remaining,block_start:ptruint;
  601. begin
  602. {$ifdef debug}
  603. writeln('-------Getmem------- ',memsize);
  604. {$endif}
  605. {Constant parts on left because of constant evaluation.}
  606. needsize:=(sizeof(Tsuballoc_header)+memblock_alignround+memsize) and not memblock_alignround;
  607. if needsize<min_suballoc_size then
  608. needsize:=min_suballoc_size;
  609. {$ifdef debug}
  610. writeln('sizememlocboom voor get:');
  611. write_sizememloc_tree(tree_sizememloc,2);
  612. {$endif}
  613. free_block:=get_block_by_size(needsize);
  614. if free_block=nil then
  615. begin
  616. page:=req_pages(1);
  617. Ppage_suballocation(page)^.page_type:=pt_suballocation;
  618. {Allocate at the end of the page, a free block at the start.}
  619. free_block:=Pfree_block(ptruint(page)+sizeof(Tpage_suballocation));
  620. remaining:=page_size-needsize-sizeof(Tpage_suballocation);
  621. block_start:=ptruint(page)+page_size-needsize;
  622. Psuballoc_header(block_start)^.alloc_size:=needsize;
  623. pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));
  624. end
  625. else
  626. begin
  627. block_start:=ptruint(free_block);
  628. remaining:=free_block^.size-needsize;
  629. if (remaining<min_suballoc_size) then
  630. begin
  631. needsize:=free_block^.size;
  632. free_block:=nil;
  633. end
  634. else
  635. inc(ptruint(free_block),needsize);
  636. Psuballoc_header(block_start)^.alloc_size:=needsize;
  637. pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));
  638. end;
  639. if free_block<>nil then
  640. begin
  641. with free_block^ do
  642. begin
  643. size:=remaining;
  644. tree_sizememloc.left:=0;
  645. tree_sizememloc.right:=0;
  646. tree_memlocation.left:=0;
  647. tree_memlocation.right:=0;
  648. end;
  649. insert_sizememloc(free_block,tree_sizememloc);
  650. insert_memlocation(free_block,tree_memlocation);
  651. end;
  652. end;
  653. function pfreemem_suballoc_page(page:Ppage_direct;p:pointer):ptrint;
  654. var free_block,neighbour:Pfree_block;
  655. headerp:Psuballoc_header;
  656. asize:ptruint;
  657. begin
  658. {$Ifdef debug}
  659. write('-------Freemem------- ');
  660. {$endif}
  661. headerp:=Psuballoc_header(ptrint(p)-sizeof(Tsuballoc_header));
  662. asize:=headerp^.alloc_size;
  663. {$ifdef debug}
  664. writeln(hexstr(ptruint(page),8),' ',asize);
  665. {$endif}
  666. free_block:=Pfree_block(headerp);
  667. {Search neighbour to coalesce with above block.}
  668. neighbour:=get_block_by_memlocation(ptruint(free_block)+asize);
  669. if neighbour<>nil then
  670. inc(asize,neighbour^.size);
  671. {Search neighbour to coalesce with below block.}
  672. neighbour:=get_smaller_neighbour(ptruint(free_block));
  673. if neighbour<>nil then
  674. begin
  675. inc(asize,neighbour^.size);
  676. free_block:=neighbour;
  677. end;
  678. {Page empty??}
  679. if (ptruint(free_block) and page_mask=sizeof(Tpage_suballocation)) and
  680. (asize=page_size-sizeof(Tpage_suballocation)) then
  681. sack_pages(pointer(ptruint(free_block) and not page_mask),1)
  682. else
  683. begin
  684. with free_block^ do
  685. begin
  686. size:=asize;
  687. tree_sizememloc.left:=0;
  688. tree_sizememloc.right:=0;
  689. tree_memlocation.left:=0;
  690. tree_memlocation.right:=0;
  691. end;
  692. insert_sizememloc(free_block,tree_sizememloc);
  693. insert_memlocation(free_block,tree_memlocation);
  694. end;
  695. end;
  696. function pgetmem(size:ptrint):pointer;
  697. begin
  698. if size<=8 then
  699. pgetmem:=pgetmem_8byte_with_bitmap
  700. else
  701. pgetmem:=pgetmem_suballocpage(size);
  702. end;
  703. function pallocmem(size:ptrint):pointer;
  704. begin
  705. if size<=8 then
  706. begin
  707. pallocmem:=pgetmem_8byte_with_bitmap;
  708. fillchar(Pbyte(pallocmem)^,8,0);
  709. end
  710. else
  711. {Freshly allocated pages are allways already cleared.}
  712. { pgallocmem:=pgallocmem_directpage(size)};
  713. end;
  714. function pfreemem(p:pointer):ptrint;
  715. var page:pointer;
  716. begin
  717. page:=pointer(ptrint(p) and not page_mask);
  718. case Ppage_type(page)^ of
  719. pt_8byte_with_bitmap:
  720. pfreemem:=pfreemem_8byte_with_bitmap(page,p);
  721. pt_suballocation:
  722. pfreemem:=pfreemem_suballoc_page(page,p);
  723. else
  724. runerror(204);
  725. end;
  726. end;
  727. function pfreememsize(p:pointer;size:ptrint):ptrint;
  728. begin
  729. { runerror(204);}
  730. pfreemem(p);
  731. end;
  732. function preallocmem(var p:pointer;size:ptrint):pointer;
  733. begin
  734. runerror(204);
  735. end;
  736. function pmemsize(p:pointer):ptrint;
  737. begin
  738. runerror(204);
  739. end;
  740. const page_memory_manager:Tmemorymanager=
  741. (
  742. needlock:false;
  743. getmem:@pgetmem;
  744. freemem:@pfreemem;
  745. freememsize:@pfreememsize;
  746. allocmem:@pallocmem;
  747. reallocmem:@preallocmem;
  748. memsize:@pmemsize;
  749. { memavail:@pmemavail;}
  750. { maxavail:@pmaxavail;}
  751. { heapsize:@pheapsize;}
  752. );
  753. var oldmemman:Tmemorymanager;
  754. initialization
  755. getmemorymanager(oldmemman);
  756. setmemorymanager(page_memory_manager);
  757. finalization
  758. setmemorymanager(oldmemman);
  759. end.