@@ -71,15 +71,19 @@ type return_on =
71
71
}
72
72
-> return_on
73
73
74
- type phase = Continue | Select | Waking_up | Process
74
+ type phase =
75
+ | Processing
76
+ | Select
77
+ | Wakeup_during_processing
78
+ | Wakeup_during_select
75
79
76
80
type state = {
77
81
phase : phase Atomic .t ;
78
82
mutable state : [ `Initial | `Starting | `Alive | `Stopping | `Stopped ];
79
83
mutable exn_bt : exn * Printexc .raw_backtrace ;
80
84
mutable pipe_inn : Unix .file_descr ;
81
85
mutable pipe_out : Unix .file_descr ;
82
- byte : Bytes .t ;
86
+ bytes : Bytes .t ;
83
87
(* *)
84
88
timeouts : Q .t Atomic .t ;
85
89
mutable next_id : int ;
@@ -117,12 +121,12 @@ let intr_key : [ `Req ] tdt Picos_thread.TLS.t = Picos_thread.TLS.create ()
117
121
let key =
118
122
Picos_domain.DLS. new_key @@ fun () ->
119
123
{
120
- phase = Atomic. make Continue ;
124
+ phase = Atomic. make Processing ;
121
125
state = `Initial ;
122
126
exn_bt = exit_bt;
123
127
pipe_inn = Unix. stdin;
124
128
pipe_out = Unix. stdin;
125
- byte = Bytes. create 1 ;
129
+ bytes = Bytes. create ( if 32 < Sys. int_size then 64 - 8 else 64 - 4 ) ;
126
130
timeouts = Atomic. make Q. empty;
127
131
next_id = 0 ;
128
132
new_rd = ref [] ;
@@ -142,13 +146,26 @@ let[@poll error] [@inline never] transition s into =
142
146
s.state < - into;
143
147
from
144
148
149
+ let prepare_select s = Atomic. compare_and_set s.phase Processing Select
150
+
151
+ let rec start_processing s =
152
+ match Atomic. get s.phase with
153
+ | Processing -> ()
154
+ | Select ->
155
+ if not (Atomic. compare_and_set s.phase Select Processing ) then
156
+ start_processing s
157
+ | Wakeup_during_processing -> Atomic. set s.phase Processing
158
+ | Wakeup_during_select ->
159
+ (* We may read more than a single byte in case [fork] has been called and
160
+ the child process ended up calling [wakeup]. *)
161
+ let n = Unix. read s.pipe_inn s.bytes 0 (Bytes. length s.bytes) in
162
+ assert (1 < = n);
163
+ Atomic. set s.phase Processing
164
+
145
165
let rec wakeup s from =
146
166
match Atomic. get s.phase with
147
- | Process | Waking_up ->
148
- (* The thread will process the fds and timeouts before next select. *)
149
- ()
150
- | Continue ->
151
- if Atomic. compare_and_set s.phase Continue Process then
167
+ | Processing ->
168
+ if Atomic. compare_and_set s.phase Processing Wakeup_during_processing then
152
169
(* We managed to signal the wakeup before the thread was ready to call
153
170
select and the thread will notice this without us needing to write to
154
171
the pipe. *)
@@ -158,12 +175,17 @@ let rec wakeup s from =
158
175
need to retry. *)
159
176
wakeup s from
160
177
| Select ->
161
- if Atomic. compare_and_set s.phase Select Waking_up then
178
+ (* A single domain application may end up here after [fork] in the child
179
+ process. *)
180
+ if Atomic. compare_and_set s.phase Select Wakeup_during_select then
162
181
if s.state == from then
163
182
(* We are now responsible for writing to the pipe to force the thread
164
183
to exit the select. *)
165
- let n = Unix. write s.pipe_out s.byte 0 1 in
184
+ let n = Unix. write_substring s.pipe_out " " 0 1 in
166
185
assert (n = 1 )
186
+ | Wakeup_during_processing | Wakeup_during_select ->
187
+ (* The thread will process the fds and timeouts before next select. *)
188
+ ()
167
189
168
190
type fos = { n : int ; unique_fds : Unix .file_descr list ; ops : return_on list }
169
191
@@ -222,7 +244,7 @@ module Thread_atomic = Picos_io_thread_atomic
222
244
let rec select_thread s timeout rd wr ex =
223
245
if s.state == `Alive then begin
224
246
let rd_fds, wr_fds, ex_fds =
225
- if Atomic. compare_and_set s.phase Continue Select then begin
247
+ if prepare_select s then begin
226
248
try
227
249
Unix. select
228
250
(s.pipe_inn :: rd.unique_fds)
@@ -231,13 +253,7 @@ let rec select_thread s timeout rd wr ex =
231
253
end
232
254
else ([] , [] , [] )
233
255
in
234
- begin
235
- match Atomic. exchange s.phase Continue with
236
- | Select | Process | Continue -> ()
237
- | Waking_up ->
238
- let n = Unix. read s.pipe_inn s.byte 0 1 in
239
- assert (n = 1 )
240
- end ;
256
+ start_processing s;
241
257
let rd = process_fds rd_fds rd (Thread_atomic. exchange s.new_rd [] ) in
242
258
let wr = process_fds wr_fds wr (Thread_atomic. exchange s.new_wr [] ) in
243
259
let ex = process_fds ex_fds ex (Thread_atomic. exchange s.new_ex [] ) in
0 commit comments