123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105(*
* Copyright (c) 2015 Thomas Leonard
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openLwt.InfixmoduleGntref=Xen_os.Xen.GntrefmoduleExport=Xen_os.Xen.Exportletreturn=Lwt.returnletmax_pages=256typeblock={id:Cstruct.uint16;gref:Gntref.t;data:Cstruct.t;}typet={grant:Gntref.t->Io_page.t->unit;mutablenext_id:Cstruct.uint16;mutableblocks:blocklist;mutablein_use:int;mutableshutdown:bool;avail:unitLwt_condition.t;(* Fires when free list becomes non-empty *)}letpage_size=Io_page.round_to_page_size1letblock_size=page_size/2letmakegrant={next_id=0;grant;blocks=[];shutdown=false;in_use=0;avail=Lwt_condition.create()}letshutdownt=t.shutdown<-true;Lwt_condition.broadcastt.avail();(* Wake anyone who's still waiting for free pages *)ift.in_use=0then(t.blocks|>List.iter(fun{id=_;gref;data}->ifdata.Cstruct.off=0then(Lwt.async(fun()->Export.end_access~release_ref:truegref)));t.blocks<-[])(* Otherwise, shutdown gets called again when in_use becomes 0 *)letalloct=letpage=Io_page.get1in(* (the Xen version of caml_alloc_pages clears the page, so we don't have to) *)Export.get()>>=fungnt->t.grantgntpage;return(gnt,Io_page.to_cstructpage)letputtblock=letwas_empty=(t.blocks=[])int.blocks<-block::t.blocks;t.in_use<-t.in_use-1;ifwas_emptythenLwt_condition.broadcastt.avail();ift.in_use=0&&t.shutdownthenshutdowntletuse_blocktfnblock=let{id;gref;data}=blockint.in_use<-t.in_use+1;Lwt.try_bind(fun()->fn~idgrefdata)(fun(_,releaseasresult)->Lwt.on_terminationrelease(fun()->puttblock);returnresult)(funex->puttblock;Lwt.failex)letrecusetfn=ift.shutdownthenfailwith"Shared_page_pool.use after shutdown";matcht.blockswith|[]whent.next_id>=max_pages->Lwt_condition.waitt.avail>>=fun()->usetfn|[]->(* Frames normally fit within 2048 bytes, so we split each page in half. *)alloct>>=fun(gref,page)->letb1=Cstruct.subpage0block_sizeinletb2=Cstruct.shiftpageblock_sizeinletid1=t.next_idinletid2=t.next_id+1int.next_id<-t.next_id+2;t.blocks<-{id=id2;gref;data=b2}::t.blocks;Lwt_condition.broadcastt.avail();use_blocktfn{id=id1;gref;data=b1}|hd::tl->t.blocks<-tl;use_blocktfnhdletblocks_neededbytes=(bytes+block_size-1)/block_size