···11defmodule Trinity.Scheduler do
22+ alias Trinity.SimProcess
23 alias Trinity.Scheduler.SimulationSupervisor
3445 defmodule Simulation do
···259260 end
260261 end
261262263263+ def handle_send_after(dest, message, time) do
264264+ %{queue: queue, now: now} = get_sim()
265265+ enqueue_event(queue, now, time, {:send_after, dest, message})
266266+ end
267267+262268 defp perform_next(queue, proc_queue_keys, now) do
263263- case pop_next(queue, proc_queue_keys) do
264264- {time, {_event, pid, ref}} ->
269269+ case pop_next(queue) do
270270+ {time, {:timeout, pid, ref}} ->
271271+ :ets.delete(proc_queue_keys, pid)
272272+ set_now(now, time)
273273+ send pid, ref
274274+ {time, {:resume, pid, ref}} ->
275275+ :ets.delete(proc_queue_keys, pid)
265276 set_now(now, time)
266277 send pid, ref
278278+ {time, {:send_after, dest, message}} ->
279279+ set_now(now, time)
280280+ SimProcess.perform_send(dest, message)
281281+ perform_next(queue, proc_queue_keys, now)
267282 end
268283 end
269284270270- defp pop_next(queue, proc_queue_keys) do
285285+ defp pop_next(queue) do
271286 case :ets.next_lookup(queue, {-1, 0}) do
272287 {_, [{{time, _i} = key, entry}]} ->
273288 :ets.delete(queue, key)
274274- {_event, pid, _ref} = entry
275275- :ets.delete(proc_queue_keys, pid)
276276-277289 {time, entry}
278290 _ ->
279291 raise "Queue empty!"
+20
lib/trinity/sim_process.ex
···1818 end
1919 end
20202121+ @spec send_after(pid | atom, term, non_neg_integer) :: term
2222+ def send_after(dest, message, time) do
2323+ case get_sim() do
2424+ nil -> Process.send_after(dest, message, time)
2525+ _sim -> sim_send_after(dest, message, time)
2626+ end
2727+ end
2828+2129 @spec node :: node
2230 def node do
2331 case get_sim() do
···9510396104 [] -> raise ArgumentError, "Invalid destination #{inspect(name_node)}"
97105 end
106106+ end
107107+108108+ # For use by Scheduler processing :send_after events
109109+ @doc false
110110+ def perform_send(dest, message) do
111111+ sim_send(dest, message)
112112+ end
113113+114114+ defp sim_send_after(dest, message, time) do
115115+ Scheduler.handle_send_after(dest, message, time)
116116+ # Real send_after returns a timer ref, but it's probably not worth the overhead
117117+ nil
98118 end
99119100120 defp sim_alias do
+5
test/trinity_test.exs
···8888 assert result == (id + 10)
8989 end)
90909191+ SimProcess.send_after self(), :finish, 1000
9292+ receive_yield do
9393+ :finish -> dbg "finished"
9494+ end
9595+9196 Scheduler.yield(1000)
9297 #dbg Scheduler.dump(), limit: :infinity
9398 end)