Skip to content

Instantly share code, notes, and snippets.

@ezyang
Created December 13, 2013 13:57
Show Gist options
  • Select an option

  • Save ezyang/7944606 to your computer and use it in GitHub Desktop.

Select an option

Save ezyang/7944606 to your computer and use it in GitHub Desktop.
pub fn alloc_mega_group(mblocks: nat) -> ~Block {
let n = MBLOCK_GROUP_BLOCKS(mblocks);
enum SearchResult<'a> {
PerfectMatch(~Block),
BestMatch(&'a mut BlockData, &'a mut BlockMeta),
NoMatch
}
// tail-recursive style makes the borrow-checker *a lot*
// happier, since some of the aliasing effects that occur when
// local mutable variables are reused go away (fresh lexical
// scope, fresh lifetime, it's great)
fn go<'a>(n: uint,
prev_link: &'a mut Option<~Block>,
best: Option<(&'a mut BlockData, &'a mut BlockMeta)>)
-> SearchResult<'a> {
match prev_link {
&None => match best {
None => NoMatch,
Some((data, meta)) => BestMatch(data, meta)
},
// NB: need to match it out, so we don't take out a
// reference on prev_link that will interfere with the
// take()
&Some(~Block {meta: BlockMeta {blocks, ..}, ..}) if blocks as uint == n => {
let mut bd = prev_link.take_unwrap();
*prev_link = bd.link.p.take();
PerfectMatch(bd)
},
&Some(ref mut bd) => {
if bd.meta.blocks as uint > n && match best {
None => true,
Some((_, ref best_meta)) => bd.meta.blocks < best_meta.blocks
} {
go(n, &mut bd.link.p, Some((&mut bd.data, &mut bd.meta)))
} else {
go(n, &mut bd.link.p, best)
}
}
}
}
// NB: global_ref can be used to mutate global state
let mut global_ref = unsafe { &mut free_mblock_list.p };
let mut bd: ~Block = match go(n, global_ref, None) {
// We found a perfect match and removed it from the list
PerfectMatch(p) => return p,
// Take our chunk off the end of the best match
BestMatch(ref data, ref mut meta) => {
let best_mblocks = BLOCKS_TO_MBLOCKS(meta.blocks as uint);
// bd = FIRST_BDESCR((StgWord8*)MBLOCK_ROUND_DOWN(best) +·
// (best_mblocks-mblocks)*MBLOCK_SIZE);
meta.blocks = MBLOCK_GROUP_BLOCKS(best_mblocks - mblocks) as u32;
fail!("initMBlock(MBLOCK_ROUND_DOWN(bd));")
},
// Nothing in the free list was big enough, so allocate
NoMatch => {
let mut mblock = MBlock::new(mblocks);
fail!("bd = FIRST_BDESCR(mblock);");
},
};
bd.meta.blocks = MBLOCK_GROUP_BLOCKS(mblocks) as u32;
return bd
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment