brk.rs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. //! BRK abstractions.
  2. //!
  3. //! This module provides safe abstractions over SBRK.
  4. use prelude::*;
  5. use core::cmp;
  6. /// Canonicalize a BRK request.
  7. ///
  8. /// Syscalls can be expensive, which is why we would rather accquire more memory than necessary,
  9. /// than having many syscalls acquiring memory stubs. Memory stubs are small blocks of memory,
  10. /// which are essentially useless until merge with another block.
  11. ///
  12. /// To avoid many syscalls and accumulating memory stubs, we BRK a little more memory than
  13. /// necessary. This function calculate the memory to be BRK'd based on the necessary memory.
  14. ///
  15. /// The return value is always greater than or equals to the argument.
  16. #[inline]
  17. fn canonicalize_space(min: usize) -> usize {
  18. // TODO: Tweak this.
  19. /// The BRK multiplier.
  20. ///
  21. /// The factor determining the linear dependence between the minimum segment, and the acquired
  22. /// segment.
  23. const BRK_MULTIPLIER: usize = 2;
  24. /// The minimum size to be BRK'd.
  25. const BRK_MIN: usize = 1024;
  26. /// The maximal amount of _extra_ elements.
  27. const BRK_MAX_EXTRA: usize = 65536;
  28. let res = cmp::max(BRK_MIN, min + cmp::min(BRK_MULTIPLIER * min, BRK_MAX_EXTRA));
  29. // Make some handy assertions.
  30. debug_assert!(res >= min, "Canonicalized BRK space is smaller than the one requested.");
  31. res
  32. }
  33. /// BRK new space.
  34. ///
  35. /// The first block represents the aligner segment (that is the precursor aligning the middle
  36. /// block to `align`), the second one is the result and is of exactly size `size`. The last
  37. /// block is the excessive space.
  38. pub fn get(size: usize, align: usize) -> (Block, Block, Block) {
  39. // Calculate the canonical size (extra space is allocated to limit the number of system calls).
  40. let brk_size = canonicalize_space(size) + align;
  41. // Use SBRK to allocate extra data segment. The alignment is used as precursor for our
  42. // allocated block. This ensures that it is properly memory aligned to the requested value.
  43. let (alignment_block, rest) = Block::brk(brk_size).align(align).unwrap();
  44. // Split the block to leave the excessive space.
  45. let (res, excessive) = rest.split(size);
  46. // Make some assertions.
  47. debug_assert!(res.aligned_to(align), "Alignment failed.");
  48. debug_assert!(res.size() + alignment_block.size() + excessive.size() == brk_size, "BRK memory leak.");
  49. (alignment_block, res, excessive)
  50. }
  51. #[cfg(test)]
  52. mod test {
  53. use super::*;
  54. #[test]
  55. fn test_ordered() {
  56. let brk = get(20, 1);
  57. assert!(brk.0 <= brk.1);
  58. assert!(brk.1 <= brk.2);
  59. }
  60. }