@@ -64,32 +64,44 @@ module Suspended = struct
64
64
Effect.Deep. discontinue t.k ex
65
65
end
66
66
67
+ (* Resume the next runnable fiber, if any. *)
68
+ let rec wakeup run_q =
69
+ match Run_queue. pop run_q with
70
+ | Some f ->
71
+ f () ;
72
+ wakeup run_q
73
+ | None -> ()
74
+
67
75
(* The Javascript backend scheduler is implemented as an event listener.
68
76
We don't need to worry about multiple domains. Here any time something
69
77
asynchronously enqueues a task to our queue, it also sends a wakeup event to
70
78
the event listener which will run the callback calling the scheduler. *)
71
79
module Scheduler = struct
72
80
type t = {
73
- scheduler : El .t ;
74
81
run_q : (unit -> unit ) Run_queue .t ;
75
- mutable listener : Ev .listener ;
82
+ mutable idle_callback : Jv .t option ;
76
83
}
77
84
78
- let v ~schedule run_q =
79
- let open Brr_io in
80
- let scheduler = El. div [] in
81
- let listener =
82
- Brr.Ev. listen Message.Ev. message (fun _ev -> schedule run_q) (El. as_target scheduler)
83
- in
84
- { scheduler; run_q; listener }
85
+ let v run_q =
86
+ let idle_callback = None in
87
+ { run_q; idle_callback }
85
88
86
- let stop t = Brr.Ev. unlisten t.listener
89
+ external _request_idle_callback : Jv .t -> Jv .t = " requestIdleCallbackShim"
90
+ external _cancel_idle_callback : Jv .t -> unit = " cancelIdleCallbackShim"
91
+
92
+ let request_idle_callback cb =
93
+ _request_idle_callback (Jv. callback ~arity: 1 (fun _ -> cb () ))
87
94
88
- (* A new message must be created for every call. *)
89
95
let wakeup t =
90
- let open Brr_io in
91
- let args = [| Ev. create Message.Ev. message |> Ev. to_jv |] in
92
- Jv. call (El. to_jv t.scheduler) " dispatchEvent" args |> ignore
96
+ (* No need to schedule a wakeup if the idle_callback is already set. *)
97
+ if Option. is_some t.idle_callback then () else begin
98
+ let idle_callback = request_idle_callback (fun () -> t.idle_callback < - None ; wakeup t.run_q) in
99
+ t.idle_callback < - Some idle_callback
100
+ end
101
+
102
+ let stop t =
103
+ Option. iter _cancel_idle_callback t.idle_callback;
104
+ t.idle_callback < - None
93
105
94
106
let enqueue_thread t k v =
95
107
Run_queue. push t.run_q (fun () -> Suspended. continue k v);
@@ -98,19 +110,15 @@ module Scheduler = struct
98
110
let enqueue_failed_thread t k v =
99
111
Run_queue. push t.run_q (fun () -> Suspended. discontinue k v);
100
112
wakeup t
113
+
114
+ let enqueue_at_head t k v =
115
+ Run_queue. push_head t.run_q (fun () -> Suspended. continue k v);
116
+ wakeup t
101
117
end
102
118
103
119
type _ Effect.t + = Enter_unchecked : (Scheduler .t -> 'a Suspended .t -> unit ) -> 'a Effect .t
104
120
let enter_unchecked fn = Effect. perform (Enter_unchecked fn)
105
121
106
- (* Resume the next runnable fiber, if any. *)
107
- let rec schedule run_q : unit =
108
- match Run_queue. pop run_q with
109
- | Some f ->
110
- f () ;
111
- schedule run_q
112
- | None -> ()
113
-
114
122
module Timeout = struct
115
123
let sleep ~ms =
116
124
enter_unchecked @@ fun st k ->
@@ -147,10 +155,10 @@ let next_event : 'a Brr.Ev.type' -> Brr.Ev.target -> 'a Brr.Ev.t = fun typ targe
147
155
(* Largely based on the Eio_mock.Backend event loop. *)
148
156
let run main =
149
157
let run_q = Run_queue. create () in
150
- let scheduler = Scheduler. v ~schedule run_q in
158
+ let scheduler = Scheduler. v run_q in
151
159
let rec fork ~new_fiber :fiber fn =
152
160
Effect.Deep. match_with fn ()
153
- { retc = (fun () -> Fiber_context. destroy fiber; schedule run_q );
161
+ { retc = (fun () -> Fiber_context. destroy fiber);
154
162
exnc = (fun ex ->
155
163
let bt = Printexc. get_raw_backtrace () in
156
164
Fiber_context. destroy fiber;
@@ -159,18 +167,18 @@ let run main =
159
167
effc = fun (type a ) (e : a Effect.t ) : ((a , unit ) Effect.Deep. continuation -> unit ) option ->
160
168
match e with
161
169
| Eio.Private.Effects. Suspend f -> Some (fun k ->
170
+ let k = { Suspended. k; fiber } in
162
171
f fiber (function
163
- | Ok v -> Run_queue. push run_q (fun () -> Effect.Deep. continue k v)
164
- | Error ex -> Run_queue. push run_q (fun () -> Effect.Deep. discontinue k ex)
165
- );
166
- schedule run_q
172
+ | Ok v -> Scheduler. enqueue_thread scheduler k v
173
+ | Error ex -> Scheduler. enqueue_failed_thread scheduler k ex
174
+ )
167
175
)
168
176
| Enter_unchecked fn -> Some (fun k ->
169
- fn scheduler { Suspended. k; fiber };
170
- schedule run_q
177
+ fn scheduler { Suspended. k; fiber }
171
178
)
172
179
| Eio.Private.Effects. Fork (new_fiber , f ) -> Some (fun k ->
173
- Run_queue. push_head run_q (Effect.Deep. continue k);
180
+ let k = { Suspended. k; fiber } in
181
+ Scheduler. enqueue_at_head scheduler k () ;
174
182
fork ~new_fiber f
175
183
)
176
184
| Eio.Private.Effects. Get_context -> Some (fun k ->
0 commit comments