pagemem.pp 25 KB

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