1
- open Lwt.Infix
2
-
3
1
let [@ inline never] not_main_thread () =
4
2
invalid_arg " not called from the main thread"
5
3
6
4
let ready = Picos_mpscq. create ()
7
5
8
- type pipes = {
9
- mutable count : int ;
10
- mutable inn : Lwt_unix .file_descr ;
11
- mutable out : Unix .file_descr ;
12
- mutable close_promise : int Lwt .t ;
13
- mutable close_resolver : int Lwt .u ;
14
- }
15
-
16
- let pipes =
17
- let close_promise, close_resolver = Lwt. wait () in
18
- {
19
- count = 0 ;
20
- inn = Lwt_unix. stdin;
21
- out = Unix. stdout;
22
- close_promise;
23
- close_resolver ;
24
- }
25
-
26
- let byte = Bytes. create 1
27
-
28
- let rec forever () =
29
- match Picos_mpscq. pop_exn ready with
30
- | resolver ->
31
- Lwt. wakeup resolver () ;
32
- forever ()
33
- | exception Picos_mpscq. Empty ->
34
- let inn = pipes.inn in
35
- if inn == Lwt_unix. stdin then Lwt. return_unit
36
- else
37
- Lwt. pick [ pipes.close_promise; Lwt_unix. read inn byte 0 1 ]
38
- >> = forever_check
39
-
40
- and forever_check n = if n < 0 then Lwt. return_unit else forever ()
6
+ type notification = { mutable ref_count : int ; mutable id : int }
7
+
8
+ let notification = { ref_count = 0 ; id = 0 }
9
+ let state = Atomic. make `Not_running
10
+
11
+ let notify_callback () =
12
+ Atomic. set state `Running ;
13
+ let rec loop () =
14
+ match Picos_mpscq. pop_exn ready with
15
+ | resolver ->
16
+ Lwt. wakeup resolver () ;
17
+ loop ()
18
+ | exception Picos_mpscq. Empty -> begin
19
+ match Atomic. get state with
20
+ | `Not_running | `Notified ->
21
+ Atomic. set state `Running ;
22
+ loop ()
23
+ | `Running ->
24
+ if not ( Atomic. compare_and_set state `Running `Not_running ) then
25
+ loop ()
26
+ end
27
+ in
28
+ loop ()
29
+
30
+ let rec notify () =
31
+ match Atomic. get state with
32
+ | `Notified -> ()
33
+ | ( `Running | `Not_running ) as before ->
34
+ if Atomic. compare_and_set state before `Notified then begin
35
+ if before == `Not_running then
36
+ Lwt_unix. send_notification notification.id
37
+ end
38
+ else notify ()
41
39
42
40
module System = struct
43
41
let sleep = Lwt_unix. sleep
@@ -50,45 +48,29 @@ module System = struct
50
48
if Picos_thread. is_main_thread () then Lwt. wakeup resolver ()
51
49
else begin
52
50
Picos_mpscq. push ready resolver;
53
- assert ( 1 = Unix. write pipes.out byte 0 1 )
51
+ notify ( )
54
52
end
55
53
56
54
let await (promise , _ ) = promise
57
55
end
58
56
59
57
let system = (module System : Picos_lwt.System )
60
58
61
- let pipes_incr () =
62
- let count = pipes.count + 1 in
63
- if count = 1 then begin
64
- let promise, resolver = Lwt. wait () in
65
- pipes.close_promise < - promise;
66
- pipes.close_resolver < - resolver;
67
- let inn, out = Lwt_unix. pipe_in ~cloexec: true () in
68
- pipes.inn < - inn;
69
- pipes.out < - out;
70
- pipes.count < - count;
71
- Lwt. async forever
72
- end
73
- else pipes.count < - count
74
-
75
- let pipes_decr _ =
76
- let count = pipes.count - 1 in
77
- if count = 0 then begin
78
- Lwt. wakeup pipes.close_resolver (- 1 );
79
- Unix. close pipes.out;
80
- pipes.out < - Unix. stdout;
81
- Lwt. async (fun () -> Lwt_unix. close pipes.inn);
82
- pipes.inn < - Lwt_unix. stdin;
83
- pipes.count < - count
84
- end
85
- else pipes.count < - count
59
+ let notification_decr _ =
60
+ let ref_count = notification.ref_count - 1 in
61
+ notification.ref_count < - ref_count;
62
+ if ref_count = 0 then Lwt_unix. stop_notification notification.id
86
63
87
64
let run ?forbid main =
88
65
if not (Picos_thread. is_main_thread () ) then not_main_thread () ;
89
- pipes_incr () ;
66
+ begin
67
+ let ref_count = notification.ref_count + 1 in
68
+ notification.ref_count < - ref_count;
69
+ if ref_count = 1 then
70
+ notification.id < - Lwt_unix. make_notification notify_callback
71
+ end ;
90
72
let promise = Picos_lwt. run ?forbid system main in
91
- Lwt. on_any promise pipes_decr pipes_decr ;
73
+ Lwt. on_any promise notification_decr notification_decr ;
92
74
promise
93
75
94
76
let () = Lwt_main. run (Lwt_unix. sleep 0.0 )
0 commit comments