1
1
open Picos
2
2
3
- let intr_sig = Sys. sigusr2
4
- let is_intr_sig s = s == intr_sig
5
- let intr_sigs = [ intr_sig ]
3
+ type config = { mutable intr_sig : int ; mutable intr_sigs : int list }
4
+
5
+ let config = { intr_sig = 0 ; intr_sigs = [] }
6
+
7
+ (* *)
6
8
7
9
type cancel_at =
8
10
| Cancel_at : {
@@ -65,6 +67,15 @@ type counter_state = { value : int; req : req }
65
67
let intr_pending = Atomic. make { value = 0 ; req = R Nothing }
66
68
let exit_exn_bt = Exn_bt. get_callstack 0 Exit
67
69
70
+ let cleared =
71
+ let computation = Computation. create () in
72
+ Computation. return computation Cleared ;
73
+ computation
74
+
75
+ let intr_key =
76
+ Picos_thread.TLS. new_key @@ fun () : [ `Req ] tdt ->
77
+ invalid_arg " Picos_select has not been configured"
78
+
68
79
let key =
69
80
Picos_domain.DLS. new_key @@ fun () ->
70
81
{
@@ -198,15 +209,17 @@ and select_thread_continue s rd wr ex (rd_fds, wr_fds, ex_fds) =
198
209
if state.value = 0 then tos
199
210
else begin
200
211
assert (0 < state.value);
201
- Unix. kill (Unix. getpid () ) intr_sig;
212
+ Unix. kill (Unix. getpid () ) config. intr_sig;
202
213
let idle = 0.000_001 (* 1μs *) in
203
214
if tos < 0.0 || idle < = tos then idle else tos
204
215
end
205
216
in
206
217
select_thread s tos rd wr ex
207
218
208
219
let select_thread s =
209
- if not Sys. win32 then Thread. sigmask SIG_BLOCK intr_sigs |> ignore;
220
+ if not Sys. win32 then begin
221
+ Thread. sigmask SIG_BLOCK config.intr_sigs |> ignore
222
+ end ;
210
223
begin
211
224
try
212
225
let pipe_inn, pipe_out = Unix. pipe ~cloexec: true () in
@@ -220,7 +233,46 @@ let select_thread s =
220
233
if s.pipe_inn != Unix. stdin then Unix. close s.pipe_inn;
221
234
if s.pipe_out != Unix. stdin then Unix. close s.pipe_out
222
235
236
+ let [@ poll error] [@ inline never] try_configure ~intr_sig ~intr_sigs =
237
+ config.intr_sigs == []
238
+ && begin
239
+ config.intr_sig < - intr_sig;
240
+ config.intr_sigs < - intr_sigs;
241
+ true
242
+ end
243
+
244
+ let is_intr_sig signum = signum = config.intr_sig
245
+
246
+ let rec configure ?(intr_sig = Sys. sigusr2) () =
247
+ if not (Picos_thread. is_main_thread () ) then
248
+ invalid_arg
249
+ " Picos_select must be configured from the main thread on the main domain" ;
250
+ assert (Sys. sigabrt = - 1 && Sys. sigxfsz < Sys. sigabrt);
251
+ if intr_sig < Sys. sigxfsz || 0 < = intr_sig || intr_sig = Sys. sigchld then
252
+ invalid_arg " Invalid interrupt signal number" ;
253
+ if not (try_configure ~intr_sig ~intr_sigs: [ intr_sig ]) then
254
+ invalid_arg " Picos_select.configure already configured" ;
255
+
256
+ if not Sys. win32 then begin
257
+ begin
258
+ let previously_blocked = Thread. sigmask SIG_BLOCK config.intr_sigs in
259
+ assert (not (List. exists is_intr_sig previously_blocked));
260
+ let old_behavior =
261
+ Sys. signal config.intr_sig (Sys. Signal_handle handle_signal)
262
+ in
263
+ assert (old_behavior == Signal_default )
264
+ end
265
+ end
266
+
267
+ and handle_signal signal =
268
+ if signal = config.intr_sig then
269
+ let (Req r) = Picos_thread.TLS. get intr_key in
270
+ Computation. return r.computation Signaled
271
+
272
+ let check_configured () = if config.intr_sigs = [] then configure ()
273
+
223
274
let [@ inline never] init s =
275
+ check_configured () ;
224
276
if try_transition s `Initial `Starting then begin
225
277
match Thread. create select_thread s with
226
278
| thread ->
@@ -319,21 +371,8 @@ let await_on file_descr op =
319
371
module Intr = struct
320
372
type t = req
321
373
322
- let cleared =
323
- let computation = Computation. create () in
324
- Computation. return computation Cleared ;
325
- computation
326
-
327
- let intr_key =
328
- Picos_thread.TLS. new_key @@ fun () : [ `Req ] tdt ->
329
- Req { state = get () ; unused = false ; computation = cleared }
330
-
331
374
let [@ inline] use = function R Nothing -> () | R (Req r ) -> r.unused < - false
332
375
333
- let handle _ =
334
- let (Req r) = Picos_thread.TLS. get intr_key in
335
- Computation. return r.computation Signaled
336
-
337
376
(* * This is used to ensure that the [intr_pending] counter is incremented
338
377
exactly once before the counter is decremented. *)
339
378
let rec incr_once (Req r as req : [ `Req ] tdt ) backoff =
@@ -366,14 +405,6 @@ module Intr = struct
366
405
let _ : bool = incr_once req Backoff. default in
367
406
()
368
407
369
- let () =
370
- if not Sys. win32 then begin
371
- let previously_blocked = Thread. sigmask SIG_BLOCK intr_sigs in
372
- assert (not (List. exists is_intr_sig previously_blocked));
373
- let old_behavior = Sys. signal intr_sig (Sys. Signal_handle handle) in
374
- assert (old_behavior == Signal_default )
375
- end
376
-
377
408
let nothing = R Nothing
378
409
379
410
let [@ alert " -handler" ] req ~seconds =
@@ -392,8 +423,10 @@ module Intr = struct
392
423
Picos_thread.TLS. set intr_key req;
393
424
let entry = Cancel_at { time; exn_bt = exit_exn_bt; computation } in
394
425
add_timeout state id entry;
395
- let _was_blocked : int list = Thread. sigmask SIG_UNBLOCK intr_sigs in
396
- (* assert (List.exists is_intr_sig was_blocked); *)
426
+ let was_blocked : int list =
427
+ Thread. sigmask SIG_UNBLOCK config.intr_sigs
428
+ in
429
+ assert (List. exists is_intr_sig was_blocked);
397
430
R req
398
431
end
399
432
@@ -408,8 +441,10 @@ module Intr = struct
408
441
let clr = function
409
442
| R Nothing -> ()
410
443
| R (Req r as req ) ->
411
- let _was_blocked : int list = Thread. sigmask SIG_BLOCK intr_sigs in
412
- (* assert (not (List.exists is_intr_sig was_blocked)); *)
444
+ let was_blocked : int list =
445
+ Thread. sigmask SIG_BLOCK config.intr_sigs
446
+ in
447
+ assert (not (List. exists is_intr_sig was_blocked));
413
448
if not (Computation. try_return r.computation Cleared ) then begin
414
449
let _ : bool = incr_once req Backoff. default in
415
450
(* We ensure that the associated increment has been done before we
0 commit comments