How to find where a process started in elixir - erlang

I am using observer in elixir and the following is the snapshot of an Application [under applications tab]:
I need to exit these processes once their work is done. Somehow, I am not able to figure out where some of the processes are originating. Is there a way in elixir/erlang to figure out the module/function where a particular process was created?
Suggestions will be highly appreciated. Thanks.

First you must always have the process's PID or its reference name.
Process.info/2
will give you information about that Process. You may get more documentation and information on how this function works in the Erlang's function it is calling:
process_info-2
There are also arity 1 variants: Process Docs

[erlang:process_info(Pid, initial_call) || Pid <- erlang:processes()].
But note that gen_server, etc., all have the same initial call, so you need to dig a little deeper.
The following is adapted from https://gist.github.com/rlipscombe/a8e87583d47799170f8b:
lists:map(
fun(Pid) ->
InitialCall = case erlang:process_info(Pid, initial_call) of
{initial_call,{proc_lib,init_p,A}} ->
case erlang:process_info(Pid, dictionary) of
{dictionary, D} ->
proplists:get_value('$initial_call', D, undefined);
_ ->
{proc_lib,init_p,A}
end;
{initial_call,{erlang,apply,A}} ->
case erlang:process_info(Pid, current_function) of
{current_function,MFA} -> MFA;
_ -> {erlang,apply,A}
end;
{initial_call,IC} ->
IC;
Other ->
Other
end,
{Pid, InitialCall}
end, erlang:processes()).

Using process_info/1 you can get a list of process information from which initial_call and current_function could help you to find the initial function call with which the process was spawned and the current function call of the process respectively.
Also process_info(Pid, initial_call) and process_info(Pid, current_function) functions are using as shortcut.

Related

How to check if a Pid is member of a list of Pids in Erlang?

I have a function that sets a value to a process Pid and I can have a process depend on another one. So if I set a value to a process then I have to also set the value to the processes that depend on it. However, if there is a circle between the processes
i.e. A depends on B and B depends on A
then I want to return an error message.
I try to do this by passing a list of Pids which have already changed values so that if I come across the same Pid twice (By checking if it is a member of the list of Pids) then the whole function stops. This is my code:
set_values(Pid, Value, PidSet, PidList) ->
case lists:member(Pid, PidList) of
false -> io:format("Setting Value~n"),
lists:map(fun(Pid) ->
Pid ! {self(), set_value, Value, [Pid | PidList]} end, PidSet);
true -> io:format("circle_detected~n"),
Pid ! {circle_detected}
end.
When I run it, I get this error:
=ERROR REPORT==== 2-Nov-2014::17:47:45 ===
Error in process <0.888.0> with exit value: {badarg,[{lists,member,
[<0.888.0>,empty_list],[]},{process,set_viewer_values,4,[{file,"process.erl"},{line,56}]},
{process,looper,2,[{file,"process.erl"},{line,116}]}]}
From what I understand I give bad arguments to lists:member function.
What should I do?
Thanks
If you read your error message, you have {lists,member,
[<0.888.0>,empty_list] ..., where lists is module, member is function name, and [<0.888.0>,empty_list] are aruguments (two) presented as list. So you are making call to lists:nenber/2 with PidList variable being atom empty_list. And this gives you an error.
So you need to look into how you funciton is being called (prefered), or create some pattern match on PidList like
set_values(Pid, Value, PidSet, _PidList = empty_list) ->
...

Is there any State variable in Mochiweb?

I have skimmed through the Mochiweb code, but have not found any sign of the State variable.
Does something similar to gen_server's State variable exist in Mochiweb?
I need to store some small amount of state-related server-side (not session-related) data on the server and I do not want to use ETS or Mnesia for that.
I think you have somewhat a misunderstanding of what gen_server state is.
First, let me explain briefly how mochiweb works.
Mochiweb doesn't produce a gen_server process per client. Instead, it just spawns a new process using proc_lib:spawn/3 and creates a parametrized module, which is, basically, a tuple of the following kind:
{mochiweb_request, #Port<0.623>, get, "/users", {1, 1}, []}
which is
{mochiweb_request, Socket, Method, RawPath, HTTPVersion, Headers}
This tuple is used as an argument to a function that you pass as a loop parameter to mochiweb_http:start/1. So, when this "loop" function is called, it will look like this:
handle_request(Req) ->
%% The pattern matching below just shows what Req really is
{mochiweb_request, _, _, _, _, _} = Req,
...
Now, to explanation of gen_server state.
Basically, gen_server is a process with approximately the following structure. Of course, IRL it's more complicated, but this should give you the general idea:
init(Options)
State = ...
loop(Module, State).
loop(Module, State)
NewState = receive
{call, Msg, From} -> Module:handle_call(Msg, From, State)
{cast, Msg} -> Module:handle_cast(Msg, State)
Info -> Module:handle_info(Info, State)
end,
loop(Module, NewState).
So, state is just an argument that you drag through all the function calls and change inside your loop. It doesn't actually matter if your process is a gen_server or not, it doesn't have what lifetime it has. In the following example the term [1, 2, 3] is a state too:
a() ->
b([1, 2, 3], now()).
b(State, Timestamp) ->
Result = do_something(Timestamp)
c(State, Result).
c(State, Payload) ->
exit({State, Payload}).
Now, back to mochiweb.
If you need to create a state of your own, you can just add an extra function argument:
handle_request(Req) ->
User = Req:get(path),
UserData = load_user_data(User),
handle_request(Req, UserData).
handle_request(Req, UserData) ->
...
Now UserData is a state too. You can loop this process, or let it respond and end right away – but you won't lose UserData as long as you pass it as an argument.
Finally, if you really want to make this process a gen_server (which is really unreasonable in most cases), you can use gen_server:enter_loop/3 function that will make your current process a gen_server. And The 3rd argument of this function will be your state that will be stored inside the started gen_server.

Understanding the return value of spawn

I'm getting started with Erlang, and could use a little help understanding the different results when applying the PID returned from spawn/3 to the process_info/1 method.
Given this simple code where the a/0 function is exported, which simply invokes b/0, which waits for a message:
-module(tester).
-export([a/0]).
a() ->
b().
b() ->
receive {Pid, test} ->
Pid ! alrighty_then
end.
...please help me understand the reason for the different output from the shell:
Example 1:
Here, current_function of Pid is shown as being tester:b/0:
Pid = spawn(tester, a, []).
process_info( Pid ).
> [{current_function,{tester,b,0}},
{initial_call,{tester,a,0}},
...
Example 2:
Here, current_function of process_info/1 is shown as being tester:a/0:
process_info( spawn(tester, a, []) ).
> [{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
Example 3:
Here, current_function of process_info/1 is shown as being tester:a/0, but the current_function of Pid is tester:b/0:
process_info( Pid = spawn(tester, a, []) ).
> [{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
process_info( Pid ).
> [{current_function,{tester,b,0}},
{initial_call,{tester,a,0}},
...
I assume there's some asynchronous code happening in the background when spawn/3 is invoked, but how does variable assignment and argument passing work (especially in the last example) such that Pid gets one value, and process_info/1 gets another?
Is there something special in Erlang that binds variable assignment in such cases, but no such binding is offered to argument passing?
EDIT:
If I use a function like this:
TestFunc = fun( P ) -> P ! {self(), test}, flush() end.
TestFunc( spawn(tester,a,[]) ).
...the message is returned properly from tester:b/0:
Shell got alrighty_then
ok
But if I use a function like this:
TestFunc2 = fun( P ) -> process_info( P ) end.
TestFunc2( spawn(tester,a,[]) ).
...the process_info/1 still shows tester:a/0:
[{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
Not sure what to make of all this. Perhaps I just need to accept it as being above my pay grade!
If you look at the docs for spawn it says it returns the newly created Pid and places the new process in the system scheduler queue. In other words, the process gets started but the caller keeps on executing.
Erlang is different from some other languages in that you don't have to explicitly yield control, but rather you rely on the process scheduler to determine when to execute which process. In the cases where you were making an assignment to Pid, the scheduler had ample time to switch over to the spawned process, which subsequently made the call to b/0.
It's really quite simple. The execution of the spawned process starts with a call to a() which at some point shortly afterwards will call b() and then just sits there and waits until it receives a specific message. In the examples where you manage to immediately call process_info on the pid, you catch it while the process is still executing a(). In the other cases, when some delay is involved, you catch it after it has called b(). What about this is confusing?

Unable to use Erlang/ets in receive block

I am trying to use Erlang/ets to store/update various informations by pattern matching received data. Here is the code
start() ->
S = ets:new(test,[]),
register(proc,spawn(fun() -> receive_data(S) end)).
receive_data(S) ->
receive
{see,A} -> ets:insert(S,{cycle,A}) ;
[[f,c],Fcd,Fca,_,_] -> ets:insert(S,{flag_c,Fcd,Fca});
[[b],Bd,Ba,_,_] -> ets:insert(S,{ball,Bd,Ba})
end,
receive_data(S).
Here A is cycle number, [f,c] is center flag , [b] is ball and Fcd,Fca, Bd, Ba are directions and angle of flag and ball from player.
Sender process is sending these informations. Here, pattern matching is working correctly which I checked by printing values of A, Fcd,Fca..etc. I believe there is something wrong with the use of Erlang/ets.
When I run this code I get error like this
Error in process <0.48.0> with exit value: {badarg,[{ets,insert,[16400,{cycle,7}]},{single,receive_data,1}]
Can anybody tell me what's wrong with this code and how to correct this problem?
The problem is that the owner of the ets-table is the process running the start/1 function and the default behavior for ets is to only allow the owner to write and other processes to read, aka protected. Two solutions:
Create the ets table as public
S = ets:new(test,[public]).
Set the owner to your newly created process
Pid = spawn(fun() -> receive_data(S) end,
ets:give_away(test, Pid, gift)
register(proc,Pid)
Documentation for give_away/3

How to find the supervisor of an OTP process?

Are there functions which would allow an OTP process to find the pid of its supervisor?
The data is hidden in the process dictionary (of any process spawned with proc_lib) under the entry '$ancestors':
1> proc_lib:spawn(fun() -> timer:sleep(infinity) end).
<0.33.0>
2> i(0,33,0).
[{current_function,{timer,sleep,1}},
{initial_call,{proc_lib,init_p,3}},
{status,waiting},
{message_queue_len,0},
{messages,[]},
{links,[]},
{dictionary,[{'$ancestors',[<0.31.0>]},
{'$initial_call',{erl_eval,'-expr/5-fun-1-',0}}]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.24.0>},
{total_heap_size,233},
{heap_size,233},
{stack_size,6},
{reductions,62},
{garbage_collection,[{min_bin_vheap_size,46368},
{min_heap_size,233},
{fullsweep_after,65535},
{minor_gcs,0}]},
{suspending,[]}]
Here the line that interests us is {dictionary,[{'$ancestors',[<0.31.0>]},.
Note that this is the kind of stuff you should rarely have any reason to use yourself. As far as I know, it's mostly used to handle clean termination in supervision trees rather than introspection for whatever code you have. Handle with care.
A cleaner way to do things without messing with OTP's sensible innards would be to have the supervisor pass its own pid as an argument to the process when starting it. This should be far less confusing for the people who'll read your code.
If you want to do it wrong, here's our solution:
%% #spec get_ancestors(proc()) -> [proc()]
%% #doc Find the supervisor for a process by introspection of proc_lib
%% $ancestors (WARNING: relies on an implementation detail of OTP).
get_ancestors(Pid) when is_pid(Pid) ->
case erlang:process_info(Pid, dictionary) of
{dictionary, D} ->
ancestors_from_dict(D);
_ ->
[]
end;
get_ancestors(undefined) ->
[];
get_ancestors(Name) when is_atom(Name) ->
get_ancestors(whereis(Name)).
ancestors_from_dict([]) ->
[];
ancestors_from_dict([{'$ancestors', Ancestors} | _Rest]) ->
Ancestors;
ancestors_from_dict([_Head | Rest]) ->
ancestors_from_dict(Rest).

Resources