this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Draw the rest of the GenServer

garrison 71f03a7b d22b6a5c

+81 -16
+4 -3
lib/trinity/scheduler.ex
··· 67 67 spawned_pid 68 68 end 69 69 70 - defmacro receive_yield(blocks) do 71 - do_block = Keyword.fetch!(blocks, :do) 70 + defmacro receive_yield(args) do 71 + do_block = Keyword.fetch!(args, :do) 72 72 73 73 {timeout, timeout_value} = 74 - case Keyword.get(blocks, :after) do 74 + case Keyword.get(args, :after) do 75 75 nil -> {:infinity, nil} 76 76 [{:->, _meta, [[timeout], timeout_value]}] -> {timeout, timeout_value} 77 77 end ··· 99 99 case receive_fun.() do 100 100 ^ref -> 101 101 # TODO: timeout 102 + yield(10) 102 103 receive_loop(receive_fun, ref, timeout) 103 104 value -> 104 105 value
+28 -6
lib/trinity/sim_gen.ex
··· 1 1 defmodule Trinity.SimGen do 2 - alias Trinity.Sim 2 + alias Trinity.{Scheduler, Sim} 3 3 4 4 import Trinity.Scheduler, only: [receive_yield: 1] 5 5 6 - def start(module, init_arg, _options) do 7 - case apply(module, :init, [init_arg]) do 6 + def start_link(module, init_arg, options) do 7 + do_start(module, init_arg, options, true) 8 + end 9 + 10 + def start(module, init_arg, options) do 11 + do_start(module, init_arg, options, false) 12 + end 13 + 14 + defp do_start(module, init_arg, _options, link?) do 15 + parent_pid = self() 16 + 17 + Scheduler.spawn_and_yield(fn -> 18 + initialize(module, init_arg, parent_pid) 19 + end, link?) 20 + 21 + receive_yield do 22 + {:ack, pid} -> {:ok, pid} 23 + # TODO: :error 24 + end 25 + end 26 + 27 + defp initialize(module, init_arg, parent_pid) do 28 + case module.init(init_arg) do 8 29 {:ok, state} -> 30 + Sim.send parent_pid, {:ack, self()} 9 31 loop(module, state) 10 32 end 11 33 end ··· 17 39 loop(module, state) 18 40 end 19 41 20 - defp dispatch({:"$sim_call", {from_pid, _alias} = from, request}, module, state) do 42 + defp dispatch({:"$sim_call", {from_pid, [:alias | _] = tag} = from, request}, module, state) do 21 43 try do 22 44 module.handle_call(request, from, state) 23 45 catch ··· 27 49 end 28 50 |> case do 29 51 {:reply, response, state} -> 30 - Sim.send(from_pid, response) 52 + Sim.send(from_pid, {tag, response}) 31 53 state 32 54 {:noreply, state} -> 33 55 state 34 56 end 35 57 end 36 58 37 - defp dispatch({"$:sim_cast", request}, module, state) do 59 + defp dispatch({:"$sim_cast", request}, module, state) do 38 60 try do 39 61 module.handle_cast(request, state) 40 62 catch
+23 -2
lib/trinity/sim_server.ex
··· 1 1 defmodule Trinity.SimServer do 2 - import Trinity.Scheduler, only: [simulation_key: 0] 2 + alias Trinity.{Sim, SimGen} 3 + 4 + import Trinity.Scheduler, only: [simulation_key: 0, receive_yield: 1] 3 5 4 6 defp get_sim, do: Process.get(simulation_key()) 5 7 8 + def start_link(module, arg, options \\ []) do 9 + SimGen.start_link(module, arg, options) 10 + end 11 + 6 12 @spec call(GenServer.server, term, timeout) :: term 7 13 def call(server, request, timeout \\ 5000) do 8 14 case get_sim() do 9 15 nil -> GenServer.call(server, request, timeout) 10 - _sim -> :noop 16 + _sim -> sim_call(server, request, timeout) 17 + end 18 + end 19 + 20 + @dialyzer {:no_improper_lists, sim_call: 3} 21 + defp sim_call(server, request, timeout) do 22 + # TODO: real alias 23 + tag = [:alias | make_ref()] 24 + 25 + Sim.send server, {:"$sim_call", {self(), tag}, request} 26 + 27 + receive_yield do 28 + {^tag, response} -> response 29 + after 30 + # TODO 31 + timeout -> raise "timeout" 11 32 end 12 33 end 13 34
+26 -5
test/trinity_test.exs
··· 3 3 4 4 alias Trinity.Scheduler 5 5 6 + defmodule Counter do 7 + use GenServer 8 + alias Trinity.SimServer 9 + 10 + def start_link(initial_count), do: SimServer.start_link(__MODULE__, initial_count) 11 + def add(server, amount), do: SimServer.call(server, {:add, amount}) 12 + 13 + def init(initial_count) do 14 + {:ok, initial_count} 15 + end 16 + 17 + def handle_call({:add, amount}, _from, count) do 18 + count = count + amount 19 + {:reply, count, count} 20 + end 21 + end 22 + 6 23 test "scheduler" do 7 24 Scheduler.run_simulation(fn -> 8 - Enum.each(1..100, fn i -> 9 - Scheduler.spawn_and_yield(fn -> 10 - dbg {self(), "proc #{i}"} 11 - Scheduler.yield(1_000_000) 12 - end, true) 25 + pids = 26 + Enum.map(1..10, fn i -> 27 + {:ok, pid} = Counter.start_link(i) 28 + pid 29 + end) 30 + dbg pids 31 + 32 + Enum.each(pids, fn pid -> 33 + dbg Counter.add(pid, 10) 13 34 end) 14 35 15 36 Scheduler.yield(1000)