Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

851 lines
25 KiB

  1. TITLE LCOMPACT - Local memory allocator, compaction procedures
  2. include kernel.inc
  3. errnz la_prev ; This code assumes la_prev = 0
  4. sBegin CODE
  5. assumes CS,CODE
  6. ; These are all the external subroutines needed by this source file.
  7. ;
  8. externNP <henum> ; HANDLE.ASM
  9. externNP <ljoin,lfree,lfreeadd,lfreedelete> ; LALLOC.ASM
  10. externNP <lnotify,lalign> ; LINTERF.ASM
  11. externFP <GlobalHandle, GlobalRealloc>
  12. ;externFP <LocalHeapSize>
  13. ; These are all of the internal subroutines defined in this source file.
  14. ;
  15. PUBLIC lmove, lbestfit, lcompact
  16. ;-----------------------------------------------------------------------;
  17. ; lmove ;
  18. ; ;
  19. ; Moves a moveable block into the top part of a free block. ;
  20. ; ;
  21. ; Arguments: ;
  22. ; BX = address of free block ;
  23. ; SI = address of busy block to move ;
  24. ; ;
  25. ; Returns: ;
  26. ; SI = old busy address (new free block) ;
  27. ; DI = new busy address ;
  28. ; BX = old free block ;
  29. ; AX = block after old free block ;
  30. ; ;
  31. ; Error Returns: ;
  32. ; ;
  33. ; Registers Preserved: ;
  34. ; ;
  35. ; Registers Destroyed: ;
  36. ; CX,DX,ES ;
  37. ; ;
  38. ; Calls: ;
  39. ; ;
  40. ; History: ;
  41. ; ;
  42. ; Tue Oct 14, 1986 06:22:28p -by- David N. Weise [davidw] ;
  43. ; Added this nifty comment block. ;
  44. ;-----------------------------------------------------------------------;
  45. cProc lmove,<PUBLIC,NEAR>
  46. cBegin nogen
  47. mov cx,[si].la_next ; Calculate #bytes in busy block
  48. sub cx,si
  49. add si,cx ; SI = bottom of busy block
  50. mov di,[bx].la_next ; DI = bottom of free block
  51. cmp si,bx ; Are the busy and free blocks adjacent?
  52. je move1 ; Yes, always room for free header
  53. mov ax,di ; Calculate the new busy block location
  54. sub ax,cx
  55. sub ax,LA_MINBLOCKSIZE ; See if there is room for two blocks
  56. cmp ax,bx ; in this free block
  57. jae move1 ; Yes, continue
  58. mov ax,di ; No, AX = block after free block
  59. mov di,bx ; New busy block will replace free block
  60. add di,cx ; with some extra slop at end
  61. jmp short move2
  62. move1:
  63. mov ax,di ; AX = block after free block
  64. move2:
  65. dec si ; Predecrement for moving backwards
  66. dec si ; on bogus Intel hardware
  67. dec di
  68. dec di
  69. shr cx,1 ; Move words
  70. push ds ; Initialize for rep movsw
  71. pop es
  72. std ; Move down as may overlap
  73. rep movsw
  74. cld ; Don't hose careless ones
  75. inc si ; More bogosity.
  76. inc si ; SI = old busy address (new free block)
  77. inc di ; DI = new busy address
  78. inc di ; BX = old free block
  79. movex: ; AX = block after old free block
  80. ret
  81. cEnd nogen
  82. ;-----------------------------------------------------------------------;
  83. ; lbestfit ;
  84. ; ;
  85. ; Searches backwards for the largest moveable block that will fit ;
  86. ; in the passed free block. ;
  87. ; ;
  88. ; Arguments: ;
  89. ; BX = free block ;
  90. ; CX = #arena entries left to examine ;
  91. ; ;
  92. ; Returns: ;
  93. ; SI = address of moveable block or zero ;
  94. ; ;
  95. ; Error Returns: ;
  96. ; ;
  97. ; Registers Preserved: ;
  98. ; ;
  99. ; Registers Destroyed: ;
  100. ; ;
  101. ; Calls: ;
  102. ; ;
  103. ; History: ;
  104. ; ;
  105. ; Tue Oct 14, 1986 06:25:46p -by- David N. Weise [davidw] ;
  106. ; Wrote it. ;
  107. ;-----------------------------------------------------------------------;
  108. cProc lbestfit,<PUBLIC,NEAR>
  109. cBegin nogen
  110. push bx
  111. push cx
  112. push dx
  113. xor si,si ; Have not found anything yet
  114. push si
  115. mov dx,[bx].la_next ; Compute max size to look for
  116. sub dx,bx
  117. bfloop:
  118. mov ax,[bx].la_prev ; Get previous block pointer
  119. test al,LA_BUSY ; Is this block busy?
  120. jz bfnext ; No, continue
  121. test al,LA_MOVEABLE ; Is this block moveable?
  122. jz bfnext ; No, continue
  123. mov si,[bx].la_handle ; Yes, is this block locked?
  124. cmp [si].lhe_count,0
  125. jne bfnext ; No, continue
  126. mov ax,[bx].la_next ; Yes, compute size of this moveable block
  127. sub ax,bx ; Compare to size of free block
  128. cmp ax,dx ; Is it bigger?
  129. ja bf2 ; Yes, continue
  130. pop si ; No, Recover largest block so far
  131. or si,si ; First time?
  132. jz bf0 ; Yes, special case
  133. add ax,si ; No, is this block better than
  134. cmp ax,[si].la_next ; ...the best so far?
  135. jbe bf1 ; No, continue
  136. bf0: mov si,bx ; Yes, remember biggest block
  137. bf1: push si ; Save largest block so far
  138. bf2: mov ax,[bx].la_prev ; Skip past this block
  139. bfnext:
  140. and al,LA_MASK
  141. mov bx,ax
  142. loop bfloop
  143. bfexit:
  144. pop si
  145. pop dx
  146. pop cx
  147. pop bx
  148. ret
  149. cEnd nogen
  150. ;-----------------------------------------------------------------------;
  151. ; lcompact ;
  152. ; ;
  153. ; Compacts the local heap. ;
  154. ; ;
  155. ; Arguments: ;
  156. ; DX = minimum #contiguous bytes needed ;
  157. ; DI = address of local heap information ;
  158. ; ;
  159. ; Returns: ;
  160. ; AX = size of largest contiguous free block ;
  161. ; BX = arena header of largest contiguous free block ;
  162. ; DX = minimum #contiguous bytes needed ;
  163. ; ;
  164. ; Error Returns: ;
  165. ; ;
  166. ; Registers Preserved: ;
  167. ; ;
  168. ; Registers Destroyed: ;
  169. ; CX,SI,ES ;
  170. ; ;
  171. ; Calls: ;
  172. ; ;
  173. ; History: ;
  174. ; ;
  175. ; Wed March 11, 1987 -by- Bob Gunderson [bobgu] ;
  176. ; Added code to maintain free list while compacting. ;
  177. ; ;
  178. ; Tue Oct 14, 1986 06:27:37p -by- David N. Weise [davidw] ;
  179. ; Added this nifty comment block. ;
  180. ;-----------------------------------------------------------------------;
  181. cProc lcompact,<PUBLIC,NEAR>
  182. cBegin nogen
  183. x = LHE_DISCARDABLE+1
  184. x = x shl 8
  185. x = x or 1
  186. IncLocalStat ls_lcompact
  187. push si
  188. mov word ptr [di].hi_ncompact,x
  189. errnz <hi_ncompact-hi_dislevel+1>
  190. cmp [di].hi_freeze,0 ; Is the heap frozen?
  191. je compact1 ; No, continue
  192. dec [di].hi_ncompact ; Yes, prevent discarding
  193. compact1:
  194. IncLocalStat ls_cloop
  195. push dx ; Save what we are looking for
  196. xor ax,ax ; Haven't found a free block yet
  197. push ax ; Remember what we have found here
  198. mov bx,[di].hi_last ; Start at end of arena
  199. mov cx,[di].hi_count
  200. ; Loop to find the next free block
  201. ;
  202. cfreeloop:
  203. IncLocalStat ls_cexamine
  204. mov ax,[bx].la_prev
  205. test al,LA_BUSY
  206. jz cfreefound
  207. and al,LA_MASK
  208. mov bx,ax
  209. cflnext:
  210. loop cfreeloop
  211. compact2:
  212. pop bx ; Recover largest free block so far
  213. pop dx ; Recover size needed
  214. mov ax,bx ; Compute size in AX
  215. or ax,ax ; Did we find a free block?
  216. jz cexit1 ; No, done
  217. sub ax,[bx].la_next ; Yes, compute size of largest free block
  218. neg ax
  219. dec [di].hi_ncompact ; Any other possibilities?
  220. jl cexit ; No, get out now
  221. cmp ax,dx ; Yes, Did we get size we needed?
  222. jb compact3 ; No, try next possibility
  223. cexit:
  224. cexit1:
  225. pop si
  226. ret ; Yes, return to caller
  227. compact3:
  228. push dx
  229. push bx
  230. dec [di].hi_dislevel ; Down to next discard level
  231. jz compact2 ; Ooops, no more, try next step
  232. inc [di].hi_ncompact ; Still discarding
  233. xor si,si ; Start enumerating handle table entries
  234. cdloop:
  235. call henum ; Get next discardable handle
  236. jz cdexit ; No, more see if we discarded anything
  237. push cx ; Got one, see if okay to discard
  238. mov cl,LN_DISCARD ; AX = LN_DISCARD
  239. xchg ax,cx ; CX = discardable flags
  240. mov bx,si ; BX = handle
  241. call lnotify
  242. pop cx
  243. or ax,ax ; Is it still discardable?
  244. jz cdloop ; No, skip this handle
  245. mov bx,[si].lhe_address ; Get true address of a block
  246. sub bx,SIZE LocalArena ; BX = address of block to free
  247. call lfree ; Free the block associated with this handle
  248. xor ax,ax ; Zero the true address field in the
  249. mov [si].lhe_address,ax
  250. or [si].lhe_flags,LHE_DISCARDED ; and mark as discarded
  251. or [di].hi_ncompact,80h ; Remember we discarded something
  252. jmp cdloop
  253. cdexit:
  254. test [di].hi_ncompact,80h ; No, did we discarded something?
  255. jz compact2
  256. xor [di].hi_ncompact,80h ; Yes, clear flag
  257. pop bx
  258. pop dx
  259. jmp compact1 ; and try compacting again
  260. ; Here when we have a free block. While the preceeding block is
  261. ; moveable, then move it down and put the free space in it place.
  262. ; When the preceeding block is not moveable, then search backwards
  263. ; for one or more moveable blocks that are small enough to fit
  264. ; in the remaining free space. Advance to previous block when
  265. ; no more blocks to examine.
  266. cfreefound:
  267. IncLocalStat ls_cfree
  268. cmp [di].hi_freeze,0 ; Is the heap frozen?
  269. jne cffexit ; No, continue
  270. ; and al,LA_MASK ; Already clear for free blocks
  271. mov si,ax ; SI = previous block
  272. test byte ptr [si].la_prev,LA_MOVEABLE
  273. jz cfreefill ; Skip if not moveable
  274. mov si,[si].la_handle ; Point to handle table entry
  275. cmp [si].lhe_count,0 ; Is it locked?
  276. jne cfreefill ; Yes, skip this block
  277. ; Here if previous block is moveable. Slide it up to the top of the
  278. ; free block and make the old busy block free. This is easy as
  279. ; we are not really adding or taking anything away from the arena
  280. ;
  281. push cx ; Save loop state regs
  282. push di
  283. mov si,ax ; SI = busy block before free block
  284. call lfreedelete ; remove [BX] from free list
  285. call lmove ; Move busy block down
  286. mov [di].la_prev,si ; Link in new busy block
  287. or byte ptr [di].la_prev,LA_MOVEABLE+LA_BUSY
  288. mov bx,ax
  289. mov [di].la_next,bx ; la_next field from old free block
  290. and [bx].la_prev,LA_ALIGN
  291. or [bx].la_prev,di
  292. mov [si].la_next,di ; Link in old busy block (new free block)
  293. and byte ptr [si].la_prev,LA_MASK ; mark it free
  294. push si
  295. push bx
  296. mov bx,si
  297. xor si,si
  298. call lfreeadd ; add new free block to free list
  299. pop bx
  300. pop si
  301. mov bx,[di].la_handle ; Modify handle table entry to point
  302. lea ax,[di].SIZE LocalArena
  303. mov [bx].lhe_address,ax ; to new location of client data
  304. pop di ; Restore arena info pointer
  305. IncLocalStat ls_cmove
  306. mov al,LN_MOVE ; Tell client we moved it
  307. lea cx,[si].SIZE LocalArena ; CX = old client data
  308. call lnotify ; BX = handle
  309. pop cx ; restore #arena entries left
  310. mov bx,si ; BX = address of free block
  311. mov si,[bx].la_prev ; SI = previous block
  312. test byte ptr [si].la_prev,LA_BUSY ; Is it free?
  313. jnz cffnext ; No, continue
  314. call ljoin ; Yes, coelesce with block in BX
  315. ;;; DO NOT change cx, ljoin leaves BX pointing after the free block
  316. ;;; dec cx ; ...keep CX in sync
  317. cffnext:
  318. jmp cflnext ; Go process next free block
  319. ; Here when done with a free block. Keep track of the largest free block
  320. ; seen so far.
  321. ;
  322. cffexit:
  323. pop si ; Recover largest free block so far
  324. cmp si,bx ; Same as current?
  325. je cff1 ; Yes, no change then
  326. test [bx].la_prev,LA_BUSY ; No, is current free?
  327. jnz cff1 ; No, ignore it then
  328. or si,si ; Yes, First time?
  329. jz cff0 ; Yes, special case
  330. mov ax,[si].la_next ; No, compute size of largest free block
  331. sub ax,si
  332. add ax,bx ; Compare to size of this free block
  333. cmp [bx].la_next,ax ; Is it bigger?
  334. jbe cff1 ; No, do nothing
  335. cff0: mov si,bx ; Yes, remember biggest free block
  336. cff1: push si ; Save largest free block so far
  337. cff2: mov bx,[bx].la_prev ; Skip past this free block
  338. and bl,LA_MASK ; (it might not be a free block)
  339. jmp cffnext
  340. ; Here if previous block is NOT moveable. Search backwards for the
  341. ; largest moveable block that will fit in this free block. As long
  342. ; as a block is found, move it to the top of the free block, free it
  343. ; from it's old location and shrink the current free block to accomodate
  344. ; the change.
  345. ;
  346. cfreefill:
  347. call lbestfit ; Search for best fit
  348. or si,si ; Find one?
  349. jz cffexit ; No, all done with this free block
  350. push cx ; Save loop state regs
  351. push di
  352. push [bx].la_prev ; Save busy block before free block
  353. call lfreedelete ; remove [BX] from free list
  354. call lmove ; Move it down
  355. ; SI = old busy address (new free block)
  356. ; DI = new busy address
  357. ; BX = old free block
  358. ; AX = block after old free block
  359. pop cx ; Recover la_prev field of old free block
  360. cmp bx,di ; Did we consume the free block?
  361. je cff ; Yes, then CX has what we want
  362. mov cx,bx ; No, then busy block will point to what
  363. mov [bx].la_next,di ; is left of the free block and vs.
  364. cff:
  365. mov [di].la_prev,cx ; Link in new busy block
  366. or byte ptr [di].la_prev,LA_MOVEABLE+LA_BUSY
  367. mov [di].la_next,ax ; la_next field from old free block
  368. xchg di,ax
  369. and [di].la_prev,LA_ALIGN
  370. or [di].la_prev,ax
  371. xchg di,ax
  372. lea cx,[di].SIZE LocalArena
  373. cmp bx,di ; Did we create a free block?
  374. je cffff
  375. push si
  376. xor si,si
  377. call lfreeadd ; Add [BX] to free list
  378. pop si
  379. cffff:
  380. cmp bx,di ; Did we create a free block?
  381. mov bx,di ; Current block is busy block
  382. mov di,[di].la_handle ; Modify handle table entry to point
  383. xchg [di].lhe_address,cx ; to new location of client data
  384. pop di ; Restore arena info pointer
  385. pop ax ; restore #arena entries left
  386. je cfff ; No, arena count okay
  387. inc ax ; Keep arena count on target
  388. inc [di].hi_count
  389. cfff:
  390. push bx ; Save current block pointer
  391. push ax ; Save #arena entries left
  392. mov al,LN_MOVE ; Tell client we moved it (CX = old addr)
  393. mov bx,[bx].la_handle ; BX = handle
  394. call lnotify
  395. pop cx ; restore #arena entries left
  396. and byte ptr [si].la_prev,not LA_MOVEABLE ; Clear moveable bit
  397. mov bx,si ; BX = address of old busy block to free
  398. push [di].hi_count
  399. call lfree ; Mark it as free
  400. pop si
  401. sub si,[di].hi_count
  402. sub cx,si ; Keep arena count on target
  403. pop bx ; BX = current block
  404. jmp cff2 ; Move to previous block.
  405. cEnd nogen
  406. ;-----------------------------------------------------------------------;
  407. ; lshrink ;
  408. ; ;
  409. ; Shrinks the local heap. ;
  410. ; ;
  411. ; Arguments: ;
  412. ; DS:DI = address of local heap information block ;
  413. ; BX = Minimum size to shrink heap ;
  414. ; ;
  415. ; Returns: ;
  416. ; AX = New size of local heap ;
  417. ; ;
  418. ; Error Returns: ;
  419. ; None. ;
  420. ; ;
  421. ; Registers Preserved: ;
  422. ; None ;
  423. ; Registers Destroyed: ;
  424. ; All ;
  425. ; Calls: ;
  426. ; ;
  427. ; History: ;
  428. ; ;
  429. ; Fri July 17, 1987 -by- Bob Gunderson [bobgu] ;
  430. ; Changed logic so we don't call lcompact every time we move ;
  431. ; a block, just call it whenever we can't find room. ;
  432. ; ;
  433. ; Fri June 12, 1987 -by- Bob Gunderson [bobgu] ;
  434. ; Wrote it. ;
  435. ;-----------------------------------------------------------------------;
  436. cProc lshrink,<PUBLIC,NEAR>
  437. cBegin nogen
  438. ; Bound the minimum size to the size specified at LocalInit() time.
  439. mov ax,[di].li_minsize
  440. cmp ax,bx ; specified smaller than min ?
  441. jbe lshr_around ; no - use what's specified
  442. mov bx,ax ; yes - use real min.
  443. lshr_around:
  444. push bx ; Save minimum heap size
  445. mov ax,[di].hi_last
  446. add ax,SIZE LocalArenaFree
  447. sub ax,[di].hi_first ; ax = current heap size
  448. cmp ax,bx ; already small enough ?
  449. ja lshr_around1
  450. jmp lshr_exit ; yes - that was quick...
  451. lshr_around1:
  452. ; local compact to get as much contiguous free space as possible.
  453. stc
  454. call lalign
  455. call lcompact ; compact everything
  456. xor dx,dx ; start with null flag
  457. ; Start with last block in heap.
  458. mov si,[di].hi_last
  459. loop1:
  460. ; SI = address of block just moved.
  461. ; This section moves moveable blocks (one at a time) up
  462. ; into free blocks below (higher addresses) all fixed blocks.
  463. ; The blocks they vacate are freed. The sentenal block is then
  464. ; moved, the heap is re-compacted. Then a test is made to see if
  465. ; the heap has shrunk enough, if not
  466. ; we start this loop again. We continue this until we can't
  467. ; move anything or we have moved enough to satisfy the minimum
  468. ; size specified by BX when called.
  469. mov si,[si].la_prev ; get next block to move
  470. and si,LA_MASK ; zap the flag bits
  471. mov ax,[si].la_prev ; get this blocks flags
  472. test ax,LA_BUSY ; is this block free?
  473. jz lshr_gobblefree ; yes - gobble this free block
  474. test ax,LA_MOVEABLE ; is it moveable ?
  475. jz lshr_cantmove ; no - exit
  476. mov bx,[si].la_handle ; get its handle
  477. cmp [bx].lhe_count,0 ; is it locked ?
  478. jnz lshr_cantmove ; yes - exit
  479. mov cx,[si].la_next
  480. sub cx,si ; get block size in cx
  481. ; Find the first free block (after fixed blocks) that is big
  482. ; enough for this block
  483. loop2:
  484. call lfirstfit
  485. jnc lshr_gotblock ; got one - continue
  486. ; If we have already tried compacting, nothing more to do
  487. or dx,dx
  488. jnz lshr_cantmove ; nothing more to do...
  489. ; Not enough room found, recompact the local heap and test again
  490. push si
  491. push cx
  492. stc
  493. call lalign
  494. call lcompact ; compact everything
  495. pop cx
  496. pop si
  497. mov dx,1 ; flag to say we have done this
  498. jmp loop2 ; try again
  499. ; DI = local arena info block address
  500. ; SI = block we didn't move (next is last block moved)
  501. lshr_cantmove:
  502. mov si,[si].la_next ; get last block moved
  503. jmp lshr_alldone ; cleanup and exit
  504. lshr_gobblefree:
  505. ; SI = address of free block
  506. ; Block to move is already free, remove it from the free list and mark
  507. ; it a busy.
  508. mov bx,si
  509. call lfreedelete
  510. or [bx].la_prev,LA_BUSY
  511. jmps lshr_shiftup
  512. lshr_gotblock:
  513. ; DI - Arena info block address
  514. ; SI - Address of block to move
  515. ; BX - Address of free block to use
  516. ; CX - Size of block to move
  517. call lfreedelete ; remove it from the free list
  518. xchg di,bx
  519. mov ax,[di].la_next
  520. sub ax,cx
  521. sub ax,LA_MINBLOCKSIZE ; Room to split free block into
  522. cmp ax,di ; two blocks ?
  523. jb lshr_nosplit ; no - don't split the block
  524. push bx
  525. push si
  526. mov bx,cx
  527. lea bx,[bx+di] ; bx = address of new free block to add
  528. ; link this new block in
  529. mov [bx].la_prev,di
  530. mov ax,[di].la_next
  531. mov [bx].la_next,ax
  532. mov [di].la_next,bx
  533. xchg ax,bx
  534. and [bx].la_prev,LA_ALIGN ; Zap only high bits
  535. or [bx].la_prev,ax ; and set new previous pointer
  536. mov bx,ax
  537. mov si,[di].la_free_prev ; previous free block
  538. call lfreeadd ; add the new smaller free block
  539. pop si
  540. pop bx
  541. inc [bx].hi_count ; bump the block count (we added
  542. ; a block)
  543. lshr_nosplit:
  544. ; BX - Arena info block address
  545. ; SI - Address of block to move
  546. ; DI - Address of free block to use
  547. ; CX - Size of block to move
  548. ; copy the flags from the old block
  549. mov ax,[si].la_prev
  550. and ax,LA_ALIGN
  551. or [di].la_prev,ax
  552. push si
  553. push di
  554. ; don't copy the block headers (but do copy the handle)
  555. add si,la_fixedsize
  556. add di,la_fixedsize
  557. sub cx,la_fixedsize
  558. ; We can take # bytes/2 as # words to move because all blocks
  559. ; start on even 4 byte boundary.
  560. shr cx,1 ; bytes / 2 = words
  561. push ds
  562. pop es ; same segment
  563. cld ; auto-increment
  564. rep movsw ; Head 'em up! Move 'em out!
  565. pop di
  566. pop si
  567. ; BX - Arena info block address
  568. ; SI - Address of block to move
  569. ; DI - Address of free block to use
  570. ; Fixup the handle table pointer
  571. push bx
  572. mov bx,[si].la_handle
  573. lea ax,[di].SIZE LocalArena
  574. mov [bx].lhe_address,ax
  575. pop di ; DI = info block address
  576. ; Mark the old block as busy fixed
  577. and [si].la_prev,LA_MASK ; clear old bits
  578. or [si].la_prev,LA_BUSY ; put in busy fixed bit
  579. jmps lshr_shiftup
  580. ; Time to shift the setenal block up, recompact and look for more
  581. ; space...
  582. ; DI = local arena info block address
  583. ; SI = block just freed
  584. public foo
  585. foo:
  586. lshr_shiftup:
  587. mov ax,[di].hi_last
  588. mov bx,ax
  589. sub bx,si ; less what is already removed
  590. sub ax,bx
  591. add ax,SIZE LocalArenaFree ; size of sentenal block
  592. sub ax,[di].hi_first ; ax = current heap size
  593. pop bx ; get min size
  594. push bx ; and put it back on stack
  595. cmp ax,bx ; already small enough ?
  596. jbe lshr_alldone ; yes - exit
  597. xor dx,dx ; localcompact flag
  598. jmp loop1 ; and back for more
  599. lshr_alldone:
  600. ; DI = local arena info block address
  601. ; SI = last block moved
  602. ; Time to shift the sentenal block up and realloc our heap
  603. pop bx ; Minimum size of the heap
  604. push bx
  605. call slide_sentenal ; slide the sentenal block up
  606. ; get our data segment handle
  607. push ds
  608. call GlobalHandle ; ax = handle of DS
  609. or ax,ax
  610. jz lshr_exit ; this can't happen.....
  611. push ax ; hMem
  612. ; determine how big we should be
  613. mov ax,[di].hi_last
  614. add ax,SIZE LocalArenaFree
  615. xor cx,cx
  616. push cx
  617. push ax ; # bytes in DS
  618. push cx ; no wFlags
  619. call GlobalRealloc
  620. ; local compact to get as much contiguous free space as possible.
  621. lshr_exit:
  622. stc
  623. call lalign
  624. call lcompact ; compact everything
  625. pop ax ; clean the stack
  626. mov ax,[di].hi_last
  627. add ax,SIZE LocalArenaFree
  628. sub ax,[di].hi_first ; ax = current heap size
  629. ret
  630. cEnd nogen
  631. ;-------------------------------------------------------------------------
  632. ; Find first free block after last fixed block. We do this by scanning
  633. ; through the free list looking for a free block with the next physical
  634. ; block being moveable (remember we just did a compact...). Then, starting
  635. ; with this free block, find the first free block that is at least
  636. ; CX bytes long.
  637. ;
  638. ; Entry:
  639. ; DI = local arena header info block address
  640. ; CX = # bytes needed
  641. ;
  642. ; Exit:
  643. ; BX = Address of free block to use
  644. ;
  645. ; Error Return:
  646. ; Carry set if no free block big enough
  647. ;
  648. ; History:
  649. ;
  650. ; Fri June 12, 1987 -by- Bob Gunderson [bobgu]
  651. ; Wrote it.
  652. ;-------------------------------------------------------------------------
  653. cProc lfirstfit,<PUBLIC,NEAR>
  654. cBegin nogen
  655. push ax
  656. mov bx,[di].hi_last
  657. mov bx,[bx].la_free_prev
  658. ; mov bx,[di].hi_first
  659. ; mov bx,[bx].la_free_next
  660. lffloop:
  661. cmp bx,[bx].la_free_prev
  662. ; cmp bx,[bx].la_free_next
  663. jz lff_err_exit
  664. cmp cx,[bx].la_size
  665. jbe lff_exit
  666. mov bx,[bx].la_free_prev
  667. ; mov bx,[bx].la_free_next
  668. jmp lffloop
  669. lff_err_exit:
  670. stc
  671. jmps lff_done
  672. lff_exit:
  673. clc ; good return
  674. lff_done:
  675. pop ax
  676. ret
  677. cEnd nogen
  678. ;-------------------------------------------------------------------------
  679. ; slide_sentenal
  680. ; This routine is called during the LocalShrink() operation.
  681. ; Make all the blocks between the one at SI and the sentenal go
  682. ; away. Then check to see if we have shrunk the heap too much. If
  683. ; so, then add a free block at SI big enough to bump the size up (this
  684. ; will be moved later by LocalCompact). Now move the sentenal block
  685. ; up after the last block.
  686. ;
  687. ; Entry:
  688. ; BX = requested minimum size of the heap
  689. ; SI = last block actually moved (put sentenal here)
  690. ; DI = local arena info block address
  691. ;
  692. ; Exit:
  693. ;
  694. ; Error Return:
  695. ;
  696. ; History:
  697. ;
  698. ; Fri Aug 14, 1987 -by- Bob Gunderson [bobgu]
  699. ; Changed things again to insure we don't shrink to heap too much.
  700. ;
  701. ; Fri July 17, 1987 -by- Bob Gunderson [bobgu]
  702. ; Was too slow, so changed the logic.
  703. ;
  704. ; Fri June 12, 1987 -by- Bob Gunderson [bobgu]
  705. ; Wrote it.
  706. ;-------------------------------------------------------------------------
  707. cProc slide_sentenal,<PUBLIC,NEAR>
  708. cBegin nogen
  709. push bx
  710. ; Get sentenal block
  711. mov bx,[di].hi_last
  712. ; Insure that we aren't trying to move to ourselves
  713. cmp si,bx
  714. jz slide_exit ; nothing to do....
  715. ; count the number of block we are removing so that we can update
  716. ; the block count in the arena header.
  717. push si
  718. xor cx,cx
  719. slide_loop:
  720. cmp si,bx
  721. jz slide_loop_exit
  722. inc cx
  723. mov si,[si].la_next
  724. jmp slide_loop
  725. slide_loop_exit:
  726. pop si
  727. sub [di].hi_count,cx ; decrement the count of blocks
  728. ; Would the heap be too small if the sentenal were moved to the block
  729. ; pointed to by si? If so, add a free block at SI to make up the
  730. ; difference.
  731. mov ax,si
  732. sub ax,[di].hi_first
  733. add ax,la_freefixedsize ; size of heap in ax
  734. pop bx ; minimum in bx
  735. cmp ax,bx
  736. ja slide_ok ; everything is ok...
  737. sub bx,ax ; bx = size to grow
  738. cmp bx,LA_MINBLOCKSIZE
  739. jbe slide_ok ; not enough for a block
  740. clc
  741. call lalign ; make it even 4 byte boundary
  742. mov bx,dx
  743. ; add a free block of bx bytes
  744. lea ax,[si+bx] ; address of new "next" block
  745. mov [si].la_next,ax ; make block point at "next"
  746. and [si].la_prev,LA_MASK ; make it a free block
  747. xor bx,bx
  748. xchg si,bx ; bx = block to add, si = 0
  749. call lfreeadd ; preserves ax
  750. inc [di].hi_count ; bump block count
  751. mov si,ax ; and bump si to "next" block
  752. mov [si].la_prev,bx ; set new block's previous pointer
  753. slide_ok:
  754. ; move the sentenal block up by copying the words.
  755. mov bx,[di].hi_last ; old sentenal block
  756. mov [si].la_next,si ; new sentenal points to self
  757. and [si].la_prev,LA_MASK ; remove any old flags
  758. or [si].la_prev,LA_BUSY ; make it busy
  759. mov ax,[bx].la_size
  760. mov [si].la_size,ax ; move in the size
  761. mov bx,[bx].la_free_prev
  762. mov [si].la_free_prev,bx ; move in previous free block
  763. mov [bx].la_free_next,si ; point prev free block to this one
  764. mov [si].la_free_next,si ; point to itself
  765. ; Now fixup the arena header block to point to the new setenal
  766. ; position.
  767. mov [di].hi_last,si
  768. ; And we are done...
  769. jmps slide_exit1
  770. slide_exit:
  771. pop bx
  772. slide_exit1:
  773. ret
  774. cEnd nogen
  775. sEnd CODE
  776. end