123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)modulePriorityQueue:sigtype'atvalcreate:unit->'atvalset_rel:('a->'a->int)->'at->unitvalis_empty:'at->boolvalexists:('a->bool)->'at->boolvalpop:?picky:('a->bool)->'at->'avalpush:'at->'a->unitvalclear:'at->unitvallength:'at->intend=structtype'aitem=int*'atype'arel='aitem->'aitem->inttype'at=('aitemlist*'arel)refletsort_timestamp(i,_)(j,_)=i-jletage=ref0letcreate()=ref([],sort_timestamp)letis_emptyt=fst!t=[]letexistspt=List.exists(fun(_,x)->px)(fst!t)letpop?(picky=(fun_->true))t=let(l,rel)=!tinletrecauxacc=function|[]->raiseQueue.Empty|(_,x)::xswhenpickyx->t:=(List.revacc@xs,rel);x|(_,x)ashd::xs->aux(hd::acc)xsinaux[]lletpushtx=let(xs,rel)=!tinincrage;(* re-roting the whole list is not the most efficient way... *)t:=(List.sortrel(xs@[!age,x]),rel)letcleart=t:=([],snd!t)letset_relrelt=letrel(_,x)(_,y)=relxyint:=(List.sortrel(fst!t),rel)letlengtht=List.length(fst!t)endtype'at={queue:'aPriorityQueue.t;lock:Mutex.t;cond:Condition.t;mutablenwaiting:int;cond_waiting:Condition.t;mutablerelease:bool;}exceptionBeingDestroyedletcreate()={queue=PriorityQueue.create();lock=Mutex.create();cond=Condition.create();nwaiting=0;cond_waiting=Condition.create();release=false;}letpop?(picky=(fun_->true))?(destroy=reffalse)tq=let{queue=q;lock=m;cond=c;cond_waiting=cn}=tqinCThread.with_lockm~scope:(fun()->iftq.releasethenraiseBeingDestroyed;whilenot(PriorityQueue.existspickyq||!destroy)dotq.nwaiting<-tq.nwaiting+1;Condition.broadcastcn;Condition.waitcm;tq.nwaiting<-tq.nwaiting-1;iftq.release||!destroythenraiseBeingDestroyeddone;if!destroythenraiseBeingDestroyed;letx=PriorityQueue.pop~pickyqinCondition.signalc;Condition.signalcn;x)letbroadcasttq=let{lock=m;cond=c}=tqinCThread.with_lockm~scope:(fun()->Condition.broadcastc)letpushtqx=let{queue=q;lock=m;cond=c;release}=tqinifreleasethenCErrors.anomaly(Pp.str"TQueue.push while being destroyed! Only 1 producer/destroyer allowed.");CThread.with_lockm~scope:(fun()->PriorityQueue.pushqx;Condition.broadcastc)letlengthtq=let{queue=q;lock=m}=tqinCThread.with_lockm~scope:(fun()->PriorityQueue.lengthq)letcleartq=let{queue=q;lock=m;cond=c}=tqinCThread.with_lockm~scope:(fun()->PriorityQueue.clearq)letclear_savingtqf=let{queue=q;lock=m;cond=c}=tqinletsaved=ref[]inCThread.with_lockm~scope:(fun()->whilenot(PriorityQueue.is_emptyq)doletelem=PriorityQueue.popqinmatchfelemwith|Somex->saved:=x::!saved|None->()done);List.rev!savedletis_emptytq=PriorityQueue.is_emptytq.queueletdestroytq=tq.release<-true;whiletq.nwaiting>0doCThread.with_locktq.lock~scope:(fun()->Condition.broadcasttq.cond)done;tq.release<-falseletwait_until_n_are_waiting_and_queue_emptyjtq=CThread.with_locktq.lock~scope:(fun()->whilenot(PriorityQueue.is_emptytq.queue)||tq.nwaiting<jdoCondition.waittq.cond_waitingtq.lockdone)letwait_until_n_are_waiting_then_snapshotjtq=letl=ref[]inCThread.with_locktq.lock~scope:(fun()->whilenot(PriorityQueue.is_emptytq.queue)dol:=PriorityQueue.poptq.queue::!ldone;whiletq.nwaiting<jdoCondition.waittq.cond_waitingtq.lockdone;List.iter(PriorityQueue.pushtq.queue)(List.rev!l);if!l<>[]thenCondition.broadcasttq.cond);List.rev!lletset_ordertqrel=CThread.with_locktq.lock~scope:(fun()->PriorityQueue.set_relreltq.queue)