Source file affect_unix__unix.ml
1
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
open Affect
open Affect__base
open Affect.Action.Private
module Signal = Affect_unix__signal
module Fd_unblocker =
Affect_unix__select
module Unblocker = struct
type t =
{ timeline : Affect_unix__timeline.t;
signal_unblocker : Signal.Unblocker.t;
fd_unblocker : Fd_unblocker.t; }
let make () =
let timeline = Affect_unix__timeline.make () in
let signal_unblocker = Signal.Unblocker.make () in
let fd_unblocker = Fd_unblocker.make () in
{ timeline; signal_unblocker; fd_unblocker }
let nonblock = Some 0L
let unblock u ~block =
let timer_did_unblock, timeout_ns =
Affect_unix__timeline.progress_to_next_deadline u.timeline
in
let signal_did_unblock = Signal.Unblocker.unblock u.signal_unblocker in
let did_unblock = timer_did_unblock || signal_did_unblock in
let timeout_ns =
if not block || did_unblock then nonblock else timeout_ns
in
let fd_did_unblock = Fd_unblocker.unblock u.fd_unblocker ~timeout_ns in
did_unblock || fd_did_unblock
let set_block_bypass u () = Fd_unblocker.set_block_bypass u.fd_unblocker
let domain_local u =
let unblock = unblock u in
let set_block_bypass = set_block_bypass u in
Action.Unblocker.Domain_local.make ~unblock ~set_block_bypass ()
let init u = Signal.Unblocker.register u.signal_unblocker
let deinit u =
Signal.Unblocker.unregister u.signal_unblocker;
Fd_unblocker.dispose u.fd_unblocker
let domain_install u =
Affect_unix__timeline.set_domain_local u.timeline;
Signal.Unblocker.set_domain_local u.signal_unblocker;
Fd_unblocker.set_domain_local u.fd_unblocker
let domain_uninstall _u =
Affect_unix__timeline.clear_domain_local ();
Signal.Unblocker.clear_domain_local ();
Fd_unblocker.clear_domain_local ()
end
let unblocker () =
let u = Unblocker.make () in
let local = Unblocker.domain_local u in
let init ~domain_count:_ = Unblocker.init u in
let domain_local _index = local in
let domain_install _local = Unblocker.domain_install u in
let domain_uninstall _local = Unblocker.domain_uninstall u in
let deinit () = Unblocker.deinit u in
Action.Unblocker.make
~init ~domain_local ~domain_install ~domain_uninstall ~deinit ()
let main
?(sigpipe = Signal.Ignore) ?domain_spawn ?domain_count ?schedule ?handler f
=
Signal.set_and_restore Sys.sigpipe sigpipe @@ fun () ->
let unblocker = unblocker () in
Fun.Async.main ~unblocker ?domain_spawn ?domain_count ?schedule ?handler f
include Unix
let wait_readable_meta = Action.Meta.make ~name:"Unix.wait_readable" ()
let wait_readable fd tag =
let poll = Action.Primitive.poll_is_none in
let block ~blocked =
let blocked = Action.Blocked.Value.make tag blocked in
let unblocker = Fd_unblocker.get_domain_local () in
Fd_unblocker.add_wait_readable unblocker fd ~blocked
in
Action.Primitive.make ~meta:wait_readable_meta ~poll ~block
let wait_writable_meta = Action.Meta.make ~name:"Unix.wait_writable" ()
let wait_writable fd tag =
let poll = Action.Primitive.poll_is_none in
let block ~blocked =
let blocked = Action.Blocked.Value.make tag blocked in
let unblocker = Fd_unblocker.get_domain_local () in
Fd_unblocker.add_wait_writable unblocker fd ~blocked
in
Action.Primitive.make ~meta:wait_writable_meta ~poll ~block
let close_noerr fd = try Unix.close fd with Unix.Unix_error _ -> ()
let socket ?(cloexec = true) dom typ proto =
let fd = Unix.socket ~cloexec dom typ proto in
Unix.set_nonblock fd; fd
let rec accept ?cloexec fd = try Unix.accept ?cloexec fd with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_readable fd ()); accept ?cloexec fd
let rec connect fd addr = try Unix.connect fd addr with
| Unix.Unix_error (EINPROGRESS, _, _) ->
Action.invoke (wait_writable fd ());
match Unix.getsockopt_error fd with
| Some error -> raise (Unix.Unix_error (error, "connect", ""))
| None -> ()
let rec read fd buf first length = try Unix.read fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_readable fd ()); read fd buf first length
let rec read_bigarray fd buf first length =
try Unix.read_bigarray fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_readable fd ()); read_bigarray fd buf first length
let rec write fd buf first length =
try Unix.write fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ()); write fd buf first length
let rec write_bigarray fd buf first length =
try Unix.write_bigarray fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ()); write_bigarray fd buf first length
let rec write_substring fd buf first length =
try Unix.write_substring fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ()); write_substring fd buf first length
let rec single_write fd buf first length =
try Unix.single_write fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ()); single_write fd buf first length
let rec single_write_bigarray fd buf first length =
try Unix.single_write_bigarray fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ());
single_write_bigarray fd buf first length
let rec single_write_substring fd buf first length =
try Unix.single_write_substring fd buf first length with
| Unix.Unix_error ((EWOULDBLOCK | EAGAIN), _, _) ->
Action.invoke (wait_writable fd ());
single_write_substring fd buf first length