<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jul 27, 2015 at 4:40 PM, Loïc Hoguin <span dir="ltr"><<a href="mailto:essen@ninenines.eu" target="_blank">essen@ninenines.eu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This and sending yourself a message is a bad idea. It will usually work, until it doesn't, and you will have a very hard time figuring out why.</blockquote></div><br>I'm quite curious. What is the scenario where this fails? I have never observed this in practice on very busy systems, and I think going through proc_lib for this is a detour I'd rather not we'd have to take.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Here are two modules, z0 and z.erl. They are very boring gen servers:</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">-module(z0).</div><div class="gmail_extra">-behaviour(gen_server).</div><div class="gmail_extra"><br></div><div class="gmail_extra">-ifdef(PULSE).</div><div class="gmail_extra">-include_lib("pulse_otp/include/pulse_otp.hrl").</div><div class="gmail_extra">-endif.</div><div class="gmail_extra"><br></div><div class="gmail_extra">-export([start_link/0]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% Operational API</div><div class="gmail_extra">-export([read/0, read_p/1]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% gen_server API</div><div class="gmail_extra">-export([</div><div class="gmail_extra">         init/1,</div><div class="gmail_extra">         handle_cast/2,</div><div class="gmail_extra">         handle_call/3,</div><div class="gmail_extra">         terminate/2,</div><div class="gmail_extra">         code_change/3,</div><div class="gmail_extra">         handle_info/2</div><div class="gmail_extra">]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% API</div><div class="gmail_extra">start_link() -></div><div class="gmail_extra">    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).</div><div class="gmail_extra"><br></div><div class="gmail_extra">read() -></div><div class="gmail_extra">    gen_server:call(?MODULE, read).</div><div class="gmail_extra"><br></div><div class="gmail_extra">read_p(P) -></div><div class="gmail_extra">    gen_server:call(P, read).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% Callbacks</div><div class="gmail_extra">init([]) -></div><div class="gmail_extra">    {ok, initializing, 0}.</div><div class="gmail_extra"><br></div><div class="gmail_extra">handle_call(read, _From, State) -></div><div class="gmail_extra">    {reply, State, State}.</div><div class="gmail_extra">    </div><div class="gmail_extra">handle_cast(_M, State) -></div><div class="gmail_extra">    {noreply, State}.</div><div class="gmail_extra"><br></div><div class="gmail_extra">handle_info(timeout, _State) -></div><div class="gmail_extra">    {noreply, ready}.</div><div class="gmail_extra">    </div><div class="gmail_extra">terminate(_How, _State) -></div><div class="gmail_extra">    ok.</div><div class="gmail_extra">    </div><div class="gmail_extra">code_change(_OldVsn, State, _Extra) -></div><div class="gmail_extra">    {ok, State}.</div><div class="gmail_extra"><br></div><div class="gmail_extra">---------------------</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">-module(z).</div><div class="gmail_extra">-behaviour(gen_server).</div><div class="gmail_extra"><br></div><div class="gmail_extra">-ifdef(PULSE).</div><div class="gmail_extra">-include_lib("pulse_otp/include/pulse_otp.hrl").</div><div class="gmail_extra">-endif.</div><div class="gmail_extra"><br></div><div class="gmail_extra">-export([start_link/0]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% Operational API</div><div class="gmail_extra">-export([read/0, read_p/1]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% gen_server API</div><div class="gmail_extra">-export([</div><div class="gmail_extra">         init/1,</div><div class="gmail_extra">         handle_cast/2,</div><div class="gmail_extra">         handle_call/3,</div><div class="gmail_extra">         terminate/2,</div><div class="gmail_extra">         code_change/3,</div><div class="gmail_extra">         handle_info/2</div><div class="gmail_extra">]).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% API</div><div class="gmail_extra">start_link() -></div><div class="gmail_extra">    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).</div><div class="gmail_extra"><br></div><div class="gmail_extra">read() -></div><div class="gmail_extra">    gen_server:call(?MODULE, read).</div><div class="gmail_extra"><br></div><div class="gmail_extra">read_p(P) -></div><div class="gmail_extra">    gen_server:call(P, read).</div><div class="gmail_extra"><br></div><div class="gmail_extra">%% Callbacks</div><div class="gmail_extra">init([]) -></div><div class="gmail_extra">    self() ! timeout,</div><div class="gmail_extra">    {ok, initializing}.</div><div class="gmail_extra"><br></div><div class="gmail_extra">handle_call(read, _From, State) -></div><div class="gmail_extra">    {reply, State, State}.</div><div class="gmail_extra">    </div><div class="gmail_extra">handle_cast(_M, State) -></div><div class="gmail_extra">    {noreply, State}.</div><div class="gmail_extra"><br></div><div class="gmail_extra">handle_info(timeout, _State) -></div><div class="gmail_extra">    {noreply, ready}.</div><div class="gmail_extra">    </div><div class="gmail_extra">terminate(_How, _State) -></div><div class="gmail_extra">    ok.</div><div class="gmail_extra">    </div><div class="gmail_extra">code_change(_OldVsn, State, _Extra) -></div><div class="gmail_extra">    {ok, State}.</div><div><br></div><div>---------------------</div><div><br></div><div>Ok, now with these down, we can use EQC and PULSE to generate the counterexample if any should be in there:</div><div><br></div><div><div>-module(z_eqc).</div><div>-include_lib("eqc/include/eqc.hrl").</div><div>-include_lib("eqc/include/eqc_statem.hrl").</div><div><br></div><div>-include_lib("pulse/include/pulse.hrl").</div><div>-include_lib("pulse_otp/include/pulse_otp.hrl").</div><div><br></div><div>-compile(export_all).</div><div><br></div><div>-record(state, { init, ref }).</div><div><br></div><div>initial_state() -></div><div>    #state { init = false }.</div><div>    </div><div>server_start() -></div><div>    {ok, Pid} = z:start_link(),</div><div>    unlink(Pid),</div><div>    Pid.</div><div>    </div><div>%% SERVER START_LINK</div><div>server_start_pre(S) -> not initialized(S).</div><div>server_start_args(_S) -> [].</div><div><br></div><div>server_start_next(S, Ref, []) -></div><div>    S#state { ref = Ref, init = true }.</div><div>    </div><div>server_start_post(_S, [], Ref) -> is_pid(Ref).</div><div><br></div><div>%% READ BY PID</div><div>read_p(P) -></div><div>    z:read_p(P).</div><div>    </div><div>read_p_pre(S) -> initialized(S).</div><div>read_p_args(#state { ref = Ref }) -> [Ref].</div><div><br></div><div>read_p_return(_S, [_Ref]) -> ready.</div><div><br></div><div>%% READ</div><div>read() -></div><div>    try z:read() of</div><div>      M -> M</div><div>    catch</div><div>      _Class:_Err -></div><div>        {error, undefined}</div><div>    end.</div><div>    </div><div>read_args(_S) -> [].</div><div>read_return(#state { init = false}, []) -> {error, undefined};</div><div>read_return(#state { init = true}, []) -> ready.</div><div><br></div><div>%% Run a test under PULSE to randomize the process schedule as well.</div><div>prop_model_pulse() -></div><div>   ?SETUP(fun() -></div><div>                   setup(),</div><div>                   fun() -> ok end</div><div>           end,</div><div>  ?LET(Shrinking, parameter(shrinking, false),</div><div>  ?FORALL(Cmds, parallel_commands(?MODULE),</div><div>    ?ALWAYS(if not Shrinking -> 1; Shrinking -> 20 end,</div><div>      ?PULSE(HSR={_, _, R},</div><div>        begin</div><div>          ok = cleanup(),</div><div>          run_parallel_commands(?MODULE, Cmds)</div><div>        end,</div><div>        aggregate(command_names(Cmds),</div><div>        pretty_commands(?MODULE, Cmds, HSR, R == ok))))))).</div><div><br></div><div>setup() -></div><div>    error_logger:tty(false),</div><div>    ok.</div><div><br></div><div>cleanup() -></div><div>    case whereis(z) of</div><div>        undefined -> ok;</div><div>        Pid -></div><div>            exit(Pid, kill),</div><div>            timer:sleep(3)</div><div>    end,</div><div>    ok.</div><div><br></div><div>initialized(#state { init = I }) -> I.</div><div><br></div><div>pulse_instrument() -></div><div>  [ pulse_instrument(File) || File <- filelib:wildcard("*.erl") ],</div><div>  ok.</div><div>  </div><div>pulse_instrument(File) -></div><div>    io:format("Compiling: ~p~n", [File]),</div><div>    {ok, Mod} = compile:file(File, [{d, 'PULSE', true}, {d, 'WITH_PULSE', true},</div><div>                                    {d, 'EQC_TESTING', true},</div><div>                                    {parse_transform, pulse_instrument}]),</div><div>  code:purge(Mod),</div><div>  code:load_file(Mod),</div><div>  Mod.</div></div><div><br></div><div>-----------------------------</div><div><br></div><div>However, when I run this, I get no errors, even though I'm trying to behave non-nicely:</div><div><br></div><div>I won't call the Pid until I know about it.</div><div>I will blindly call the name, z, and if I get an error on this, I'll verify that the possible linearization is that the process was not started yet. If I get a result, I force it to be ready:</div><div><br></div><div><div>60> eqc:module({testing_time, 30}, z_eqc).</div><div>prop_model_pulse: ....................................................................................................(x10)....................................................................................................(x100)............................(x10).......</div><div>Time limit reached: 30.0 seconds.</div><div><br></div><div>OK, passed 3970 tests</div><div><br></div><div>49.857% {z_eqc,read,0}</div><div>44.492% {z_eqc,read_p,1}</div><div>5.651% {z_eqc,server_start,0}</div><div>[]</div></div><div><br></div><div>...</div><div><br></div><div>So: What is the scenario where this approach fails?</div><div><br></div></div><br clear="all"><div><br></div>-- <br><div class="gmail_signature">J.</div>
</div></div>