@@ -326,23 +326,26 @@ module Intr = struct
326
326
327
327
let intr_key =
328
328
Picos_tls. new_key @@ fun () : [ `Req ] tdt ->
329
- Req { state = get () ; unused = true ; computation = cleared }
329
+ Req { state = get () ; unused = false ; computation = cleared }
330
330
331
331
let [@ inline] use = function R Nothing -> () | R (Req r ) -> r.unused < - false
332
332
333
333
let handle _ =
334
334
let (Req r) = Picos_tls. get intr_key in
335
335
Computation. return r.computation Signaled
336
336
337
- let rec finish (Req r as req : [ `Req ] tdt ) backoff =
337
+ (* * This is used to ensure that the [intr_pending] counter is incremented
338
+ exactly once before the counter is decremented. *)
339
+ let rec incr_once (Req r as req : [ `Req ] tdt ) backoff =
338
340
let before = Atomic. get intr_pending in
341
+ (* [intr_pending] must be read before [r.unused]! *)
339
342
r.unused && before.req != R req
340
343
&& begin
341
344
use before.req;
342
345
let after = { value = before.value + 1 ; req = R req } in
343
346
if Atomic. compare_and_set intr_pending before after then
344
347
after.value = 1
345
- else finish req (Backoff. once backoff)
348
+ else incr_once req (Backoff. once backoff)
346
349
end
347
350
348
351
let intr_action trigger (Req r as req : [ `Req ] tdt ) id =
@@ -353,14 +356,14 @@ module Intr = struct
353
356
| Signaled ->
354
357
(* Signal was delivered before timeout. *)
355
358
remove_action trigger r.state id;
356
- if finish req Backoff. default then
359
+ if incr_once req Backoff. default then
357
360
(* We need to make sure at least one select thread will keep on
358
361
triggering interrupts. *)
359
362
wakeup r.state `Alive
360
363
| exception Exit ->
361
364
(* The timeout was triggered. This must have been called from the
362
365
select thread, which will soon trigger an interrupt. *)
363
- let _ : bool = finish req Backoff. default in
366
+ let _ : bool = incr_once req Backoff. default in
364
367
()
365
368
366
369
let () =
@@ -411,7 +414,9 @@ module Intr = struct
411
414
let _was_blocked : int list = Thread. sigmask SIG_BLOCK intr_sigs in
412
415
(* assert (not (List.exists is_intr_sig was_blocked)); *)
413
416
if not (Computation. try_return r.computation Cleared ) then begin
414
- let _ : bool = finish req Backoff. default in
417
+ let _ : bool = incr_once req Backoff. default in
418
+ (* We ensure that the associated increment has been done before we
419
+ decrement so that the [intr_pending] counter is never too low. *)
415
420
decr Backoff. default
416
421
end
417
422
end
0 commit comments