@@ -355,13 +355,14 @@ module Awaitable = struct
355355  let  update  t  ~signal   ~count   = 
356356    try 
357357      let  signal =  ref  signal in 
358+       let  count =  ref  count in 
358359      let  backoff =  ref  Backoff. default in 
359360      while 
360361        not 
361362          (let  before =  Htbl. find_exn awaiters t in 
362363           match 
363-              if  ! signal then  Awaiters. signal before ~count 
364-              else  Awaiters. cleanup before ~count 
364+              if  ! signal then  Awaiters. signal before ~count:  ! count 
365+              else  Awaiters. cleanup before ~count:  ! count 
365366           with 
366367           |  Zero  -> Htbl. try_compare_and_remove awaiters t before
367368           |  One  r  ->
@@ -373,58 +374,70 @@ module Awaitable = struct
373374               before ==  after
374375               ||  Htbl. try_compare_and_set awaiters t before after)
375376      do 
377+         (*  Even if the hash table update after signal fails, the trigger(s) have
378+            been signaled. *)  
376379        signal :=  false ;
380+         (*  If a single awaiter and multi awaiter cleanup are attempted in
381+            parallel it might be that a multi awaiter cleanup "succeeds" and yet 
382+            some awaiters are left in the queue.  For this reason we perform a 
383+            multi awaiter cleanup after failure.  It might be possible to improve 
384+            upon this with some more clever approach. *)  
385+         count :=  Int. max_int;
377386        backoff :=  Backoff. once ! backoff
378387      done 
379388    with  Not_found  ->  () 
380389
381-   let  add_as  (type  a ) (t  : a awaitable ) value  = 
382-     let  trigger =  Trigger. create ()  in 
383-     let  one  : Awaiters.is1  = 
384-       One  { awaitable =  t; value; trigger; counter =  0 ; next =  Min0  Zero  }
385-     in 
386-     let  backoff =  ref  Backoff. default in 
387-     while 
388-       not 
389-         (match  Htbl. find_exn awaiters (Packed  t) with 
390-         |  before  ->
391-             let  many =  Awaiters. snoc before one in 
392-             Htbl. try_compare_and_set awaiters (Packed  t) before (Min1  many)
393-         |  exception  Not_found  -> Htbl. try_add awaiters (Packed  t) (Min1  one))
394-     do 
395-       backoff :=  Backoff. once ! backoff
396-     done ;
397-     one
398- 
399390  module  Awaiter  =  struct 
400391    type  t  = Awaiters .is1 
401392
402-     let  add  (type  a ) (t  : a awaitable ) = 
403-       add_as t (Sys. opaque_identity (Obj. magic awaiters : a ))
393+     let  add_as  (type  a ) (t  : a awaitable ) trigger  value  = 
394+       let  one  : Awaiters.is1  = 
395+         One  { awaitable =  t; value; trigger; counter =  0 ; next =  Min0  Zero  }
396+       in 
397+       let  backoff =  ref  Backoff. default in 
398+       while 
399+         not 
400+           (match  Htbl. find_exn awaiters (Packed  t) with 
401+           |  before  ->
402+               let  many =  Awaiters. snoc before one in 
403+               Htbl. try_compare_and_set awaiters (Packed  t) before (Min1  many)
404+           |  exception  Not_found  -> Htbl. try_add awaiters (Packed  t) (Min1  one))
405+       do 
406+         backoff :=  Backoff. once ! backoff
407+       done ;
408+       one
409+ 
410+     let  add  (type  a ) (t  : a awaitable ) trigger  = 
411+       let  unique_value =  Sys. opaque_identity (Obj. magic awaiters : a ) in 
412+       add_as t trigger unique_value
404413
405414    let  remove  one  = 
406415      Awaiters. signal_and_clear one;
407416      update (Awaiters. awaitable_of one) ~signal: false  ~count: 1 
417+   end 
408418
409-     let  await  one  = 
419+   let  await  t  value  = 
420+     let  trigger =  Trigger. create ()  in 
421+     let  one =  Awaiter. add_as t trigger value in 
422+     if  Awaiters. is_signalable one then  Awaiter. remove one
423+     else 
410424      match  Awaiters. await one with 
411425      |  None  -> () 
412426      |  Some  exn_bt  ->
413427          Awaiters. clear one;
414428          update (Awaiters. awaitable_of one) ~signal: true  ~count: 1 ;
415429          Printexc. raise_with_backtrace (fst exn_bt) (snd exn_bt)
416-   end 
417- 
418-   let  await  t  value  = 
419-     let  one =  add_as t value in 
420-     if  Awaiters. is_signalable one then  Awaiter. remove one else  Awaiter. await one
421430
422431  let [@ inline] broadcast t =  update (Packed  t) ~signal: true  ~count: Int. max_int
423432  let [@ inline] signal t =  update (Packed  t) ~signal: true  ~count: 1 
424433
425434  let  ()  = 
426435    Stdlib. at_exit @@  fun  ()  ->
427436    match  Htbl. find_random_exn awaiters with 
428-     |  _  -> failwith " leaked awaitable" 
437+     |  _  ->
438+         (*  This should not normally happen, but might happen due to the program
439+            being forced to exit without proper cleanup.  Otherwise this may 
440+            indicate a bug in the cleanup of awaiters. *)  
441+         Printf. eprintf " Awaitable leaked\n %!" 
429442    |  exception  Not_found  -> () 
430443end
0 commit comments