Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
bounded_queue.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182type 'a t = { max_size: int; q: 'a Queue.t; mutex: Mutex.t; cond_push: Condition.t; cond_pop: Condition.t; mutable closed: bool; } exception Closed let create ~max_size () : _ t = if max_size < 1 then invalid_arg "Bounded_queue.create"; { max_size; mutex = Mutex.create (); cond_push = Condition.create (); cond_pop = Condition.create (); q = Queue.create (); closed = false; } let close (self : _ t) = Mutex.lock self.mutex; if not self.closed then ( self.closed <- true; (* awake waiters so they fail *) Condition.broadcast self.cond_push; Condition.broadcast self.cond_pop ); Mutex.unlock self.mutex (** Check if the queue is full. Precondition: [self.mutex] is acquired. *) let[@inline] is_full_ (self : _ t) : bool = Queue.length self.q >= self.max_size let push (self : _ t) x : unit = let continue = ref true in Mutex.lock self.mutex; while !continue do if self.closed then ( (* push always fails on a closed queue *) Mutex.unlock self.mutex; raise Closed ) else if is_full_ self then Condition.wait self.cond_push self.mutex else ( let was_empty = Queue.is_empty self.q in Queue.push x self.q; if was_empty then Condition.broadcast self.cond_pop; (* exit loop *) continue := false; Mutex.unlock self.mutex ) done let pop (self : 'a t) : 'a = Mutex.lock self.mutex; let rec loop () = if Queue.is_empty self.q then ( if self.closed then ( (* pop fails on a closed queue if it's also empty, otherwise it still returns the remaining elements *) Mutex.unlock self.mutex; raise Closed ); Condition.wait self.cond_pop self.mutex; (loop [@tailcall]) () ) else ( let was_full = is_full_ self in let x = Queue.pop self.q in (* wakeup pushers that were blocked *) if was_full then Condition.broadcast self.cond_push; Mutex.unlock self.mutex; x ) in loop () let try_pop ~force_lock (self : _ t) : _ option = let has_lock = if force_lock then ( Mutex.lock self.mutex; true ) else Mutex.try_lock self.mutex in if has_lock then ( if self.closed then ( Mutex.unlock self.mutex; raise Closed ); let was_full_before_pop = is_full_ self in match Queue.pop self.q with | x -> (* wakeup pushers that are blocked *) if was_full_before_pop then Condition.broadcast self.cond_push; Mutex.unlock self.mutex; Some x | exception Queue.Empty -> Mutex.unlock self.mutex; None ) else None let try_push ~force_lock (self : _ t) x : bool = let has_lock = if force_lock then ( Mutex.lock self.mutex; true ) else Mutex.try_lock self.mutex in if has_lock then ( if self.closed then ( Mutex.unlock self.mutex; raise Closed ); if is_full_ self then ( Mutex.unlock self.mutex; false ) else ( let was_empty = Queue.is_empty self.q in Queue.push x self.q; if was_empty then Condition.broadcast self.cond_pop; Mutex.unlock self.mutex; true ) ) else false let[@inline] max_size self = self.max_size let size (self : _ t) : int = Mutex.lock self.mutex; let n = Queue.length self.q in Mutex.unlock self.mutex; n let transfer (self : 'a t) q2 : unit = Mutex.lock self.mutex; let continue = ref true in while !continue do if Queue.is_empty self.q then ( if self.closed then ( Mutex.unlock self.mutex; raise Closed ); Condition.wait self.cond_pop self.mutex ) else ( let was_full = is_full_ self in Queue.transfer self.q q2; if was_full then Condition.broadcast self.cond_push; continue := false; Mutex.unlock self.mutex ) done type 'a gen = unit -> 'a option type 'a iter = ('a -> unit) -> unit let to_iter self k = try while true do let x = pop self in k x done with Closed -> () let to_gen self : _ gen = fun () -> match pop self with | exception Closed -> None | x -> Some x let rec to_seq self : _ Seq.t = fun () -> match pop self with | exception Closed -> Seq.Nil | x -> Seq.Cons (x, to_seq self)