@@ -20,6 +20,7 @@ module Lf_queue = Eio_utils.Lf_queue
20
20
module Fiber_context = Eio.Private. Fiber_context
21
21
module Ctf = Eio.Private. Ctf
22
22
module Rcfd = Eio_unix.Private. Rcfd
23
+ module Poll = Iomux. Poll
23
24
24
25
type exit = [`Exit_scheduler ]
25
26
@@ -40,6 +41,7 @@ type t = {
40
41
run_q : runnable Lf_queue .t ;
41
42
42
43
poll : Poll .t ;
44
+ mutable poll_maxi : int ;
43
45
44
46
(* When adding to [run_q] from another domain, this domain may be sleeping and so won't see the event.
45
47
In that case, [need_wakeup = true] and you must signal using [eventfd]. *)
@@ -106,41 +108,44 @@ let clear_event_fd t =
106
108
let buf = Bytes. create 8 in
107
109
let got = Unix. read t.eventfd_r buf 0 (Bytes. length buf) in
108
110
assert (got > 0 );
109
- Poll. set t.poll t.eventfd_r Poll.Event. read
111
+ Poll. (set_index t.poll ( Iomux.Util. fd_of_unix t.eventfd_r) t.eventfd_r Flags. pollin)
110
112
111
- let ready t fd (event : Poll.Event.t ) =
113
+ let update t waiters fd =
114
+ let fdi = Iomux.Util. fd_of_unix fd in
115
+ let flags =
116
+ match not (Lwt_dllist. is_empty waiters.read),
117
+ not (Lwt_dllist. is_empty waiters.write) with
118
+ | false , false -> Poll.Flags. empty
119
+ | true , false -> Poll.Flags. pollin
120
+ | false , true -> Poll.Flags. pollout
121
+ | true , true -> Poll.Flags. (pollin + pollout)
122
+ in
123
+ if flags = Poll.Flags. empty then (
124
+ Poll. (invalidate_index t.poll fdi);
125
+ Hashtbl. remove t.fd_map fd
126
+ ) else (
127
+ Poll. (set_index t.poll fdi fd flags);
128
+ if fdi > t.poll_maxi then
129
+ t.poll_maxi < - fdi
130
+ )
131
+
132
+ let ready t _index fd revents =
133
+ (* Reason about this *)
112
134
if fd == t.eventfd_r then (
113
135
clear_event_fd t
114
136
(* The scheduler will now look at the run queue again and notice any new items. *)
115
137
) else (
116
138
let waiters = Hashtbl. find t.fd_map fd in
117
139
let pending = Lwt_dllist. create () in
118
- if event.readable then Lwt_dllist. transfer_l waiters.read pending;
119
- if event.writable then Lwt_dllist. transfer_l waiters.write pending;
120
- (* Everything is marked as ONESHOT, so if we want to use anything later we need to re-arm with EPOLL_CTL_MOD.
121
- Except that if the FD gets closed and reassigned then we'll need to use EPOLL_CTL_ADD instead.
122
- Since we don't know whether it will be closed or not, stop watching it immediately. *)
123
- let event2 : Poll.Event.t = {
124
- readable = not (Lwt_dllist. is_empty waiters.read);
125
- writable = not (Lwt_dllist. is_empty waiters.write);
126
- } in
127
- Poll. set t.poll fd event2;
128
- if event2 = Poll.Event. none then Hashtbl. remove t.fd_map fd;
129
- Lwt_dllist. iter_node_r (remove_and_resume t) pending
130
- )
140
+ if Poll.Flags. (mem revents (pollout + pollhup + pollerr)) then
141
+ Lwt_dllist. transfer_l waiters.write pending;
142
+ if Poll.Flags. (mem revents (pollin + pollhup + pollerr)) then
143
+ Lwt_dllist. transfer_l waiters.read pending;
144
+ (* If pending has things, it means we modified the waiters, refresh our view *)
145
+ if not (Lwt_dllist. is_empty pending) then
146
+ update t waiters fd;
147
+ Lwt_dllist. iter_node_r (remove_and_resume t) pending)
131
148
132
- (* todo: remove event when empty. Or when closed? But hard to know when that happens. *)
133
- let update t waiters fd =
134
- let event : Poll.Event.t = {
135
- readable = not (Lwt_dllist. is_empty waiters.read);
136
- writable = not (Lwt_dllist. is_empty waiters.write);
137
- } in
138
- try
139
- Poll. set t.poll fd event
140
- with Unix. Unix_error (Unix. EPERM, _ , "" ) ->
141
- (* [fd] doesn't support polling (e.g. it's a regular file). Assume it won't block
142
- and wake the caller immediately. *)
143
- ready t fd event
144
149
145
150
let add_read t fd k =
146
151
let waiters = get_waiters t fd in
@@ -183,13 +188,13 @@ let rec next t : [`Exit_scheduler] =
183
188
let time = Mtime. to_uint64_ns time in
184
189
let now = Mtime. to_uint64_ns now in
185
190
let diff_ns = Int64. sub time now in
186
- Poll.Timeout. after diff_ns
187
- | `Nothing -> Poll.Timeout. never
191
+ Poll. Nanoseconds diff_ns
192
+ | `Nothing -> Poll. Infinite
188
193
in
189
194
if not (Lf_queue. is_empty t.run_q) then (
190
195
Lf_queue. push t.run_q IO ; (* Re-inject IO job in the run queue *)
191
196
next t
192
- ) else if timeout = Never && t.active_ops = 0 then (
197
+ ) else if timeout = Infinite && t.active_ops = 0 then (
193
198
(* Nothing further can happen at this point. *)
194
199
Lf_queue. close t.run_q; (* Just to catch bugs if something tries to enqueue later *)
195
200
`Exit_scheduler
@@ -200,18 +205,14 @@ let rec next t : [`Exit_scheduler] =
200
205
If [need_wakeup] is still [true], this is fine because we don't promise to do that.
201
206
If [need_wakeup = false], a wake-up event will arrive and wake us up soon. *)
202
207
Ctf. (note_hiatus Wait_for_work );
203
- let r =
204
- match Poll. wait t.poll timeout with
205
- | `Ok | `Timeout as x -> x
206
- | exception Unix. Unix_error (Unix. EINTR, _ , "" ) -> `EINTR
208
+ let nready =
209
+ try Poll. ppoll t.poll (t.poll_maxi + 1 ) timeout []
210
+ with Unix. Unix_error (Unix. EINTR, _ , "" ) -> 0
207
211
in
208
212
Ctf. note_resume system_thread;
209
213
Atomic. set t.need_wakeup false ;
210
214
Lf_queue. push t.run_q IO ; (* Re-inject IO job in the run queue *)
211
- begin match r with
212
- | `EINTR | `Timeout -> ()
213
- | `Ok -> Poll. iter_ready t.poll ~f: (ready t); Poll. clear t.poll
214
- end ;
215
+ Poll. iter_ready t.poll nready (ready t);
215
216
next t
216
217
) else (
217
218
(* Someone added a new job while we were setting [need_wakeup] to [true].
@@ -236,10 +237,16 @@ let with_sched fn =
236
237
assert was_open
237
238
in
238
239
let poll = Poll. create () in
239
- let cleanup () = Poll. close poll; cleanup () in
240
+ for i = 0 to Poll. maxfds poll - 1 do
241
+ Poll. invalidate_index poll i
242
+ done ;
240
243
let fd_map = Hashtbl. create 10 in
241
- let t = { run_q; poll; fd_map; eventfd; eventfd_r; active_ops = 0 ; need_wakeup = Atomic. make false ; sleep_q } in
242
- Poll. set poll eventfd_r Poll.Event. read;
244
+ let t = { run_q; poll; poll_maxi = 0 ; fd_map; eventfd; eventfd_r;
245
+ active_ops = 0 ; need_wakeup = Atomic. make false ; sleep_q } in
246
+ let eventfd_ri = Iomux.Util. fd_of_unix eventfd_r in
247
+ Poll. (set_index t.poll eventfd_ri eventfd_r Flags. pollin);
248
+ if eventfd_ri > t.poll_maxi then
249
+ t.poll_maxi < - eventfd_ri;
243
250
match fn t with
244
251
| x -> cleanup () ; x
245
252
| exception ex ->
0 commit comments