home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / b121_1 / Heap < prev    next >
Encoding:
Text File  |  1993-08-16  |  18.2 KB  |  594 lines

  1. Heap memory manager
  2. ===================
  3.  
  4. WimpExtension's heap manager is one of the module's most powerful, useful,
  5. and - unavoidably - complicated features. This document is provided to
  6. explain more about what a relocatable heap is, and how to use it.
  7.  
  8. Programming examples in this document are given in BASIC, because practically
  9. everyone knows how to use it.
  10.  
  11. This document assumes that you know how to program in the RISC OS Wimp, and
  12. that you understand terms such as "WimpSlot" (read the chapter "The Window
  13. Manager" in the PRMs if you don't).
  14.  
  15. Read the "SWIs" and "Manual" files for a brief description of the parameters
  16. for the SWI WimpExt_Heap.
  17.  
  18.  
  19. NB  This document is in two sections. The first section is relatively simple
  20. --  and tells you all you will probably need to know about using the heap
  21.     manager. The second section explains the advanced features of the heap
  22.     manager. BE WARNED; this section is not simple. But, most of you won't
  23.     need to read it, so if you find it confusing, ignore it.
  24.  
  25.  
  26.  
  27. Section 1
  28. =========
  29.  
  30.  
  31.  
  32. Why do I need a heap?
  33. ---------------------
  34.  
  35. Any program which uses more than one block of memory which changes size needs
  36. a heap manager. For example, Edit and Paint need a heap manager, because they
  37. can have several files loaded at once, all of which can be changing size at
  38. any time. The files are loaded into memory "blocks", which are provided by
  39. the heap manager.
  40.  
  41.  
  42.  
  43. Why use a relocatable heap?
  44. ---------------------------
  45.  
  46. RISC OS provides a non-relocatable heap manager. This means that the memory
  47. blocks are fixed in memory, and don't move about. The problem with this is
  48. that it gets very wasteful on memory when you have finished using the block.
  49. Say you loaded three files into a text editor:
  50.  
  51.   /--------\ Highest memory address
  52.   | File 3 |
  53.   |        |
  54.   |--------|
  55.   | File 2 |
  56.   |        |
  57.   |        |
  58.   |--------|
  59.   | File 1 |
  60.   \--------/ Lowest memory address
  61.  
  62. This is fine, no problems so far. However, suppose the user decided to close
  63. the file "File 2":
  64.  
  65.   /--------\ Highest memory address
  66.   | File 3 |
  67.   |        |
  68.   |--------|
  69.   | unused |
  70.   |        |
  71.   |        |
  72.   |--------|
  73.   | File 1 |
  74.   \--------/ Lowest memory address
  75.  
  76. The block of memory in the middle is now unused, and is wasting space. A
  77. non-relocatable heap manager can't do anything about this. Another example is
  78. if the user adds something to File 2, making it longer. File 2 will no longer
  79. fit in its original block - if you extended it then it would overwrite
  80. File 3. Therefore the heap manager has to copy the whole file up in memory,
  81. as shown in the diagram:
  82.  
  83.   /--------\ Highest memory address
  84.   | File 2 |
  85.   |        |
  86.   |        |
  87.   |        |
  88.   |--------|
  89.   | File 3 |
  90.   |        |
  91.   |--------|
  92.   | unused |
  93.   |        |
  94.   |        |
  95.   |--------|
  96.   | File 1 |
  97.   \--------/ Lowest memory address
  98.  
  99. WimpExtension provides a relocatable heap manager, however. This means that
  100. the heap manager is allowed to move the blocks about, to try and reduce the
  101. amount of wasted memory. In the situation above, for example, WimpExtension
  102. would move File 2 and File 3 down in memory, like so:
  103.  
  104.   /--------\ Highest memory address
  105.   | File 2 |
  106.   |        |
  107.   |        |
  108.   |        |
  109.   |--------|
  110.   | File 3 |
  111.   |        |
  112.   |--------|
  113.   | File 1 |
  114.   \--------/ Lowest memory address
  115.  
  116. As you can see, this can save a lot of memory.
  117.  
  118.  
  119.  
  120. Anchors
  121. -------
  122.  
  123. The only disadvantage of a reloctable heap is due to the fact that it IS
  124. relocatable - the blocks of memory aren't fixed and may move about. A
  125. question which immediately arises is "How do I find my memory block?" - if
  126. the block may have moved, how do you find it?
  127.  
  128. The answer is by using an "anchor". An anchor is a word in memory. The
  129. contents of this word is always a pointer to the start of the block. ie:
  130.  
  131.                       /-------\
  132.                       |       |
  133.   /--------\          |       |
  134.   | anchor |--------->| block |
  135.   \--------/          \-------/
  136.  
  137. The anchor always stays fixed in the same place in memory, so you always know
  138. where to find it. So, to find the location of your block, you would use:
  139.  
  140.   block%=!anchor% : REM block% now points to the first byte in the block
  141.  
  142. The anchors are stored all together at the beginning of the heap.
  143.  
  144.  
  145.  
  146. Size of blocks
  147. --------------
  148.  
  149. The word before the start of any block contains the size of the block in
  150. bytes. So to find the size of a block, you would use:
  151.  
  152.   size%=!(block%-4)
  153.  
  154. or:
  155.  
  156.   size%=!( (!anchor%) -4)
  157.  
  158. (because block%=!anchor%).
  159.  
  160. Due to the way the heap manager works, the size of a block is always four
  161. plus a multiple of eight (ie. 12, 20, 28, etc.). If you ask WimpExtension to
  162. make a block with a size which isn't four plus a multiple of eight, then the
  163. size will be rounded up by between one and seven bytes, to take it to the
  164. next largest acceptable size.
  165.  
  166.  
  167.  
  168. Initialising the heap
  169. ---------------------
  170.  
  171. Before you can use any of the heap operations, you must initialise the heap.
  172. This requires two parameters - the number of anchors to create initially, and
  173. the address in memory of the base of the heap.
  174.  
  175. The anchors are stored all together at the beginning of the heap. Because you
  176. need one anchor for every block in use, the number of anchors is effectively
  177. the maximum number of blocks you can have in use at any one time. You can
  178. create more anchors later, but it is best to create enough now, and then you
  179. don't have to worry about it later. Remember that anchors do take memory
  180. though, so don't go wild.
  181.  
  182. For example:
  183.  
  184.   SYS "WimpExt_Heap",0,base%,anchors%
  185.  
  186. Note that a heap which is empty (ie. no blocks are in use) takes absolutely
  187. no memory at all.
  188.  
  189.  
  190.  
  191. Allocating blocks
  192. -----------------
  193.  
  194. Whenever you ask WimpExtension to make you a new block (called "allocating"
  195. a block), it gives you a pointer to the anchor for that block. You must store
  196. the pointer to the anchor, NOT the pointer to the block, because the anchor
  197. will never move, but the block may do. For example, to ask WimpExtension for
  198. a block "size%" bytes long, you would use:
  199.  
  200.   SYS "WimpExt_Heap",2,,size% TO ,anchor%
  201.  
  202. If WimpExtension cannot create the block, because there is not enough free
  203. memory, then the anchor returned will be zero. You need to check for this
  204. before writing anything into the block. eg:
  205.  
  206.   SYS "WimpExt_Heap",2,,size% TO ,anchor%
  207.   IF anchor%=0 THEN ERROR 1,"Not enough free memory"
  208.  
  209.  
  210.  
  211. Freeing blocks
  212. --------------
  213.  
  214. When you have finished using a block, you use the "Free block" call to tell
  215. WimpExtension that you don't need the block any more, and the memory it takes
  216. up can be re-used. eg:
  217.  
  218.   SYS "WimpExt_Heap",3,anchor%
  219.  
  220. or:
  221.  
  222.   SYS "WimpExt_Heap",3,block%
  223.  
  224. The block will be added to WimpExtension's list of free blocks.
  225.  
  226.  
  227.  
  228. Reallocating blocks
  229. -------------------
  230.  
  231. Sometimes you will want to re-size a block - this is called "reallocating"
  232. the block. WimpExtension allows you to increase or decrease the size of any
  233. block at any time. eg:
  234.  
  235.   SYS "WimpExt_Heap",4,block%,new_size% TO ,flag%
  236.  
  237. or:
  238.  
  239.   SYS "WimpExt_Heap",4,anchor%,new_size% TO ,flag%
  240.  
  241. If the flag is zero on exit then the re-size failed because there wasn't
  242. enough free memory.
  243.  
  244. Note that this call may cause the specified block to move in memory. Only the
  245. specific block that you are re-sizing can move, though - all the other blocks
  246. will stay where they are.
  247.  
  248.  
  249.  
  250. Garbarge collection
  251. -------------------
  252.  
  253. "Garbage collection" is the whole point of the relocatable heap. This is the
  254. process of shuffling the blocks about in memory, so that no memory is wasted.
  255. For example, if the heap was in the following state:
  256.  
  257.   /---------\ Highest memory address
  258.   | block 2 |
  259.   |         |
  260.   |---------|
  261.   |  free   |
  262.   |         |
  263.   |         |
  264.   |---------|
  265.   | block 1 |
  266.   \---------/ Lowest memory address
  267.  
  268. then performing garbage collection would shuffle the blocks as follows:
  269.  
  270.   /---------\ Highest memory address
  271.   | block 2 |
  272.   |         |
  273.   |---------|
  274.   | block 1 |
  275.   \---------/ Lowest memory address
  276.  
  277. This then allows WimpExtension to decrease your task's WimpSlot, thus making
  278. this memory available to any other programs which might need it.
  279.  
  280. Two garbage collection calls are provided; the Tidy call:
  281.  
  282.   SYS "WimpExt_Heap",5
  283.  
  284. and the Compact call:
  285.  
  286.   SYS "WimpExt_Heap",6
  287.  
  288. The Tidy call just tidies the heap a little bit - the heap won't necessarily
  289. immediately be shuffled into the ideal position, but the call is usually
  290. quite fast. This call is intended to be called just before you call
  291. Wimp_Poll. If you set bit 3 of R2 when you called WimpExt_Initialise, then
  292. the heap will be automatically Tidied once a second, in WimpExt_PrePoll. Most
  293. of the time, you can just set this bit, and then forget all about garbage
  294. collection - it will all be handled for you.
  295.  
  296. The Compact call tidies the heap completely - the heap will immediately be
  297. shuffled into the ideal position. This call is often slower than the Tidy
  298. call, however, as it does more work.
  299.  
  300.  
  301.  
  302. How often should I tidy the heap?
  303. ---------------------------------
  304.  
  305. How often you tidy the heap depends on the average size of the blocks your
  306. program uses. If your program uses lots of little blocks then you should tidy
  307. the heap quite often. If it uses a smaller number of larger blocks then you
  308. should tidy it less often.
  309.  
  310. For a text editor, for example, the once-a-second tidy provided automatically
  311. should be fine. For something which uses smaller blocks, you should probably
  312. tidy the heap more often.
  313.  
  314.  
  315.  
  316. Finding the anchor of a block
  317. -----------------------------
  318.  
  319. If you have a pointer to a block, and you want to locate the block's anchor,
  320. then a call is provided to do this:
  321.  
  322.   SYS "WimpExt_Heap",7,block% TO ,anchor%
  323.  
  324. An error is produced if block% is not a valid pointer to the start of a
  325. block.
  326.  
  327.  
  328.  
  329. Fixing blocks
  330. -------------
  331.  
  332. Sometimes you may want to temporarily 'fix' the heap. This makes it so that
  333. all the blocks are fixed and cannot move. This is useful if you need to rely
  334. on a block staying put at the same position in memory for a while.
  335.  
  336. To fix the heap, you would use:
  337.  
  338.   SYS "WimpExt_Heap",8
  339.  
  340. and to unfix it you would use:
  341.  
  342.   SYS "WimpExt_Heap",10
  343.  
  344. Note that WimpExtension keeps a count of the number of times you haved fixed
  345. the heap, and only unfixes the heap when you tell it to the same number of
  346. times. ie:
  347.  
  348.   SYS "WimpExt_Heap",8
  349.   SYS "WimpExt_Heap",8
  350.   SYS "WimpExt_Heap",10
  351.  
  352. would leave the heap fixed. The following, however, would leave the heap
  353. unfixed, as the number of "unfixings" matches the number of "fixings":
  354.  
  355.   SYS "WimpExt_Heap",8
  356.   SYS "WimpExt_Heap",8
  357.   SYS "WimpExt_Heap",10
  358.   SYS "WimpExt_Heap",10
  359.  
  360. You can force WimpExtension to unfix the heap straight away, regardless of
  361. the number of times it has been fixed, using the following call:
  362.  
  363.   SYS "WimpExt_Heap",9
  364.  
  365. ie. The following would leave the heap unfixed:
  366.  
  367.   SYS "WimpExt_Heap",8
  368.   SYS "WimpExt_Heap",8
  369.   SYS "WimpExt_Heap",9
  370.  
  371.  
  372.  
  373. Creating more anchors
  374. ---------------------
  375.  
  376. WimpExtension allows you to create more anchors, even while the heap is in
  377. use. Note that this call has to move the entire heap up in memory, so it can
  378. be quite slow. For example:
  379.  
  380.   SYS "WimpExt_Heap",11,add%
  381.  
  382. "add%" extra anchors will be created. All the blocks will be moved.
  383.  
  384. WimpExtension also provides a call to allocate a block, automatically
  385. creating more anchors if you've run out:
  386.  
  387.   SYS "WimpExt_Heap",12,,size% TO ,anchor%
  388.  
  389.  
  390. Freeing all blocks
  391. ------------------
  392.  
  393. WimpExtension provides a call to free all the blocks in the heap:
  394.  
  395.   SYS "WimpExt_Heap",13
  396.  
  397. Every single allocated block will be freed, and all the memory released.
  398.  
  399.  
  400.  
  401. Describing the heap
  402. -------------------
  403.  
  404. WimpExtension provides a call which provides various bits of information
  405. about the heap:
  406.  
  407.   SYS "WimpExt_Heap",1 TO ,,largest%,free%,heapsize%,anchors%,blocks%
  408.  
  409.   largest%  : The size of the largest continuous area of memory in the heap
  410.   free%     : The total amount of memory free in the heap
  411.   heapsize% : The total amount of memory used by the heap
  412.   anchors%  : The number of anchors which have been created
  413.   blocks%   : The number of blocks which are currently allocated
  414.  
  415.  
  416. -----------------------------------------------------------------------------
  417. Here ends the simple part of this file.
  418.  
  419. From here on it is far more complicated, but you almost certainly won't need
  420. to read it. So if you get confused, don't worry.
  421.  
  422.  
  423. Section 2
  424. =========
  425.  
  426. OK, tremble in fear, mortals, because if you thought that the last bit was
  427. complicated, you're just gonna LOVE this. Now we get to talk about multiple
  428. heaps, heaps within heaps, and heaps that can move about in memory (called
  429. 'shifting' heaps).
  430.  
  431. WimpExtension's heap manager supports multiple heaps. ie. You can have more
  432. than one heap going at once. Each heap is treated as totally separate from
  433. all the other heaps.
  434.  
  435. It also supports 'shifting' heaps, which can move about in memory. The
  436. standard heap is NOT a shifting heap, because although the blocks themselves
  437. can move about, the heap itself always stays in the same place.
  438.  
  439. The extra considerations involved when using shifting heaps are NOT trivial,
  440. and are liable to cause severe headaches if you try to think about them for
  441. too long. (That's what happens to me, anyway.)
  442.  
  443. Different heaps are referred to by their 'heap pointers'. A heap pointer
  444. points to a block of memory set out as follows:
  445.  
  446.   +00  hp_heap       offset of heap data area
  447.   +04  hp_free       offset of first free block, or 0 if no free blocks
  448.   +08  hp_anchors    offset of first anchor
  449.   +0C  hp_heapsize   total size of heap in bytes
  450.   +10  hp_heapfix    'fixed' counter
  451.   +14  hp_tidytime   monotonic time of last Tidy call
  452.   +18  hp_heaptidy   tidy flag; 0 if heap is fully tidied, non-zero otherwise
  453.   +1C  hp_created    created flag; 0 if heap is uncreated, non-zero otherwise
  454.   +20  hp_base       pointer to base of heap memory
  455.   +24  hp_pagesize   'page' size
  456.   +28  hp_setsize    pointer to routine to change size of heap
  457.   +2C  hp_numblocks  number of blocks claimed
  458.   +30  hp_rootptr    pointer to pointer to base of heap memory
  459.   +34  hp_misc       depends on what sort of heap this is
  460. All offsets are from hp_base.
  461.  
  462. The following things are defined about the heap:
  463.   * hp_base must be a multiple of 8
  464.   * hp_free need not contain a sensible value if hp_created is zero
  465.   * the anchors are in the area hp_anchors to hp_heap
  466.   * each anchor is 8 bytes, 4 bytes pointer to block then 4 bytes task handle
  467.   * hp_heapsize must be a multiple of 8
  468.   * hp_heap must be a multiple of 8
  469.   * hp_anchors must be a multiple of 8
  470.  
  471.  
  472.  
  473. hp_rootptr and hp_base
  474. ----------------------
  475.  
  476. hp_rootptr points to a pointer to the base of the heap. This must always be
  477. where the heap actually is in memory. hp_base contains the position of the
  478. heap in memory last time the heap manager looked. These addresses are used by
  479. the relocation routine (see below) to update the anchors if the heap moves.
  480. hp_rootptr does not provide a sufficient level of indirection if the heap is
  481. nested inside a shifting heap, and you will have to update this value
  482. manually if this is the case.
  483.  
  484.  
  485.  
  486. hp_setsize and hp_pagesize
  487. --------------------------
  488.  
  489. hp_setsize is a routine that is called when WimpExtension wants to change the
  490. size of the heap. It is entered in SVC mode as follows:
  491.  R0  = size required
  492.  R10 = heap pointer
  493.  R13 = supervisor stack
  494.  R14 = return address
  495. Exit:
  496.  R0  = 0 indicates failure, non-zero indicates success
  497.  all other registers preserved
  498.  
  499. It should NOT return errors, just indicate success or failure with R0 as
  500. shown. The routine should update hp_heapsize as necessary, and the base of
  501. the heap as indicated by hp_rootptr if the heap has moved. It should NOT
  502. change hp_base, as this is needed to relocate the anchors.
  503.  
  504. hp_pagesize is used to decide whether or not it is worth increasing or
  505. decreasing the heap size. The heap size is always decreased or increased in
  506. multiples of this value.
  507.  
  508.  
  509.  
  510. hp_misc
  511. -------
  512.  
  513. hp_misc's value depends on what sort of heap this is. For the standard heap,
  514. it is reserved and its value is undefined. For a heap within a heap, created
  515. for you by WimpExtension, it contains the heap pointer of the parent heap. If
  516. the heap was created by you, then you can use it for whatever purpose you
  517. want.
  518.  
  519.  
  520.  
  521. Selecting a different heap
  522. --------------------------
  523.  
  524. To select a different heap, use call 14:
  525.  
  526.   SYS "WimpExt_Heap",14,new_heap% TO old_heap%,new_heap%
  527.  
  528. new_heap% can take one of several values:
  529.   -1     don't change the selected heap
  530.   +1     select the standard heap
  531.   other  new_heap% is a heap pointer; select this heap
  532.  
  533. On exit, old_heap% and new_heap% contain the heap pointers of the previous
  534. and current heaps respectively, or 0 if no heap was/is selected.
  535.  
  536. After this call, all other WimpExt_Heap calls act on the selected heap.
  537.  
  538.  
  539.  
  540. Relocating the heap
  541. -------------------
  542.  
  543. If you have moved the heap about in memory, then use the Relocate call to
  544. update the anchors:
  545.  
  546.   SYS "WimpExt_Heap",15
  547.  
  548. This call is used automatically after WimpExtension calls hp_setsize, and on
  549. entry to any of the other WimpExt_Heap calls, so you will only need to use it
  550. if you move the heap at some other time and then need to reference an anchor
  551. before using another WimpExt_Heap call.
  552.  
  553.  
  554.  
  555. Creating a heap within another heap
  556. -----------------------------------
  557.  
  558. WimpExtension supports another call to create heaps. This one creates a heap
  559. inside a heap block in another heap. It is used as follows:
  560.  
  561.   SYS "WimpExt_Heap",16,heapptr%,anchors%
  562.  
  563. heapptr% points to a block of memory which is filled in by the call with a
  564. heap description block. anchors% is the number of anchors to create.
  565.  
  566.  
  567.  
  568. Creating custom heaps
  569. ---------------------
  570.  
  571. To create a heap to your own specification, simply make a heap description
  572. block, and then select it as the current heap. If you set hp_created to zero,
  573. then you won't have to set up anything in the heap memory itself.
  574.  
  575.  
  576.  
  577. Considerations for shifting heaps
  578. ---------------------------------
  579.  
  580. Shifting heaps are fun. Not only can all the blocks move, but the heap itself
  581. can move as well. This means that the anchors can move. So you have to store
  582. the offset of the anchor in the heap, rather than a pointer to the anchor
  583. itself, and then calculate the address of the anchor when you need it by
  584. referencing hp_base.
  585.  
  586. Basically, nothing at all in a shifting heap is fixed, EXCEPT the heap
  587. pointer. BUT the heap pointer doesn't have to be fixed, you can move it
  588. around as long as you re-select the heap...
  589.  
  590. When you start using shifting heaps inside shifting heaps, the excitement
  591. knows no bounds... A shifting heap inside a block in a shifting heap inside
  592. a block in a shifting heap inside a block in a shifting heap is actually
  593. quite tricky to keep track of ;-).
  594.